WebGL图形编程实战【2】:动态着色 × 纹理贴图技术揭秘

上一篇文章:WebGL初体验【1】:绘制图形与变换技巧
仓库地址:github…gitee…

传递非坐标数据到顶点着色器

在前面的例子中,我们传递了顶点坐标到顶点着色器,然后由顶点着色器计算出顶点在屏幕上的位置。然后例子当中也有一个大小的值。下面用来实现传递大小值给点

修改顶点着色器代码

let vertexString = `
  attribute vec4 a_position;
  attribute float size1;
  uniform float size2;
  void main(){
    gl_Position = a_position;
    gl_PointSize = size1;
  }`;

这里可以用 attribute 和 uniform 定义大小的值,然后传递给顶点着色器,那么对应他的 js 赋值的代码如下:

利用 attribute 传递变量需要以下五个步骤、

创建缓冲区对象
绑定Buffer
将数据写入到缓冲区对象
将缓冲区对象分配给attribute变量
开启attribute变量

如果你用的 web storm 或者 idea 来写 md,发现 mermaid 预览不了,可以在插件 plugin 里面搜索 mermaid 进行安装

如果是 vscode,可以安装插件:Markdown Preview Mermaid Support

而同时使用 uniform 传递变量就可以直接获取进行赋值效果是一样的,都可以把值传递进去(但是这里 uniform
传值设置的是随机数,但是设置的所有顶点的值都是同一个)

// attribute
const sizeArray = new Float32Array([60, 100, 80, 30]);
let sizeBuffer = webGL.createBuffer();
webGL.bindBuffer(webGL.ARRAY_BUFFER, sizeBuffer);
webGL.bufferData(webGL.ARRAY_BUFFER, sizeArray, webGL.STATIC_DRAW);
let aSize = webGL.getAttribLocation(program, "size");
// 参数说明:attribute变量,传递值个数、数据类型,是否要归一化,跨度,偏移量
webGL.vertexAttribPointer(aSize, 1, webGL.FLOAT, false, 4, 0);
webGL.enableVertexAttribArray(aSize);

// uniform
let uSize = webGL.getUniformLocation(program, "size2");
webGL.uniform1f(uSize, Math.random() * 100);

拓展 attribute 和 uniform 的使用

特性attributeuniform
作用范围逐顶点(每个顶点不同)全局(所有顶点共享)
数据来源顶点缓冲区(如顶点坐标数组)直接通过 JavaScript 设置
更新频率每个顶点处理时更新一次绘制调用中保持不变
典型用途顶点位置、颜色、纹理坐标变换矩阵、全局参数
WebGL设置方法 gl.vertexAttribPointergl.uniform* 系列函数

如何选择?

  • 用 attribute:当数据需要为每个顶点单独指定时(例如顶点坐标、颜色)
  • 用 uniform:当数据对所有顶点一致时(例如变换矩阵、全局光照参数)

修改颜色

现在已经知道了将其他非坐标数据传递给顶点着色器了,同样的方法可以将颜色数据传递过去,但是处理颜色是在片元着色器当中,接下来看怎么将数据从顶点着色器传到片元着色器

先搞点传递给顶点着色器(在顶点着色器里面定义一个 attribute 的 a_color 值)

const colorArray = new Float32Array([
  1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
]);
let aColor = webGL.getAttribLocation(program, "a_color");
let colorBuffer = webGL.createBuffer();
webGL.bindBuffer(webGL.ARRAY_BUFFER, colorBuffer);
webGL.bufferData(webGL.ARRAY_BUFFER, colorArray, webGL.STATIC_DRAW);
webGL.vertexAttribPointer(aColor, 4, webGL.FLOAT, false, 4 * 4, 0);
webGL.enableVertexAttribArray(aColor);

将顶点着色器的值共享给片元着色器只需要有一个 varying 修饰的相同变量即可,这个时候的顶点和片元的代码如下:表示将 js 当中赋值的
a_color 给到 v_color,
同时由于 v_color 是 varying 修饰的所以可以共享 v_color 给片元着色器

// 顶点着色器
const vertexString = `
  attribute vec4 a_position;
  uniform mat4 proj;
  attribute float size;
  attribute vec4 a_color;
  varying vec4 v_color;
  void main(){
    gl_Position = proj * a_position;
    gl_PointSize = size;
    v_color = a_color;
  }`;

// 片元着色器
const fragmentString = `
  varying vec4 v_color;
  void main(){
    gl_FragColor = v_color;
  }`;

注:报错:ERROR: 0:2: ‘’ : No precision specified for (float)

原因是:片元着色器中未声明浮点型(float)变量的默认精度。GLSL ES 规范要求片元着色器必须显式定义浮点类型的精度,否则编译器会报错

解决:在片元着色器中声明精度,如:precision mediump float;

在这里插入图片描述

拓展 precision mediump float

precision:用于声明着色器中浮点数或整数的计算精度

为什么片元着色器必须声明?‌

  • 顶点着色器默认支持 highp。顶点着色器中的 float 默认是 highp,无需显式声明
  • 片元着色器无默认精度 ‌。片元着色器中的 float 精度必须手动指定,否则编译器报错(No precision specified)

精度对性能和效果的影响

精度等级性能适用场景典型问题
float一般计算(如颜色、阴影、纹理采样)移动设备可能不支持或性能差
highp需要高精度的计算(如复杂光照、抗锯齿)移动设备可能不支持或性能差
mediump大多数颜色计算(纹理采样、颜色混合)极小数(如 < 0.0001)可能被截断
lowp简单颜色计算(如纯色、低精度渐变)颜色过渡可能出现断层

varying 变量的作用和内插过程

顶点的颜色赋值给了顶点着色器中的 varying 变量 v_color,它的值被传给片元着色器中的同名、同类型变量(即片元着色器中的 varying
变量 v_color),
但是,更准确地说,顶点着色器中的 v_Co1or 变量在传人片元着色器之前经过了内插过程。所以,片元着色器中的 v_color 变量和顶点着色器中的
v_color 变量实际上并不是一回事,这也正是我们将这种变量称为“varying”(变化的)变量的原因

渐变三角形

在顶点着色器和片元着色器之间还有两个步骤

  • 图形装配过程:将孤立的顶点坐标装配成几何图形。几何图形 的类别由 gl.drawArrays()函数的第一个参数决定
  • 光栅化:装配好的几何图形转化为片元

在光栅化过程生成的片元都是带有坐标信息的,调用片元着色器时这些坐标信息也随着片元传了进去,我们可以通过片元着色器中的内置变量来访问片元的坐标

在前面已经有一个创建三角形的案例,然后也知道怎么把颜色赋值进去了,修改片元着色器

vec4 gl_FragCoord 该内置变量的第 1 个和第 2 个分量表示片元在坐标系统(窗口坐标系统)中的坐标值

const fragmentString = `
  precision mediump float;
  uniform float u_width;
  uniform float u_height;
  void main(){
    gl_FragColor = vec4(gl_FragCoord.x / u_width, 0.0, gl_FragCoord.y / u_height, 1.0);
  }`;

然后在 js 当中给片元着色器传递一个 u_width 和 u_height 的值,然后就可以得到一个渐变的三角形了(传递的值就是 canvas 的宽高)

let uniformWidth = webGL.getUniformLocation(program, "u_width");
webGL.uniform1f(uniformWidth, 1024.0);

let uniformHeight = webGL.getUniformLocation(program, "u_height");
webGL.uniform1f(uniformHeight, 768.0);

补充:片元着色器的内置变量

变量名类型/结构读写权限含义与用途注意事项
gl_FragCoordvec4只读片元在屏幕空间的位置(x,y 原点在视口左下角,z 深度值,w 透视校正的倒数)与 Canvas 坐标系不同,常用于屏幕空间特效
gl_FrontFacingbool只读判断片元是否属于图元正面(true 为正面,false 为背面)用于双面材质(如正反面不同颜色)
gl_FragColorvec4只写片元的最终颜色(RGBA)WebGL 2.0 已废弃,改用 out 变量(如 out vec4 color;)
gl_FragDatavec4[]只写多渲染目标(MRT)时,输出到不同颜色附件的颜色数组WebGL 1.0 支持有限,WebGL 2.0 需通过 layout(location=N) 指定自定义输出变量
gl_PointCoordvec2只读绘制 GL_POINTS 时,片元在点精灵内的纹理坐标(范围 [0.0, 1.0])原点在点精灵左下角,用于粒子效果或纹理贴图的点
gl_DepthRangestruct只读深度缓冲区参数(包含 near, far, diff 三个字段)通常由 GPU 自动处理,手动计算深度时参考
gl_LastFragDatavec4[](扩展)只读保留前一次渲染的片元颜色数据(需启用扩展)用于高级混合或延迟渲染技术,仅限 WebGL 2.0 扩展

纹理贴图

纹理映射

  • 说明:将一张图像(就像一张贴纸)映射(贴)到一个几何图形的表面上去。将一张真实世界的图片贴到一个由两个三角形组成的矩形上,这样矩形表面看上去就是这张图片。此时,这张图片又可以称为纹理图像(texture
    image)或纹理(texture)
  • 作用:就是根据纹理图像,为之前光栅化后的每个片元涂上合适的颜色。组成纹理图像的像素又被称为纹素(texels,texture elements)
    ,每一个纹素的颜色都使用 RGB 或 RGBA 格式编码

在 webGL 当中,要进行纹理映射有以下四个步骤:

  • 准备好映射到几何图形上的纹理图像
  • 为几何图形配置映射方式
  • 加载纹理图形,对其进行配置,以便使用
  • 在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素的颜色赋给片元

点精灵贴图

在前面例子的基础上进行调整,先添加纹理到片元着色器中,

let fragmentString = `
  precision mediump float;
  uniform sampler2D texture;
  void main(){
    vec4 color = texture2D(texture, gl_PointCoord);
    if(color.a < 0.1){
        discard;
    }
    gl_FragColor = color;
  }`;

在通用方法 initBuffer 当中添加,其中 uTexture 作为全局变量需要提前定义。

  • enable(webGL.BLEND):激活片元的颜色融合计算
  • blendFunc()
    定义了一个用于混合像素算法的函数 参数说明如下:参数可选见 API
    • @param 为源混合因子指定一个乘数。默认值是 gl.ONE
    • @param 为源目标合因子指定一个乘数。默认值是 gl.ZERO
    • SRC_ALPHA:将所有颜色乘以源 alpha 值
    • ONE_MINUS_SRC_ALPHA:将所有颜色乘以 1 减去源 alpha 值
uTexture = webGL.getUniformLocation(program, "texture");
webGL.enable(webGL.BLEND);
webGL.blendFunc(webGL.SRC_ALPHA, webGL.ONE_MINUS_SRC_ALPHA);
initTexture();

引入图片作为纹理贴图

  • createTexture 创建纹理对象
  • 然后加载一张本地 png 图片作为纹理贴图
  • 在加载完成后会触发 onload 方法,这个时候调用一个自定义的方法进行纹理配置
function initTexture() {
  let textureHandle = webGL.createTexture();
  textureHandle.image = new Image();
  textureHandle.image.src = "../assets/image/point64.png";
  textureHandle.image.onload = () => {
    handleLoadedTexture(textureHandle);
  };
}

进行纹理贴图配置

  • bindTexture(target, texture) 将纹理对象绑定到目标上

    • @param target
      • TEXTURE_2D 二维纹理
      • TEXTURE_CUBE_MAP 立方体映射纹理
      • TEXTURE_3D 三维纹理
      • TEXTURE_2D_ARRAY 二维数组纹理
  • texImage2D()
    方法指定了二维纹理图像 API 详细说明…

    • @param target TEXTURE_2D 二维纹理
    • @param level 指定详细级别。0 级是基本图像等级,n 级是第 n 个金字塔简化级
    • @param 指定纹理中的颜色
    • @param 和第三个参数保持一致
    • @param type UNSIGNED_BYTE,RGBA 每个通道 8 位
    • @param pixels 纹理的像素源(image)
  • texParameteri(target, pname, param)
    设置纹理参数 API 详细说明…

    • @param target 同上 bindTexture 的 target
function handleLoadedTexture(texture) {
  webGL.bindTexture(webGL.TEXTURE_2D, texture);
  webGL.texImage2D(
    webGL.TEXTURE_2D,
    0,
    webGL.RGBA,
    webGL.RGBA,
    webGL.UNSIGNED_BYTE,
    texture.image
  );
  webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_MAG_FILTER, webGL.LINEAR);
  webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_MIN_FILTER, webGL.LINEAR);
  webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_WRAP_S, webGL.REPEAT);
  webGL.texParameteri(webGL.TEXTURE_2D, webGL.TEXTURE_WRAP_T, webGL.REPEAT);
  webGL.uniform1i(uTexture, 0);
}

到这里就将图片作为纹理贴图渲染到目标上。

其中 texParameteri 方法第二个参数为要设置的纹理参数

名称描述
TEXTURE_MAG_FILTER纹理放大滤波器
TEXTURE_MIN_FILTER纹理缩小滤波器
TEXTURE_WRAP_S纹理坐标水平填充
TEXTURE_WRAP_T纹理坐标垂直填充

第三个参数为展示的算法(先看 TEXTURE_MAG_FILTER 和 TEXTURE_MIN_FILTER 的取值)

模式描述特点适用场景
NEAREST最近邻过滤性能高,锯齿明显性能优先,画质要求低
LINEAR线性过滤平滑,计算开销略高需要平滑效果
NEAREST_MIPMAP_NEAREST最近邻 mipmap 过滤性能高,锯齿或模糊性能优先,mipmap 支持
LINEAR_MIPMAP_NEAREST线性 mipmap 过滤平滑,性能适中平衡性能和画质
NEAREST_MIPMAP_LINEAR双线性 mipmap 过滤更平滑,性能较好平衡性能和画质
LINEAR_MIPMAP_LINEAR三线性过滤最佳平滑效果,计算开销最高对画质要求高的场景

而后是 TEXTURE_WRAP_S 和 TEXTURE_WRAP_T 的取值

模式描述特点适用场景
REPEAT纹理以平铺的方式重复无缝拼接,适合重复图案如砖墙、草地等需要重复的场景
CLAMP_TO_EDGE超出范围的坐标被截断到最近的边界值边缘拉伸,无重复或镜像效果单张图片或背景
MIRRORED_REPEAT纹理以镜像的方式重复每次重复都会翻转方向,减少割裂感自然平铺效果,如地板、水面等

使用 LINEAR 和 NEAREST 的区别【锯齿效果对比】
在这里插入图片描述

纹理坐标

纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色。WebGL系统中的纹理坐标系统是二维的,WebGL使用s和t命名纹理坐标(st坐标系统)

纹理图像四个角的坐标为左下、右下、右上、和左上。纹理坐标很通用,因为坐标值与图像自身的尺寸无关,
不管是128×128还是128×256的图像,其右上角的纹理坐标始终是(1.0,1.0)。

单纹理贴图

上一步说明了怎么给点添加纹理,这一步就是给平面来添加纹理贴图。首先来个案例,绘制一个正方形,这个正方形就是到时候要贴图的块,拿两个三角形给他拼接成一个正方形,他的坐标就是这样:这里不管你是用的
webGL 原本-1 到 1 的坐标系,还是转换成 canvas 的坐标系,后续只要修改 triangleSize 变量即可

const triangleSize = 500;

// let triangleArray = [
//   0, 0, 0, 1.0, 0, 0,
//   0, triangleSize, 0, 1.0, 0, 1,
//   triangleSize, 0, 0, 1.0, 1, 0,
//   triangleSize, 0, 0, 1.0, 1, 0,
//   0, triangleSize, 0, 1.0, 0, 1,
//   triangleSize, triangleSize, 0, 1.0, 1, 1
// ];

其他的代码我就不一一贴在这了,可以参考上一篇文章绘制三角形的代码 WebGL 初体验:绘制图形与变换技巧

之后就是添加纹理了,修改顶点着色器和片元着色器的代码,也就是下面这个,好,现在心想那他不就是和上一步的点精灵纹理一样嘛?那我就按照这样的步骤去实现,最后会发现纹理贴图并不会贴上来,取而代之的反而是一片纯色,因为纹理贴图没有被正确绘制,所以就出现了问题。

// 顶点着色器
let vertexString = `
  attribute vec4 a_position;
  uniform mat4 proj;
  void main(){
    gl_Position = proj * a_position;
}`;

// 片元着色器
let fragmentString = `
  precision mediump float;
  uniform sampler2D texture;
  void main(){
    vec4 color = texture2D(texture, gl_PointCoord);
    gl_FragColor = color;
  }`;

那这个着色的代码就不对,需要修改一下,要指定纹理的坐标,纹理坐标是会变化的,所以还是先通过 attribute 传递给顶点着色器,在通过
varying 传给片元着色器,并且在片元着色器当中 texture2D 的第二个参数设置为传递来的纹理坐标

// 顶点着色器
let vertexString = `
  attribute vec4 a_position;
  attribute vec2 a_texture_coord;
  varying vec2 v_texture_coord;
  uniform mat4 proj;
  void main(){
    gl_Position = proj * a_position;
    v_texture_coord = a_texture_coord;
  }`;

// 片元着色器
let fragmentString = `
  precision mediump float;
  uniform sampler2D texture;
  varying vec2 v_texture_coord;
  void main(){
    vec4 color = texture2D(texture, v_texture_coord);
    gl_FragColor = color;
  }`;

调整坐标,每一行都是一个点的位置,其中六个坐标分别代表 x,y,z,纹理坐标 u,v,其中 u 和 v 的范围是 0~1,所以需要把 x,y,z
坐标除以纹理大小,得到纹理坐标

// 格式化的时候总把这个数组弄乱,我注释了先
// let triangleArray = [
//   0, 0, 0, 1.0, 0, 0,
//   0, triangleSize, 0, 1.0, 0, 1,
//   triangleSize, 0, 0, 1.0, 1, 0,
//   triangleSize, 0, 0, 1.0, 1, 0,
//   0, triangleSize, 0, 1.0, 0, 1,
//   triangleSize, triangleSize, 0, 1.0, 1, 1
// ];

然后就是参数传递,这里的参数传递不同的就是每个参数都要跳过 4 个,因为这里的顶点着色器传递的顶点坐标是 vec4,所以要跳过 4 个

let aTexCoord = webGL.getAttribLocation(program, "a_texture_coord");
webGL.enableVertexAttribArray(aTexCoord);
webGL.vertexAttribPointer(aTexCoord, 2, webGL.FLOAT, false, 6 * 4, 4 * 4);

最后加载图片绘制纹理就是相同的代码了,这里看一下效果
在这里插入图片描述

图片反转

现在是将 webGL 的坐标转换成了 canvas 的坐标系,但是如果用的是 webGL 的坐标系进行添加纹理贴图的时候就会发现图片是反的,这个时候就需要对图片进行反转,如下

  • pixelStorei(pname, parmas)是用于图像预处理的函数
webGL.pixelStorei(webGL.UNPACK_FLIP_Y_WEBGL, true);
参数名 (pname)描述可选值 (param)
PACK_ALIGNMENT指定打包(读取)像素数据时的字节对齐方式。1, 2, 4, 8
UNPACK_ALIGNMENT指定解包(写入)像素数据时的字节对齐方式。1, 2, 4, 8
UNPACK_FLIP_Y_WEBGL指定在解包图像数据时是否沿 Y 轴翻转图像。truefalse
UNPACK_PREMULTIPLY_ALPHA_WEBGL指定在解包图像数据时是否将颜色值与 Alpha 值预乘。truefalse
UNPACK_COLORSPACE_CONVERSION_WEBGL指定在解包图像数据时是否进行颜色空间转换(如从 sRGB 到线性 RGB)。gl.BROWSER_DEFAULT_WEBGLgl.NONE
让纹理动起来

在了解了纹理贴图之后,思考一下,如果让纹理动起来,比如让纹理滚动或者旋转,那应该如何实现呢?那就是改变纹理的坐标就可以实现纹理的运动效果。实现起来很简单的,修改片元着色器

let fragmentString = `
  precision mediump float;
  uniform sampler2D texture;
  varying vec2 v_texture_coord;
  uniform float u_translateX;
  void main(){
    vec4 color = texture2D(texture, vec2(v_texture_coord.x + u_translateX,v_texture_coord.y));
    gl_FragColor = color;
  }`;

// 缩放对应的变量和取值
`uniform float u_scale;
vec4 color = texture2D(texture, vec2(v_texture_coord.x * u_scale, v_texture_coord.y * u_scale));`;

在片元着色器里面,加了一个 uniform 变量 u_translateX,然后通过 uniform 传递给片元着色器,在 texture2D
中创建贴图的时候去修改其二维坐标的一个位置,最后在 js 当中修改传递进来的值。
当然其他的旋转、缩放效果也是一样的。去修改片元着色器的纹理坐标,然后通过 uniform 传递

let count = 0;
let scale = 1;
let maxScale = 4;

function textureAnimate() {
  count += 0.005;
  if (scale < maxScale) {
    scale += 0.005;
  }
  if (scale >= maxScale) {
    scale = 1;
  }
  let uTranslateX = webGL.getUniformLocation(program, "u_translateX");
  webGL.uniform1f(uTranslateX, count);

  let uScale = webGL.getUniformLocation(program, "u_scale");
  webGL.uniform1f(uScale, scale);
  draw();
  requestAnimationFrame(textureAnimate);
}

在这里插入图片描述

多重纹理

既然单层纹理已经搞定了,那么多层纹理是不是往里面再加一个纹理,再通过 js 赋值就完事了呢?照着这个思路来改代码,先调整片元着色器,往里面再加一个
texture

let fragmentString = `
  precision mediump float;
  uniform sampler2D texture1;
  uniform sampler2D texture2;
  varying vec2 v_texture_coord;
  void main(){
    vec4 color1 = texture2D(texture1, v_texture_coord);
    vec4 color2 = texture2D(texture2, v_texture_coord);
    gl_FragColor = color1+color2;
  }`;

找到加载图片作为纹理的入口,把 texture1 和 texture2 赋值给 uTexture1 和 uTexture2,这几个变量都定义了全局变量,我这省去了

uTexture1 = webGL.getUniformLocation(program, 'texture1');
uTexture2 = webGL.getUniformLocation(program, 'texture2');

texture1 = initTexture('../assets/image/send.png');
texture2 = initTexture('../assets/image/man.png');

最后调用draw方法,这里的draw方法也要进行调整。

  • 通过activeTexture激活纹理单元,
  • 然后绑定纹理对象,
  • 最后再把纹理单元传递给片元着色器。
  • uniform1i传递的第二个参数(0和1)分别表示纹理单元的索引
function draw() {
  webGL.clearColor(0, 0, 1, 1);
  webGL.clear(webGL.COLOR_BUFFER_BIT);
  webGL.enable(webGL.DEPTH_TEST);

  webGL.activeTexture(webGL.TEXTURE0);
  webGL.bindTexture(webGL.TEXTURE_2D, texture1);
  webGL.uniform1i(uTexture1, 0);

  webGL.activeTexture(webGL.TEXTURE1);
  webGL.bindTexture(webGL.TEXTURE_2D, texture2);
  webGL.uniform1i(uTexture2, 1);

  webGL.drawArrays(webGL.TRIANGLES, 0, triangleArray.length / 6);

  requestAnimationFrame(draw);
}

注意:在调用draw方法的时候要先让两个纹理都加载完了之后再调用。
在这里插入图片描述

课程介绍你是否在寻找机会进入自动化测试领域? 你是否渴望学习selenium webdriver + Java以及最新的框架和技术进行web自动化测试? 你是否感兴趣学习Selenium如何用在你现有的项目里的? 这门课带你从Selenium搭建环境开始讲起,然后学习selenium,TestNG, logback, maven, jenkins。 我们假设学员没有任何自动化经验,来设计的这套课程。每个课题都从最基础的开始讲起。Selenium相关的该覆盖的课题都覆盖了。 例子都是来自于真实的web应用项目,帮助你理解不同的组件怎么用上自动化,这将展示给你一个行业层面的框架,增加自信心。 全网没有其他课程像这门课涵盖到如此之深的细节。 您将会学到什么 学完课程以后,你将拥有完整的Selenium Webdriver知识 你将具备从头开始设计Page Object、Page Factory、DATADRIVEN等搭建自动化框架的能力 用100多个实例对Selenium现实场景应用进行深入理解 全面了解TestNG, Maven, Jenkins, HTML报告,多浏览器并行测试 了解数据库测试和使用Selenium进行性能测试 你将彻底了解testNG框架 你从网上随便选择一个网站,都可以实现自动化,用所有可能的测试用例进行自动化测试 将提高你的编码技能,以编写最优化的自动化测试用例代码 你基本可以搞定任何Selenium面试,并能从设计阶段开始领导整个Selenium自动化项目 你应该能够使用应用程序的GUI来验证数据完整性 你将能够创建漂亮的报告来打动客户或领导 更深入地理解自动化指南和代码质量标准 会附带一个练习网站,可以用上所有可用的WebDriver功能,实现自动化 【适合人群】 软件手动测试人员想转为自动化测试的人员 自动化软件测试人员想加强专业技能的 刚毕业学生想从事软件行业 QA 组长或项目经理 【课程优势】 学完课程以后,你将拥有完整的Selenium Webdriver知识 【讲师介绍】 资质介绍: 12年以上软件测试工作经验,其中7年以上自动化测试开发经验 新书“Python3+Selenium3自动化测试项目实战”作者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Modify_QmQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值