WebGL立方體旋轉

在本章中,我們將舉一個例子來演示如何使用WebGL繪製一個旋轉3D立方體。

示例 - 繪製一個旋轉的3D立方體


以下程序顯示瞭如何繪製一個旋轉的3D立方體 -

  <script>

     /\*============= Creating a canvas =================\*/
     var canvas = document.getElementById('my\_Canvas');
     gl = canvas.getContext('experimental-webgl');

     /\*============ Defining and storing the geometry =========\*/

     var vertices = \[
        -1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
        -1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
        -1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
        1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
        -1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
        -1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1, 
     \];

     var colors = \[
        5,3,7, 5,3,7, 5,3,7, 5,3,7,
        1,1,3, 1,1,3, 1,1,3, 1,1,3,
        0,0,1, 0,0,1, 0,0,1, 0,0,1,
        1,0,0, 1,0,0, 1,0,0, 1,0,0,
        1,1,0, 1,1,0, 1,1,0, 1,1,0,
        0,1,0, 0,1,0, 0,1,0, 0,1,0
     \];

     var indices = \[
        0,1,2, 0,2,3, 4,5,6, 4,6,7,
        8,9,10, 8,10,11, 12,13,14, 12,14,15,
        16,17,18, 16,18,19, 20,21,22, 20,22,23 
     \];

     // Create and store data into vertex buffer
     var vertex\_buffer = gl.createBuffer ();
     gl.bindBuffer(gl.ARRAY\_BUFFER, vertex\_buffer);
     gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(vertices), gl.STATIC\_DRAW);

     // Create and store data into color buffer
     var color\_buffer = gl.createBuffer ();
     gl.bindBuffer(gl.ARRAY\_BUFFER, color\_buffer);
     gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(colors), gl.STATIC\_DRAW);

     // Create and store data into index buffer
     var index\_buffer = gl.createBuffer ();
     gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, index\_buffer);
     gl.bufferData(gl.ELEMENT\_ARRAY\_BUFFER, new Uint16Array(indices), gl.STATIC\_DRAW);

     /\*=================== Shaders =========================\*/

     var vertCode = 'attribute vec3 position;'+
        'uniform mat4 Pmatrix;'+
        'uniform mat4 Vmatrix;'+
        'uniform mat4 Mmatrix;'+
        'attribute vec3 color;'+//the color of the point
        'varying vec3 vColor;'+

        'void main(void) { '+//pre-built function
           'gl\_Position = Pmatrix\*Vmatrix\*Mmatrix\*vec4(position, 1.);'+
           'vColor = color;'+
        '}';

     var fragCode = 'precision mediump float;'+
        'varying vec3 vColor;'+
        'void main(void) {'+
           'gl\_FragColor = vec4(vColor, 1.);'+
        '}';

     var vertShader = gl.createShader(gl.VERTEX\_SHADER);
     gl.shaderSource(vertShader, vertCode);
     gl.compileShader(vertShader);

     var fragShader = gl.createShader(gl.FRAGMENT\_SHADER);
     gl.shaderSource(fragShader, fragCode);
     gl.compileShader(fragShader);

     var shaderProgram = gl.createProgram();
     gl.attachShader(shaderProgram, vertShader);
     gl.attachShader(shaderProgram, fragShader);
     gl.linkProgram(shaderProgram);

     /\* ====== Associating attributes to vertex shader =====\*/
     var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
     var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
     var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");

     gl.bindBuffer(gl.ARRAY\_BUFFER, vertex\_buffer);
     var position = gl.getAttribLocation(shaderProgram, "position");
     gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;

     // Position
     gl.enableVertexAttribArray(position);
     gl.bindBuffer(gl.ARRAY\_BUFFER, color\_buffer);
     var color = gl.getAttribLocation(shaderProgram, "color");
     gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;

     // Color
     gl.enableVertexAttribArray(color);
     gl.useProgram(shaderProgram);

     /\*==================== MATRIX =====================\*/

     function get\_projection(angle, a, zMin, zMax) {
        var ang = Math.tan((angle\*.5)\*Math.PI/180);//angle\*.5
        return \[
           0.5/ang, 0 , 0, 0,
           0, 0.5\*a/ang, 0, 0,
           0, 0, -(zMax+zMin)/(zMax-zMin), -1,
           0, 0, (-2\*zMax\*zMin)/(zMax-zMin), 0 
        \];
     }

     var proj\_matrix = get\_projection(40, canvas.width/canvas.height, 1, 100);

     var mov\_matrix = \[1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1\];
     var view\_matrix = \[1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1\];

     // translating z
     view\_matrix\[14\] = view\_matrix\[14\]-6;//zoom

     /\*==================== Rotation ====================\*/

     function rotateZ(m, angle) {
        var c = Math.cos(angle);
        var s = Math.sin(angle);
        var mv0 = m\[0\], mv4 = m\[4\], mv8 = m\[8\];

        m\[0\] = c\*m\[0\]-s\*m\[1\];
        m\[4\] = c\*m\[4\]-s\*m\[5\];
        m\[8\] = c\*m\[8\]-s\*m\[9\];

        m\[1\]=c\*m\[1\]+s\*mv0;
        m\[5\]=c\*m\[5\]+s\*mv4;
        m\[9\]=c\*m\[9\]+s\*mv8;
     }

     function rotateX(m, angle) {
        var c = Math.cos(angle);
        var s = Math.sin(angle);
        var mv1 = m\[1\], mv5 = m\[5\], mv9 = m\[9\];

        m\[1\] = m\[1\]\*c-m\[2\]\*s;
        m\[5\] = m\[5\]\*c-m\[6\]\*s;
        m\[9\] = m\[9\]\*c-m\[10\]\*s;

        m\[2\] = m\[2\]\*c+mv1\*s;
        m\[6\] = m\[6\]\*c+mv5\*s;
        m\[10\] = m\[10\]\*c+mv9\*s;
     }

     function rotateY(m, angle) {
        var c = Math.cos(angle);
        var s = Math.sin(angle);
        var mv0 = m\[0\], mv4 = m\[4\], mv8 = m\[8\];

        m\[0\] = c\*m\[0\]+s\*m\[2\];
        m\[4\] = c\*m\[4\]+s\*m\[6\];
        m\[8\] = c\*m\[8\]+s\*m\[10\];

        m\[2\] = c\*m\[2\]-s\*mv0;
        m\[6\] = c\*m\[6\]-s\*mv4;
        m\[10\] = c\*m\[10\]-s\*mv8;
     }

     /\*================= Drawing ===========================\*/
     var time\_old = 0;

     var animate = function(time) {

        var dt = time-time\_old;
        rotateZ(mov\_matrix, dt\*0.005);//time
        rotateY(mov\_matrix, dt\*0.002);
        rotateX(mov\_matrix, dt\*0.003);
        time\_old = time;

        gl.enable(gl.DEPTH\_TEST);
        gl.depthFunc(gl.LEQUAL);
        gl.clearColor(0.5, 0.5, 0.5, 0.9);
        gl.clearDepth(1.0);

        gl.viewport(0.0, 0.0, canvas.width, canvas.height);
        gl.clear(gl.COLOR\_BUFFER\_BIT | gl.DEPTH\_BUFFER\_BIT);
        gl.uniformMatrix4fv(Pmatrix, false, proj\_matrix);
        gl.uniformMatrix4fv(Vmatrix, false, view\_matrix);
        gl.uniformMatrix4fv(Mmatrix, false, mov\_matrix);
        gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, index\_buffer);
        gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED\_SHORT, 0);

        window.requestAnimationFrame(animate);
     }
     animate(0);

  </script>

這將產生以下結果(這裏只能放靜態圖片,具體旋轉效果可自己運行代碼觀察)  -
WebGL立方體旋轉