一、加载Shader
本文的Shader脚本与上一篇不同,首先做一下修改:
Vertex:
1: <script id="shader-vs" type="x-shader/x-vertex">
2: attribute vec3 aVertexPosition;
3: attribute vec4 aVertexColor;
4: uniform mat4 uMVMatrix;
5: uniform mat4 uPMatrix;
6: varying lowp vec4 vColor;
7: void main(void) { 8: gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
9: vColor = aVertexColor;
10: }
11: </script>
第2、6、9行为新增的内容。
Fragment:
1: <script id="shader-fs" type="x-shader/x-fragment">
2: varying lowp vec4 vColor;
3: void main(void) { 4: gl_FragColor = vColor;
5: }
6: </script>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
第2行为新增,第4行原来为定值。
以上script中的代码主要是为了便于对比查看。还是延续上一篇的做法,本例直接将代码赋值到js变量中:
var testVertexCode = '\
attribute vec3 aVertexPosition;\
attribute vec4 aVertexColor;\
uniform mat4 uMVMatrix;\
uniform mat4 uPMatrix;\
varying lowp vec4 vColor;\
void main(void){\ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\
vColor = aVertexColor;\
}',
testFragmentCode = '\
varying lowp vec4 vColor;\
void main(void){\ gl_FragColor=vColor;\
}';
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
以下为流水账:
1、创建Shader对象
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, testVertexCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, testFragmentCode);
gl.compileShader(fragShader);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
2、创建Program对象并附加Shader
var program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
3、引用Program对象
gl.linkProgram(program);
gl.useProgram(program);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
4、关联gl与Shader脚本中的变量
var vertexPosAttr = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPosAttr);
var colorPosAttr = gl.getAttribLocation(program, 'aVertexColor');
gl.enableVertexAttribArray(colorPosAttr);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
上面这一步在撰写本文例子的时候又有点新的心得。getAttribLocation方法的第二个参数对应Shader脚本中已定义的变量名,自己则返回一个int值,根据名称猜测,该返回值应该是变量句柄之类的东西。enableVertexAttribArray方法应该是根据这个句柄来启用WebGL和Shader之间的某种关联关系。
二、创建定点及颜色
本例需要一组顶点数据和一组颜色数据,如下:
var vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
var colors = [
1.0, 1.0, 1.0, 1.0, // white
1.0, 0.0, 0.0, 1.0, // red
0.0, 1.0, 0.0, 1.0, // green
0.0, 0.0, 1.0, 1.0 // blue
];
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
下面将它们附加到gl中:
var squareVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(vertexPosAttr, 3, gl.FLOAT, false, 0, 0);
var squareVerticesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.vertexAttribPointer(colorPosAttr, 4, gl.FLOAT, false, 0, 0);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
请注意vertexAttribPointer方法的第2个参数,单个定点(XYZ)定义为3个float值,单个色彩(RGBA)定义为4个float值,上次提到,貌似这个参数应为分组数据的个数。
三、设置位置
再赘述一下MatrixHelper对象:
function MatrixHelper(){ this.matrix = Matrix.I(4); } MatrixHelper.prototype = { /* makePerspective */
make : function(fovy, aspect, znear, zfar){ this.ppm = makePerspective(fovy, aspect, znear, zfar);
},
/* multMatrix */
mult : function(m){ this.matrix = this.matrix.x(m);
},
/* mvTranslate */
trans : function(v){ this.mult(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
},
/* setMatrixUniforms */
set : function(gl, sProg){ if(!!this.ppm){ gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uPMatrix")
, false, new Float32Array(this.ppm.flatten()));
}
if(!!this.matrix){ gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uMVMatrix")
, false, new Float32Array(this.matrix.flatten()));
}
}
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
设置位置之前,需要在页头中引用MDN提供的两个包,我已上传到我的空间里:
sylvester.js
glUtils.js
这两个文件会提供一个Matrix对象来简化位置状态的设置,MatrixHelper只是重新封装了一下,下面使用它设置位置:
var matrix = new MatrixHelper();
matrix.trans([0.0, 0.0, -5.0]);
matrix.make(45, 640 / 480, 0.1, 100.0);
matrix.set(gl, program);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
四、绘制
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
好了,大功告成。不出意外的话,你的屏幕上应该出现类似下图的内容:

好像有点意思了,至少比一个白方块强哈。本文与上一篇相比没有太多新东西。附代码:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Step 02</title>
<style type="text/css">
canvas{ background-color:#666; } </style>
<script type="text/ecmascript" src="sylvester.js"></script>
<script type="text/ecmascript" src="glUtils.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying lowp vec4 vColor;
void main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
varying lowp vec4 vColor;
void main(void) { gl_FragColor = vColor;
}
</script>
<script type="text/ecmascript">
function MatrixHelper(){ this.matrix = Matrix.I(4); } MatrixHelper.prototype = { /* makePerspective */
make : function(fovy, aspect, znear, zfar){ this.ppm = makePerspective(fovy, aspect, znear, zfar);
},
/* multMatrix */
mult : function(m){ this.matrix = this.matrix.x(m);
},
/* mvTranslate */
trans : function(v){ this.mult(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
},
/* setMatrixUniforms */
set : function(gl, sProg){ if(!!this.ppm){ gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uPMatrix")
, false, new Float32Array(this.ppm.flatten()));
}
if(!!this.matrix){ gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uMVMatrix")
, false, new Float32Array(this.matrix.flatten()));
}
}
}
</script>
</head>
<body>
<canvas id="glcanvas" width="640" height="480">看来您的浏览器不支持<code><canvas></code>标记</canvas>
<script type="text/ecmascript">
var testVertexCode = '\
attribute vec3 aVertexPosition;\
attribute vec4 aVertexColor;\
uniform mat4 uMVMatrix;\
uniform mat4 uPMatrix;\
varying lowp vec4 vColor;\
void main(void){\ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\
vColor = aVertexColor;\
}',
testFragmentCode = '\
varying lowp vec4 vColor;\
void main(void){\ gl_FragColor=vColor;\
}';
var vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
var colors = [
1.0, 1.0, 1.0, 1.0, // white
1.0, 0.0, 0.0, 1.0, // red
0.0, 1.0, 0.0, 1.0, // green
0.0, 0.0, 1.0, 1.0 // blue
];
var canvas = document.getElementById('glcanvas'); var gl = canvas.getContext('experimental-webgl');
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, testVertexCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, testFragmentCode);
gl.compileShader(fragShader);
var program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
gl.linkProgram(program);
gl.useProgram(program);
var vertexPosAttr = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPosAttr);
var colorPosAttr = gl.getAttribLocation(program, 'aVertexColor');
gl.enableVertexAttribArray(colorPosAttr);
var squareVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(vertexPosAttr, 3, gl.FLOAT, false, 0, 0);
var squareVerticesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.vertexAttribPointer(colorPosAttr, 4, gl.FLOAT, false, 0, 0);
var matrix = new MatrixHelper();
matrix.trans([0.0, 0.0, -5.0]);
matrix.make(40, 640 / 480, 0.1, 100.0);
matrix.set(gl, program);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
</script>
</body>
</html>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
代码中装载Shaper脚本的script标记只是为了方便观瞻,不必纠结。