WebGL笔记(二):顶点着色
一、加载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>
第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;\
}';
以下为流水账:
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);
2、创建Program对象并附加Shader
var program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
3、引用Program对象
gl.linkProgram(program);
gl.useProgram(program);
4、关联gl与Shader脚本中的变量
var vertexPosAttr = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPosAttr);
var colorPosAttr = gl.getAttribLocation(program, 'aVertexColor');
gl.enableVertexAttribArray(colorPosAttr);
上面这一步在撰写本文例子的时候又有点新的心得。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
];
下面将它们附加到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);
请注意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()));
}
}
}
设置位置之前,需要在页头中引用MDN提供的两个包,我已上传到我的空间里:
这两个文件会提供一个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);
四、绘制
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
好了,大功告成。不出意外的话,你的屏幕上应该出现类似下图的内容:
好像有点意思了,至少比一个白方块强哈。本文与上一篇相比没有太多新东西。附代码:
<!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>
代码中装载Shaper脚本的script标记只是为了方便观瞻,不必纠结。