zoukankan      html  css  js  c++  java
  • WebGL笔记(三):绘制立方体

    终于要在三维的场景里绘制一个三维的物体了——1个Cube。

    我们先来厘清几个事情:

    1. 一个立方体有6个面,每个面4个顶点,所以要绘制24个顶点。
    2. 每个顶点位置由3个数字表示,所以顶点信息是72个数字的数组。
    3. 每个顶点颜色由4个数字表示,所以颜色信息是96个数字的数组。

    先看一看长长的顶点数组:

    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
    ]

    开头说过了,一共24个顶点,这些数字应该是顶点的索引值。那他们的用处是什么呢?引用MDN原文:

    https://developer.mozilla.org/en/WebGL/Creating_3D_objects_using_WebGL

    The cubeVertexIndices array defines each face as a pair of triangles, specifying each triangle's vertices as an index into the cube's vertex array. Thus the cube is described as a collection of 12 triangles.

    E文不好的童鞋不用担心我来翻译一下,咳:大概其啊,呐,cubeVertexIndices这个数组呢,将每一个面定义为一对三角形,并且标出了每个三角形顶点在vertices数组中的索引键。这样以来呢,这个Cube——就是立方体啦——就被描述为一个12个三角形的集合。接触过3D建模的童鞋,可能对此不会太陌生。

    然后是颜色数组。MDN原文为了减少篇幅,只定义了6个颜色给6个面,然后用程序扩展为96个。

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

    颜色每个值的取值范围是0.0~1.0之间的浮点数,每一组4个值分别是红、绿、蓝和透明度。那段扩展的代码比较简单:用一个嵌套循环,将每个数组复制4次,组成一个新的数组。

    虽然颜色和顶点的数据有所变化,但是它们的定义和操作没有变化。

    绘制开始前,有两个需要注意的地方:

    一、在绘制(draw…)之前,应当对场景做初始设置。

    // 黑底, 不透明
    gl.clearColor(0.0, 0.0, 0.0, 1.0);  
    // 清除所有
    gl.clearDepth(1.0);                 
    // Enable depth testing / 开启...深度测试?
    gl.enable(gl.DEPTH_TEST);           
    // Near things obscure far things / 近处物体遮挡远处物体?
    gl.depthFunc(gl.LEQUAL);   

    因为这次涉及较为复杂的图形,如果不做设置,尤其是不开启DEPTH_TEST的话,往往会出现比较搞笑的情况。

    二、有些语句是有顺序依赖的。

    在第一篇中曾经提到过类似问题,本例中也有一处:

       1:  //定义顶点
       2:  var cubeVerticesBuffer = gl.createBuffer();
       3:  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
       4:  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
       5:  //传送数据到Shader指定变量
       6:  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
       7:   
       8:  //定义颜色
       9:  var cubeVerticesColorBuffer = gl.createBuffer();
      10:  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
      11:  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(generatedColors), gl.STATIC_DRAW);
      12:  //传送颜色数据到Shader
      13:  gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);

    在某个数据被bindBuffer之后,当前缓存数据即为该数据,在下次更改之前,必须及时传递到Shader中(vertexAttribPointer)。上面第6、13行如果顺序发生变化的话可能会引发顶点绘制错误。

    下面附上所有代码,简单写了注释,不再赘述。MatrixHelper增加了rotate方法,末尾写了一个小动画,可以看到立方体旋转起来。

    从下一篇开始,要尝试封装自己的WebGL库,像颜色、顶点之类的复杂数据也计划设计为便于操作的js类。

    WebGL03

    <!DOCTYPE HTML>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>WebGL Step 03</title>
    <style type="text/css">
    canvas{ background-color:#666; }
    </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.js"></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())); 
            }
        },
        /* mvRotate */
        rotate : function(angle, v){
            var m = Matrix.Rotation(angle * Math.PI / 180.0, $V([v[0], v[1], v[2]])).ensure4x4();
            this.mult(m);
        }
    }
    </script>
     
    </head>
     
    <body>
     
    <canvas id="glcanvas" width="640" height="480">看来您的浏览器不支持<code>&lt;canvas&gt;</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 = [
        // 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]);
        }
    }
     
    var canvas = document.getElementById('glcanvas');
    var gl = canvas.getContext('experimental-webgl');
     
    // 黑底, 不透明
    gl.clearColor(0.0, 0.0, 0.0, 1.0);  
    // 清除所有
    gl.clearDepth(1.0);                 
    // Enable depth testing / 开启...深度测试?
    gl.enable(gl.DEPTH_TEST);           
    // Near things obscure far things / 近处物体遮挡远处物体?
    gl.depthFunc(gl.LEQUAL);            
     
    //定义Vertext Shader
    var vertShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertShader, testVertexCode);
    gl.compileShader(vertShader);
    //定义Fragment Shader
    var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragShader, testFragmentCode);
    gl.compileShader(fragShader);
     //定义Program
    var program = gl.createProgram();
    //附加两个Shader到program
    gl.attachShader(program, vertShader);
    gl.attachShader(program, fragShader);
    //引用
    gl.linkProgram(program);
    gl.useProgram(program);
     
    //定位Shader所需变量并启用
    var vertexPositionAttribute = gl.getAttribLocation(program, 'aVertexPosition');
    gl.enableVertexAttribArray(vertexPositionAttribute);
     
    var vertexColorAttribute = gl.getAttribLocation(program, 'aVertexColor');
    gl.enableVertexAttribArray(vertexColorAttribute);
     
    //定义顶点索引
    var cubeVerticesIndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
     
    //定义顶点
    var cubeVerticesBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    //传送数据到Shader指定变量
    gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
     
    //定义颜色
    var cubeVerticesColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(generatedColors), gl.STATIC_DRAW);
    //传送颜色数据到Shader
    gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
     
     
    //调整位置
    var matrix = new MatrixHelper();
    matrix.trans([0.0, 0.0, -6.0]);
    matrix.make(40, 640 / 480, 0.1, 100.0);
     
    //动画函数
    var animate = function(){
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        matrix.rotate(1, [1, 0, 1]);
        matrix.set(gl, program);
        gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
    }
     
    //转吧
    setInterval(animate, 40);
     
    </script>
    </body>
    </html>
  • 相关阅读:
    css3之box-shadow
    css3之圆角
    KOA 学习(九)koa-static
    KOA 学习(八) koa-bodyparser
    KOA 学习(七) 路由koa-router
    videojs使用的常见问题
    KOA 学习(六)superAgent
    KOA 学习(四)
    Ng第五课:Octave 教程(Octave Tutorial)
    Ng第四课:多变量线性回归(Linear Regression with Multiple Variables)
  • 原文地址:https://www.cnblogs.com/muse/p/2269938.html
Copyright © 2011-2022 走看看