在上一节的JS文件里,我们将点的位置是直接编写在顶点着色器中的,虽然易于理解,但缺乏可扩展性。所以这一节,我们要将顶点的位置坐标从JS传到着色器程序中,然后再对应位置上将点绘制出来。虽然结果一样,但用到的方法是可扩展的。
目标:用另一种更灵活地方法绘制一个最简单的图形-点(位于原点(0.0,0.0,0.0)处,大小10像素)!
结果:
使用attribute变量
我们要将位置信息从JS程序中传给顶点着色器,有两种方式可以做到这点:
- attribute变量
- uniform变量
使用哪一个变量取决于需要传输的数据本身,attribute 变量传输的是那些与顶点相关的数据,而 unuform 变量传输的是那些对于所有顶点都想通的数据。本例使用 attribute 变量来传输顶点坐标。
为了使用 attribute 变量,需要包含以下步骤:
- 在顶点着色器中,声明 attribute 变量;
- 将 attribute 变量赋值给 gl_Position 变量;
- 向 attribute 变量传输数据。
HelloPoint2.js
HelloPoint2.js
//顶点着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;'+
'void main(){'+
'gl_Position=a_Position;'+
'gl_PointSize=10.0;'+
'}';
//片元着色器程序
var FSHADER_SOURCE=
'void main(){'+
'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);'+
'}';
function main() {
//获取canvas元素
var canvas = document.getElementById("webgl");
if(!canvas){
console.log("Failed to retrieve the <canvas> element");
return;
}
//获取WebGL绘图上下文
var gl = getWebGLContext(canvas);
if(!gl){
console.log("Failed to get the rendering context for WebGL");
return;
}
//初始化着色器
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("Failed to initialize shaders.");
return;
}
//获取attribute变量存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0){
console.log("Failed to get the storage location of a_Position");
return;
}
//将顶点位置传输给attribute变量
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
//指定清空<canvas>颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制一个点
gl.drawArrays(gl.POINTS, 0, 1);
}
我们在着色器中声明了 attribute 变量:
'attribute vec4 a_Position;'+
这一行中,关键词 attribute 被称为存储限定符(storage qualifier),它表示接下来的变量是一个 attribute 变量。attribute 变量必须声明成全局变量,数据将从着色器外部传给该变量。
一旦声明 a_Position 之后,我们将其赋值给 gl_Position:
'gl_Position=a_Position;'+
获取 attribute 变量的存储位置
每个变量都具有一个存储地址,以便通过存储地址向变量传输数据。
//获取attribute变量存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
方法的第一个参数是程序对象,它包括了顶点着色器和片元着色器。第二个参数是想要获取存储地址的 attribute 变量的名称。
方法的返回值是 attribute 变量的存储地址。这个地址存储在JS变量 a_Position中,之后使用。
向 attribute 变量赋值
我们使用 gl.vertexAttrib3f()向着色器传入值
//将顶点位置传输给attribute变量
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
该函数的第1个参数是 attribute 变量的存储地址,第2,3,4个参数是三个浮点型数值,即点的x, y和z坐标值。函数被调用后,这三个值被一起传给顶点坐标其中的 a_Position变量。
接着,在顶点着色器中,a_Position 的值就被赋给了 gl_Position,这样我们就成功将点的x、y和z的坐标值从JS传入了着色器,并赋值给了gl_Position。
你可能已经注意到,在顶点着色器的变量声明里,a_Postion 变量是 vec4 类型的,但是gl.vertexAttrib3f()仅传了三个分量值(x、y、z)而不是4个。其实是如果你省略了第4个参数,这个方法就会默认地将第4个分量设置为了1.0。
gl.vertexAttrib3f()同族函数
gl.vertexAttrib3f()是一系列同族函数中的一个,该系列函数的任务就是从JS向顶点着色器中的 attribute 变量传值。
结果
其实和昨天的是一样的,只是实现这一结果的的第二种方法