WebGL笔记(四):初步封装
第一篇笔记曾经提到过WebGLHelper对象,但是实际后续的篇幅中并没有使用这个Helper。为了封装的需要,现在我们需要开始讨论并完善这个对象。在这两天的封装过程中,经过删改,WebGLHelper最终形态如下:
/*
* WebGLHelper
* 管理WebGL的辅助对象
*/
var WebGLHelper = {
/* 根据ID定位DOM元素 */
$ : function(id){
return typeof id == 'string' ? document.getElementById(id) : id;
},
/* 获取canvas标记的WebGL对象 */
$$ : function(canvas){
if(!(canvas = this.$(canvas))
|| canvas.nodeType != 1
|| canvas.nodeName.toLowerCase() != 'canvas'
){
return null;
} else {
try{
return canvas.getContext('experimental-webgl');
} catch(ex){ return null; }
}
},
/* 获取script标记中的代码 */
getShaderScript : function(script){
if(!(script = this.$(script))) return null;
var source = '', child = script.firstChild;
while(!!child){
if(child.nodeType == 3){
source += child.textContent;
}
child = child.nextSibling;
}
child = script = null;
return source;
},
/* 获取所有x-shader代码节点 */
allScripts : function(){
var arr = [], els = document.getElementsByTagName('script'), i = 0, len = els.length;
for(; i < len; i++){
if(!!els[i].type && els[i].type.toLowerCase().indexOf('x-shader/') >= 0){
arr.push(els[i]);
}
}
els = i = len = null;
if(arr.length < 1){
return arr = null
} else {
return arr;
}
},
/*
* 从所有代码节点中理出vertex和fragment两种代码
* 返回一个对象{ vs:string, fs:string }
* 如果有两个相同type的shader-script,较靠后的节点的内容会作为最终赋值
*/
documentShaders : function(){
var scripts = this.allScripts(), i = 0, len = scripts.length
shaders = {};
;
for(; i < len; i++){
switch(scripts[i].type){
case 'x-shader/x-fragment':
shaders.fs = this.getShaderScript(scripts[i]);
break;
case 'x-shader/x-vertex':
shaders.vs = this.getShaderScript(scripts[i]);
break;
}
}
return shaders;
}
}
为了减少代码,现在只保留了可能用到的方法。在以后有可能根据情况再作删改。
综合这两天的代码,另外创建了iWebGL对象。嗯,加个i是为了赶时髦的,但是加上以后这名字也的确平添了不少亲和力有木有?
下面是对前例的修改,使用iWebGL后的感觉思路比较清晰了:
/*
创建WebGL对象
第一个参数是canvas节点id
参数大于1个的时候,会调用clear方法,后面的参数将传递给clear方法
所以参数0为clear参数的第一个参数r,即背景色的红色数量
这里是为了在构造函数中调用clear
也可以
var igl = new iWebGL('glcanvas');
igl.clear();
*/
var igl = new iWebGL('glcanvas', 0);
/*
调用Shader脚本
可接受参数类型为两种情况
1.无参数.这时会在页面中搜寻script标记并加载.
2.两个参数,即shader形参方式
void shader(vert, frag);
分别加载vertex和fragment两种代码字符串
*/
igl.shader();
//定位Shader的参数并对其赋值
igl.paramVertices('aVertexPosition').define(vertices);
igl.paramColors('aVertexColor').define(generatedColors);
igl.paramVerticesIndex().define(cubeVertexIndices);
//设置场景
igl.matrix.trans([0.0, 0.0, -8.0]);
igl.matrix.make(40, 640 / 480, 0.1, 100.0);
//动画函数
var animate = function(){
igl.matrix.rotate(1, [1, 0, 1]);
igl.drawCube();;
}
//转吧
setInterval(animate, 40);
归纳为三步:
- 初始化,(获取)定义对象的相关属性;
- 加载Shader并传递数据;
- 设置场景;
- 绘制物体。
从本例开始,Shader沿用MDN的做法,混写在html中了。Js写换行字符串比较难看。
另外说明一下,为了不污染window域,我对glUtils.js文件做了一点修改,将makePerspective等几个function挪到Matrix下了,并更名为glUtils_mod.js。这两个文件都已上传。
在Chrome15和FF8下运行通过
相关文件列表:
文件 |
说明 |
这个是改过的 |
|
这个是原文件,但是本文木有用 |
|
iWebGL对象 |
|
Matrix对象基础 |
代码全文:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Step 04</title>
<style type="text/css">
canvas{ background-color:#f1f1f1; }
</style>
<script type="text/ecmascript" src="https://files.cnblogs.com/muse/sylvester.js"></script>
<script type="text/ecmascript" src="https://files.cnblogs.com/muse/glUtils_mod.js"></script>
<script type="text/ecmascript" src="https://files.cnblogs.com/muse/iWebGL_beta.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>
</head>
<body>
<canvas id="glcanvas" width="640" height="480">看来您的浏览器不支持<code><canvas></code>标记</canvas>
<script type="text/ecmascript">
var vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
var cubeVertexIndices = [
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // back
8, 9, 10, 8, 10, 11, // top
12, 13, 14, 12, 14, 15, // bottom
16, 17, 18, 16, 18, 19, // right
20, 21, 22, 20, 22, 23 // left
]
var colorGroups = [
[1.0, 0.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
[0.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 0.0, 1.0]
];
var generatedColors = [];
for(var i = 0; i < 6; i++){
for(var j = 0; j < 4; j++){
generatedColors = generatedColors.concat(colorGroups[i]);
}
}
/*
创建WebGL对象
第一个参数是canvas节点id
参数大于1个的时候,会调用clear方法,后面的参数将传递给clear方法
所以参数0为clear参数的第一个参数r,即背景色的红色数量
这里是为了在构造函数中调用clear
也可以
var igl = new iWebGL('glcanvas');
igl.clear();
*/
var igl = new iWebGL('glcanvas', 0);
/*
调用Shader脚本
可接受参数类型为两种情况
1.无参数.这时会在页面中搜寻script标记并加载.
2.两个参数,即shader形参方式
void shader(vert, frag);
分别加载vertex和fragment两种代码字符串
*/
igl.shader();
//定位Shader的参数并对其赋值
igl.paramVertices('aVertexPosition').define(vertices);
igl.paramColors('aVertexColor').define(generatedColors);
igl.paramVerticesIndex().define(cubeVertexIndices);
//设置场景
igl.matrix.trans([0.0, 0.0, -8.0]);
igl.matrix.make(40, 640 / 480, 0.1, 100.0);
//动画函数
var animate = function(){
igl.matrix.rotate(1, [1, 0, 1]);
igl.drawCube();;
}
//转吧
setInterval(animate, 40);
</script>
</body>
</html>
预告一下:下一步封装顶顶点和颜色等这类大数组。