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);

归纳为三步:

  1. 初始化,(获取)定义对象的相关属性;
  2. 加载Shader并传递数据;
  3. 设置场景;
  4. 绘制物体。

从本例开始,Shader沿用MDN的做法,混写在html中了。Js写换行字符串比较难看。

另外说明一下,为了不污染window域,我对glUtils.js文件做了一点修改,将makePerspective等几个function挪到Matrix下了,并更名为glUtils_mod.js。这两个文件都已上传。

在Chrome15和FF8下运行通过

捕获2捕获3


相关文件列表:

文件

说明

glUtils_mod.js 

这个是改过的

glUtils.js

这个是原文件,但是本文木有用

iWebGL_beta.js 

iWebGL对象

sylvester.js

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>&lt;canvas&gt;</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>

预告一下:下一步封装顶顶点和颜色等这类大数组。

原文地址:https://www.cnblogs.com/muse/p/2271846.html