javascript基础学习系列四百七十四:调试着色器和程序
给着色器传值前面定义的每个着色器都需要传入一个值,才能完成工作。要给着色器传值,必须先找到要接收值 的变量。对于 uniform 变量,可以调用 gl.getUniformLocation()方法。这个方法返回一个对象,这个例子从 program 中找到 uniform 变量 uColor,然后返回了它的内存位置。第二行代码调用 gl.uniform4fv()方法给 uColor 传入了值。给顶点
给着色器传值
前面定义的每个着色器都需要传入一个值,才能完成工作。要给着色器传值,必须先找到要接收值 的变量。对于 uniform 变量,可以调用 gl.getUniformLocation()方法。这个方法返回一个对象,
这个例子从 program 中找到 uniform 变量 uColor,然后返回了它的内存位置。第二行代码调用 gl.uniform4fv()方法给 uColor 传入了值。
给顶点着色器传值也是类似的过程。而要获得 attribute 变量的位置,可以调用 gl.getAttrib- Location()方法。找到变量的内存地址后,可以像下面这样给它传入值:
let aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); gl.enableVertexAttribArray(aVertexPosition); gl.vertexAttribPointer(aVertexPosition, itemSize, gl.FLOAT, false, 0, 0);
表示该 uniform 变量在内存中的位置。然后,可以使用这个位置来完成赋值。比如: let uColor = gl.getUniformLocation(program, “uColor”);
gl.uniform4fv(uColor, [0, 0, 0, 1]);
这里,首先取得 aVertexPosition 的内存位置,然后使用 gl.enableVertexAttribArray() 来启用。最后一行代码创建了一个指向调用 gl.bindBuffer()指定的缓冲区的指针,并把它保存在 aVertexPosition 中,从而可以在后面由顶点着色器使用。
调试着色器和程序
与 WebGL 中的其他操作类似,着色器操作也可能失败,而且是静默失败。如果想知道发生了什么 错误,则必须手工通过 WebGL 上下文获取关于着色器或程序的信息。 20
对于着色器,可以调用 gl.getShaderParameter()方法取得编译之后的编译状态:
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { alert(gl.getShaderInfoLog(vertexShader));
}
着色器程序也可能失败,因此也有类似的方法。gl.getProgramParameter()用于检测状态。最 23 常见的程序错误发生在链接阶段,为此可以使用以下代码来检查:
这个例子检查了 vertexShader 编译的状态。如果着色器编译成功,则调用 gl.getShaderParameter() 会返回 true。如果返回 false,则说明编译出错了。此时,可以使用 gl.getShaderInfoLog()并传 入着色器取得错误。这个方法返回一个字符串消息,表示问题所在。
gl.getShaderParameter()和 gl.getShaderInfoLog()既可以用于顶点着色器,也可以用于片段着色器。
alert(gl.getProgramInfoLog(program));
}
与gl.getShaderParameter()一样,gl.getProgramParameter()会在链接成功时返回true, 失败时返回 false。当然也有一个 gl.getProgramInfoLog()方法,可以在程序失败时获取错误 信息。
这些方法主要在开发时用于辅助调试。只要没有外部依赖,在产品环境中就可以放心地删除它们。
GLSL 100 升级到 GLSL 300
WebGL2 的主要变化是升级到了 GLSL 3.00 ES 着色器。这个升级暴露了很多新的着色器功能,包括 3D 纹理等在支持 OpenGL ES 3.0 的设备上都有的功能。要使用升级版的着色器,着色器代码的第一行必须是: 27
#version 300 es
这个升级需要一些语法的变化。
顶点 attribute 变量要使用 in 而不是 attribute 关键字声明。
使用 varying 关键字为顶点或片段着色器声明的变量,现在必须根据相应着色器的行为改为使 用in或out。
预定义的输出变量 gl_FragColor 没有了,片段着色器必须为颜色输出声明自己的 out 变量。
纹理查找函数 texture2D 和 textureCube 统一成了一个 texture 函数。
绘图
WebGL 只能绘制三种形状:点、线和三角形。其他形状必须通过这三种基本形状在 3D 空间的组合 来绘制。WebGL 绘图要使用 drawArrays()和 drawElements()方法,前者使用数组缓冲区,后者则 操作元素数组缓冲区。
drawArrays()和 drawElements()的第一个参数都表示要绘制形状的常量。下面列出了这些常量。
gl.POINTS:将每个顶点当成一个点来绘制。
gl.LINES:将数组作为一系列顶点,在这些顶点间绘制直线。每个顶点既是起点也是终点,因
此数组中的顶点必须是偶数个才能开始绘制。
gl.LINE_LOOP:将数组作为一系列顶点,在这些顶点间绘制直线。从第一个顶点到第二个顶点
绘制一条直线,再从第二个顶点到第三个顶点绘制一条直线,以此类推,直到绘制到最后一个
顶点。此时再从最后一个顶点到第一个顶点绘制一条直线。这样就可以绘制出形状的轮廓。
gl.LINE_STRIP:类似于 gl.LINE_LOOP,区别在于不会从最后一个顶点到第一个顶点绘制直线。
gl.TRIANGLES:将数组作为一系列顶点,在这些顶点间绘制三角形。如不特殊指定,每个三角
形都分开绘制,不共享顶点。
gl.TRIANGLES_STRIP:类似于 gl.TRIANGLES,区别在于前 3 个顶点之后的顶点会作为第三
个顶点与其前面的两个顶点构成三角形。例如,如果数组中包含顶点 A、B、C、D,那么第一个
三角形使用 ABC,第二个三角形使用 BCD。
gl.TRIANGLES_FAN:类似于 gl.TRIANGLES,区别在于前 3 个顶点之后的顶点会作为第三个
顶点与其前面的顶点和第一个顶点构成三角形。例如,如果数组中包含顶点 A、B、C、D,那么
第一个三角形使用 ABC,第二个三角形使用 ACD。
以上常量可以作为 gl.drawArrays()方法的第一个参数,第二个参数是数组缓冲区的起点索引,
第三个参数是数组缓冲区包含的顶点集合的数量。以下代码使用 gl.drawArrays()在画布上绘制了一 个三角形:
// 假设已经使用本节前面的着色器清除了视口
// 定义3个顶点的x坐标和y坐标
let vertices = new Float32Array([ 0, 1, 1, -1, -1, -1 ]),
buffer = gl.createBuffer(),
vertexSetSize = 2,
vertexSetCount = vertices.length/vertexSetSize,
uColor,
aVertexPosition;
// 将数据放入缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 给片段着色器传入颜色
uColor = gl.getUniformLocation(program, "uColor"); gl.uniform4fv(uColor, [ 0, 0, 0, 1 ]);
// 把顶点信息传给着色器
aVertexPosition = gl.getAttribLocation(program, "aVertexPosition"); gl.enableVertexAttribArray(aVertexPosition);
接着给顶点着色器传入顶点集的大小,以及表示顶点坐标数值类型的 gl.FlOAT。第四个参数是一 个布尔值,表示坐标不是标准的。第五个参数是步长值(stride value),表示跳过多个数组元素取得下一 个值。除非真要跳过一些值,否则就向这里传入 0 即可。最后一个参数是起始偏移量,这里的 0 表示从 第一个数组元素开始。 18
最后一步是使用 gl.drawArrays()把三角形绘制出来。通过把第一个参数指定为 gl.TRIANGLES, 就可以从(0, 1)到(1, –1)再到(–1, –1)绘制一个三角形,并填充传给片段着色器的颜色。第二个参数表示缓 冲区的起始偏移量,最后一个参数是要读取的顶点数量。以上绘图操作的结果
这个例子定义了一个 Float32Array 变量,它包含 3 组两个点的顶点。完成计算的关键是跟踪顶 点大小和数量。将 vertexSetSize 的值指定为 2,再计算出 vertexSetCount。顶点信息保存在了缓 冲区。然后把颜色信息传给片段着色器。
gl.vertexAttribPointer(aVertexPosition, vertexSetSize, gl.FLOAT, false, 0, 0); // 绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, vertexSetCount);
通过改变 gl.drawArrays()的第一个参数,可以修改绘制三角形的方式。图 18-17 展示了修改第
一个参数之后的两种输出。
更多推荐
所有评论(0)