这里首先贴出其第三章绘制正方形代码的简化版本(为了阅读流畅性,去除了一些错误判断):
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
'}\n';
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE);
var n = initVertexBuffers(gl);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
}
function initVertexBuffers(gl) {
var vertices = new Float32Array([-0.5,0.5,-0.5,-0.5,0.5,0.5,0.5,-0.5]);
var n = 4;
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
return n;
}
下面对代码中的一些关键点做个解释:
//-------------------------------------------------------------------------------------------------------------------------------
gl.clear(gl.COLOR_BUFFER_BIT);
这行代码的意思是清除缓冲区,参数可以是一下三种
gl.COLOR_BUFFER_BIT 指定颜色缓存
gl.DEPTH_BUFFER_BIT 指定深度缓冲区
gl.STENCIL_BUFFER_BIT 指定模板缓冲区
使用位操作符or(|)可用来清空多个缓冲区。
//-------------------------------------------------------------------------------------------------------------------------------
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
这行代码的意思是从向量数组中绘制图元。其原型是:void gl.drawArrays(mode,first,count)。其参数说明如下:
mode 指定绘图的方式,可接受以下常量的符号:
gl.POINTS //绘制点
gl.LINES //绘制一个线段
gl.LINE_STRIP //绘制多点线条
gl.LINE_LOOP //绘制多点封闭线条
gl.TRIANGLES //绘制单个三角形
gl.TRIANGLE_STRIP //绘制三角形条带
gl.TRIANGLE_FAN //绘制三角形扇面
first 指定从那个顶点开始绘制(整数型)
count 指定绘制需要用到多少个顶点(整数型)
//-------------------------------------------------------------------------------------------------------------------------------
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
这行代码的意思是绑定缓冲区,函数原型是gl.bindBuffer(target,buffer)。
其中target可以是下面两种:
gl.ARRAY_BUFFER 表示缓冲区对象包含了顶点的数据。
gl.ELEMENT_ARRAY_BUFFER 表示缓冲区对象中包含顶点的索引值。
buffer指定之前由gl.creareBuffer返回的待绑定的缓冲区对象,如果指定为null,则禁用对target的绑定。
//-------------------------------------------------------------------------------------------------------------------------------
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
这行代码的意思是向已经绑定的缓冲区中写入数据,函数的原型是l.bufferData(target,data,usage)
其中target的值可以是gl.ARRAY_BUFFER或gl.ELEMENT_ARRAY_BUFFER,data是写入缓冲区对象的数据,usage表示程序如何处理写入的数据,其值可以是以下三种:
gl.STATIC_DRAM 只会向缓冲区写入一次数据,但需要绘制很多次
gl.STREAM_DARM 只会向缓冲区对象写入一次数据,然后需要绘制若干次
gl.DYNAMIC_DRAM 会向缓冲区对象中写入多次数据,并绘制很多次
//-------------------------------------------------------------------------------------------------------------------------------
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
这行代码的意思是获取字符串'a_Position'参数指定的gl.program着色器对象中的attribute变量存储地址。与此类似的是下面这行代码:
var u_FragColor=gl.getUniformLocation(gl.program,'u_FragColor');
它的意思是获取字符串'au_FragColor参数指定的gl.program着色器对象中的uniform变量存储地址。
需要说明的是在shader中有三种变量类型,分别是attribute、uniform和varying。分别介绍如下:
1.attribute变量是只能在vertex着色器中使用的变量。(它不能在fragment着色器中声明attribute变量,也不能被fragment着色器中使用),一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。在application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。使用参考如下:
uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
varying vec2 v_texCoord;
void main(void)
{
gl_Position = u_matViewProjection * a_position;
v_texCoord = a_texCoord0;
}
2.uniform变量在vertex着色器和fragment着色器两者之间声明方式完全一样,则它可以在vertex着色器和fragment着色器共享使用(相当于一个被vertex着色器和fragment着色器共享的全局变量),uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。使用参考如下:
uniform mat4 viewProjMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;
3.varying变量
varying变量是vertex着色器和fragment着色器之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。application不能使用此变量。其在Vertex着色器中使用参考如下:
uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
varying vec2 v_texCoord;
void main(void)
{
gl_Position = u_matViewProjection * a_position;
v_texCoord = a_texCoord0;
}
其在Fragment着色器中使用参考如下:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_baseMap;
uniform sampler2D s_lightMap;
void main()
{
vec4 baseColor;
vec4 lightColor;
baseColor = texture2D(s_baseMap, v_texCoord);
lightColor = texture2D(s_lightMap, v_texCoord);
gl_FragColor = baseColor * (lightColor + 0.25);
}
//-------------------------------------------------------------------------------------------------------------------------------
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
这行代码的意思是将绑定到gl.ARRY_BUFFER的缓冲区对象分配给location指定的attribute变量。其函数原型是void gl.vertexAttribPointer(index, size, type, normalized, stride, offset)。其参数说明如下:
location 指定待分配attribute变量存储位置
size 指定缓冲区中每个顶点的分量个数
type 用以下类型之一来指定数据格式
gl.UNSIGNED_BYTE 无符号字节 Uint8Array
gl.SHORT 短整型 Int16Array
gl.UNSIGNED_SHORT 无符号短整型 Uint16Array
gl.INT 整型 Int32Array
gl.UNSIGNED_INT 无符号整型 Uint32Array
gl.FLOAT 浮点型 Float32Array
normalized 传入true或false,表明是否将非浮点型的数据归一化到[0,1]或[-1,1]之间
stride 指定相邻的两个顶点间的字节数,默认为0
offset 指定缓冲区对象的偏移量,即attribute变量从缓冲区中的何处开始储存。
//-------------------------------------------------------------------------------------------------------------------------------
gl.enableVertexAttribArray(a_Position);
这行代码的意思是打开(或者说激活)属性数组列表中指定索引处的通用顶点属性数组。函数的原型是void gl.enableVertexAttribArray(index);
你可以通过以下方法关闭顶点属性数组 disableVertexAttribArray()。
在WebGL中,作用于顶点的数据会先储存在attributes。这些数据仅对JavaScript代码和顶点着色器可用。属性由索引号引用到GPU维护的属性列表中。在不同的平台或GPU上,某些顶点属性索引可能具有预定义的值。创建属性时,WebGL层会分配其他属性。
无论怎样,都需要你使用enableVertexAttribArray()方法,来激活每一个属性以便使用,不被激活的属性是不会被使用的。一旦激活,以下其他方法就可以获取到属性的值了,包括vertexAttribPointer(),vertexAttrib*(),和 getVertexAttrib()。