原生WebGL場景中繪製多個圓錐圓柱

       前幾天解決了原生WebGL開發中的一個問題,就是在一個場景中繪製多個幾何網格特徵不一樣的模型,好比本文所作的繪製多個圓錐和圓柱在同一個場景中,今天抽空把解決的辦法記錄下來,同時也附上代碼。首先聲明,圓柱和圓錐的網格生成是我本身寫的polyhedron.js模塊,若是要加載其餘模型,只須要把geometry換成其餘幾何體的網格便可,本文的重點不在於使用什麼幾何模型,而在於如何將各類不一樣的模型繪製到同一個場景中去。javascript

      第一件事,咱們仍是先把依賴的模型生成的js文件貼出來,以便參考者可以將代碼組裝起來。首先看工程目錄結構,以下圖html

       該工程實際用到的文件就是這4個紅框框出的文件,其中除了jquery-2.1.4.min.js之外(請於cdn或百度或51cto站點自行下載),剩下的minMatrix.js,polyhedron.js,testCoordinates.html本做都將貼出完整的源碼,以便參考者本地調試。java

       首先貼出minMatrix.js源碼,minMatrix.js負責向量矩陣的運算,因爲不是本文的中心論點,故不作贅述,以下所示jquery

// ------------------------------------------------------------------------------------------------
// minMatrix.js
// version 0.0.1
// Copyright (c) doxas
// ------------------------------------------------------------------------------------------------

function matIV(){
    this.create = function(){
        return new Float32Array(16);
    };
    this.identity = function(dest){
        dest[0]  = 1; dest[1]  = 0; dest[2]  = 0; dest[3]  = 0;
        dest[4]  = 0; dest[5]  = 1; dest[6]  = 0; dest[7]  = 0;
        dest[8]  = 0; dest[9]  = 0; dest[10] = 1; dest[11] = 0;
        dest[12] = 0; dest[13] = 0; dest[14] = 0; dest[15] = 1;
        return dest;
    };
    this.multiply = function(mat1, mat2, dest){
        var a = mat1[0],  b = mat1[1],  c = mat1[2],  d = mat1[3],
            e = mat1[4],  f = mat1[5],  g = mat1[6],  h = mat1[7],
            i = mat1[8],  j = mat1[9],  k = mat1[10], l = mat1[11],
            m = mat1[12], n = mat1[13], o = mat1[14], p = mat1[15],
            A = mat2[0],  B = mat2[1],  C = mat2[2],  D = mat2[3],
            E = mat2[4],  F = mat2[5],  G = mat2[6],  H = mat2[7],
            I = mat2[8],  J = mat2[9],  K = mat2[10], L = mat2[11],
            M = mat2[12], N = mat2[13], O = mat2[14], P = mat2[15];
        dest[0] = A * a + B * e + C * i + D * m;
        dest[1] = A * b + B * f + C * j + D * n;
        dest[2] = A * c + B * g + C * k + D * o;
        dest[3] = A * d + B * h + C * l + D * p;
        dest[4] = E * a + F * e + G * i + H * m;
        dest[5] = E * b + F * f + G * j + H * n;
        dest[6] = E * c + F * g + G * k + H * o;
        dest[7] = E * d + F * h + G * l + H * p;
        dest[8] = I * a + J * e + K * i + L * m;
        dest[9] = I * b + J * f + K * j + L * n;
        dest[10] = I * c + J * g + K * k + L * o;
        dest[11] = I * d + J * h + K * l + L * p;
        dest[12] = M * a + N * e + O * i + P * m;
        dest[13] = M * b + N * f + O * j + P * n;
        dest[14] = M * c + N * g + O * k + P * o;
        dest[15] = M * d + N * h + O * l + P * p;
        return dest;
    };
    this.scale = function(mat, vec, dest){
        dest[0]  = mat[0]  * vec[0];
        dest[1]  = mat[1]  * vec[0];
        dest[2]  = mat[2]  * vec[0];
        dest[3]  = mat[3]  * vec[0];
        dest[4]  = mat[4]  * vec[1];
        dest[5]  = mat[5]  * vec[1];
        dest[6]  = mat[6]  * vec[1];
        dest[7]  = mat[7]  * vec[1];
        dest[8]  = mat[8]  * vec[2];
        dest[9]  = mat[9]  * vec[2];
        dest[10] = mat[10] * vec[2];
        dest[11] = mat[11] * vec[2];
        dest[12] = mat[12];
        dest[13] = mat[13];
        dest[14] = mat[14];
        dest[15] = mat[15];
        return dest;
    };
    this.translate = function(mat, vec, dest){
        dest[0] = mat[0]; dest[1] = mat[1]; dest[2]  = mat[2];  dest[3]  = mat[3];
        dest[4] = mat[4]; dest[5] = mat[5]; dest[6]  = mat[6];  dest[7]  = mat[7];
        dest[8] = mat[8]; dest[9] = mat[9]; dest[10] = mat[10]; dest[11] = mat[11];
        dest[12] = mat[0] * vec[0] + mat[4] * vec[1] + mat[8]  * vec[2] + mat[12];
        dest[13] = mat[1] * vec[0] + mat[5] * vec[1] + mat[9]  * vec[2] + mat[13];
        dest[14] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
        dest[15] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
        return dest;
    };
    this.rotate = function(mat, angle, axis, dest){
        var sq = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
        if(!sq){return null;}
        var a = axis[0], b = axis[1], c = axis[2];
        if(sq != 1){sq = 1 / sq; a *= sq; b *= sq; c *= sq;}
        var d = Math.sin(angle), e = Math.cos(angle), f = 1 - e,
            g = mat[0],  h = mat[1], i = mat[2],  j = mat[3],
            k = mat[4],  l = mat[5], m = mat[6],  n = mat[7],
            o = mat[8],  p = mat[9], q = mat[10], r = mat[11],
            s = a * a * f + e,
            t = b * a * f + c * d,
            u = c * a * f - b * d,
            v = a * b * f - c * d,
            w = b * b * f + e,
            x = c * b * f + a * d,
            y = a * c * f + b * d,
            z = b * c * f - a * d,
            A = c * c * f + e;
        if(angle){
            if(mat != dest){
                dest[12] = mat[12]; dest[13] = mat[13];
                dest[14] = mat[14]; dest[15] = mat[15];
            }
        } else {
            dest = mat;
        }
        dest[0] = g * s + k * t + o * u;
        dest[1] = h * s + l * t + p * u;
        dest[2] = i * s + m * t + q * u;
        dest[3] = j * s + n * t + r * u;
        dest[4] = g * v + k * w + o * x;
        dest[5] = h * v + l * w + p * x;
        dest[6] = i * v + m * w + q * x;
        dest[7] = j * v + n * w + r * x;
        dest[8] = g * y + k * z + o * A;
        dest[9] = h * y + l * z + p * A;
        dest[10] = i * y + m * z + q * A;
        dest[11] = j * y + n * z + r * A;
        return dest;
    };
    
    
    
    
    this.lookAt = function(eye, center, up, dest){
        var eyeX    = eye[0],    eyeY    = eye[1],    eyeZ    = eye[2];
        var    centerX = center[0], centerY = center[1], centerZ = center[2];
        var    upX     = up[0],     upY     = up[1],     upZ     = up[2];
        
        if(eyeX == centerX && eyeY == centerY && eyeZ == centerZ){
            return this.identity(dest);
        }
        
        
        
        var x0, x1, x2, y0, y1, y2, z0, z1, z2, l;
        
        
        
        z0 = eyeX - centerX; z1 = eyeY - centerY; z2 = eyeZ - centerZ;
        l = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
        z0 *= l; z1 *= l; z2 *= l;
        
        
        
        x0 = upY * z2 - upZ * z1; x1 = upZ * z0 - upX * z2; x2 = upX * z1 - upY * z0;
        l = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
        if(!l){
            x0 = 0; x1 = 0; x2 = 0;
        } else {
            l = 1 / l;
            x0 *= l; x1 *= l; x2 *= l;
        }
        
        
        
        y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0;
        l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
        if(!l){
            y0 = 0; y1 = 0; y2 = 0;
        } else {
            l = 1 / l;
            y0 *= l; y1 *= l; y2 *= l;
        }
        
        
        
        dest[0] = x0; dest[1] = y0; dest[2]  = z0; dest[3]  = 0;
        dest[4] = x1; dest[5] = y1; dest[6]  = z1; dest[7]  = 0;
        dest[8] = x2; dest[9] = y2; dest[10] = z2; dest[11] = 0;
        dest[12] = -(x0 * eyeX + x1 * eyeY + x2 * eyeZ);
        dest[13] = -(y0 * eyeX + y1 * eyeY + y2 * eyeZ);
        dest[14] = -(z0 * eyeX + z1 * eyeY + z2 * eyeZ);
        dest[15] = 1;
        return dest;
    };
    
    
    this.view = function(eye, at, up, dest){
        
        var forward = [];
        forward[0] = at[0] - eye[0];
        forward[1] = at[1] - eye[1];
        forward[2] = at[2] - eye[2];
        var l = Math.sqrt(forward[0]*forward[0] + forward[1]*forward[1] + forward[2]*forward[2]);
        forward[0] = forward[0]/l; forward[1] = forward[1]/l; forward[2] = forward[2]/l;
        
        
        var side = [];
        side[0] = forward[2]*up[1] - up[2]*forward[1];
        side[1] = forward[0]*up[2] - up[0]*forward[2];
        side[2] = forward[1]*up[0] - up[1]*forward[0];
        l = Math.sqrt(side[0]*side[0] + side[1]*side[1] + side[2]*side[2]);
        side[0] = side[0]/l; side[1] = side[1]/l; side[2] = side[2]/l;
        
        
        up[0] = side[2]*forward[1] - forward[2]*side[1];
        up[1] = side[0]*forward[2] - forward[0]*side[2];
        up[2] = side[1]*forward[0] - forward[1]*side[0];
        
        
        var dest = [];
        dest[0] = side[0]; dest[1] = up[0]; dest[2] = -forward[0]; dest[3] = 0;
        dest[4] = side[1]; dest[5] = up[1]; dest[6] = -forward[1]; dest[7] = 0;
        dest[8] = side[2]; dest[9] = up[2]; dest[10]= -forward[2]; dest[11]= 0;
        dest[12]= 0;       dest[13]= 0;        dest[14]= 0;           dest[15]= 1;
        
        
        
        dest[0] = dest[0]; dest[1] = dest[1]; dest[2]  = dest[2];  dest[3]  = dest[3];
        dest[4] = dest[4]; dest[5] = dest[5]; dest[6]  = dest[6];  dest[7]  = dest[7];
        dest[8] = dest[8]; dest[9] = dest[9]; dest[10] = dest[10]; dest[11] = dest[11];
        dest[12] = dest[0] * (-eye[0]) + dest[4] * (-eye[1]) + dest[8]  * (-eye[2]) + dest[12];
        dest[13] = dest[1] * (-eye[0]) + dest[5] * (-eye[1]) + dest[9]  * (-eye[2]) + dest[13];
        dest[14] = dest[2] * (-eye[0]) + dest[6] * (-eye[1]) + dest[10] * (-eye[2]) + dest[14];
        dest[15] = dest[3] * (-eye[0]) + dest[7] * (-eye[1]) + dest[11] * (-eye[2]) + dest[15];
        
        return dest;
    }
    
    
    /**
     * 正交投影
     */
    this.ortho = function(left, right, bottom, top, near, far, dest){
        
        var a = 2/(right-left);
        var b = -(right+left)/(right-left);
        var c = 2/(top-bottom);
        var d = -(top+bottom)/(top-bottom);
        var e = 2/(far-near);
        var f = -(far+near)/(far-near);
        
        
        dest[0] = a; dest[1] = 0; dest[2] = 0; dest[3] = b;
        dest[4] = 0; dest[5] = c; dest[6] = 0; dest[7] = d;
        dest[8] = 0; dest[9] = 0; dest[10]= e; dest[11]= f;
        dest[12]= 0; dest[13]= 0; dest[14]= 0; dest[15]= 1;
        
        
        return dest;
    }
    
    
    /**
     * 透視投影
     */
    this.perspective = function(fovy, aspect, near, far, dest){
        var t = near * Math.tan(fovy * Math.PI / 360);
        var r = t * aspect;
        var a = r * 2, b = t * 2, c = far - near;
        dest[0] = near * 2 / a;
        dest[1] = 0;
        dest[2] = 0;
        dest[3] = 0;
        dest[4] = 0;
        dest[5] = near * 2 / b;
        dest[6] = 0;
        dest[7] = 0;
        dest[8] = 0;
        dest[9] = 0;
        dest[10] = -(far + near) / c;
        dest[11] = -1;
        dest[12] = 0;
        dest[13] = 0;
        dest[14] = -(far * near * 2) / c;
        dest[15] = 0;
        return dest;
    };
    this.transpose = function(mat, dest){
        dest[0]  = mat[0];  dest[1]  = mat[4];
        dest[2]  = mat[8];  dest[3]  = mat[12];
        dest[4]  = mat[1];  dest[5]  = mat[5];
        dest[6]  = mat[9];  dest[7]  = mat[13];
        dest[8]  = mat[2];  dest[9]  = mat[6];
        dest[10] = mat[10]; dest[11] = mat[14];
        dest[12] = mat[3];  dest[13] = mat[7];
        dest[14] = mat[11]; dest[15] = mat[15];
        return dest;
    };
    this.inverse = function(mat, dest){
        var a = mat[0],  b = mat[1],  c = mat[2],  d = mat[3],
            e = mat[4],  f = mat[5],  g = mat[6],  h = mat[7],
            i = mat[8],  j = mat[9],  k = mat[10], l = mat[11],
            m = mat[12], n = mat[13], o = mat[14], p = mat[15],
            q = a * f - b * e, r = a * g - c * e,
            s = a * h - d * e, t = b * g - c * f,
            u = b * h - d * f, v = c * h - d * g,
            w = i * n - j * m, x = i * o - k * m,
            y = i * p - l * m, z = j * o - k * n,
            A = j * p - l * n, B = k * p - l * o,
            ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);
        dest[0]  = ( f * B - g * A + h * z) * ivd;
        dest[1]  = (-b * B + c * A - d * z) * ivd;
        dest[2]  = ( n * v - o * u + p * t) * ivd;
        dest[3]  = (-j * v + k * u - l * t) * ivd;
        dest[4]  = (-e * B + g * y - h * x) * ivd;
        dest[5]  = ( a * B - c * y + d * x) * ivd;
        dest[6]  = (-m * v + o * s - p * r) * ivd;
        dest[7]  = ( i * v - k * s + l * r) * ivd;
        dest[8]  = ( e * A - f * y + h * w) * ivd;
        dest[9]  = (-a * A + b * y - d * w) * ivd;
        dest[10] = ( m * u - n * s + p * q) * ivd;
        dest[11] = (-i * u + j * s - l * q) * ivd;
        dest[12] = (-e * z + f * x - g * w) * ivd;
        dest[13] = ( a * z - b * x + c * w) * ivd;
        dest[14] = (-m * t + n * r - o * q) * ivd;
        dest[15] = ( i * t - j * r + k * q) * ivd;
        return dest;
    };
    this.rotateByAnyAxis = function(RawMat, axis, rad, destMat){

    };
}

       接下來就要貼出幾何體生成工具 polyhedron.js,咱們用到的幾何體是其中的圓錐 coneGeo和圓柱 cylinderGeo,這兩個類都是PolyhedronGeometry的子類,幾何體都包含頂點成員this.vertices,法向成員this.normals,索引成員this.faces。具體構造詳見代碼以下web

/**
 * Created by ccentry on 2018/10/15.
 */

/**
 * 圓錐
 * radius:底面半徑
 * height:圓錐高度
 * meshDensity:網格密度
 * */
var coneGeo = function(radius, height, segment){
    //錐頂
    var top = [0, height, 0];
    //錐底,錐底半徑radius
    //根據segment來切割錐底圓
    var sliceNum = segment || 3;
    var rad = Math.PI*2/sliceNum;
    var bottom = [];
    for(var i=0; i<sliceNum; i++){
        bottom[i*3] = radius*Math.cos(rad*i);
        bottom[i*3 + 1] = 0;
        bottom[i*3 + 2] = radius*Math.sin(rad*i);
    }
    //圓錐的頂點
    this.vertices = [];
    //頂點法向
    this.normals = [];
    //錐頂
    for(var i=0; i<sliceNum; i++){
        this.vertices[i*3] = top[0];
        this.vertices[i*3+1] = top[1];
        this.vertices[i*3+2] = top[2];
    }
    //錐面圓環
    for(var i=0; i<bottom.length; i++){
        this.vertices[3*sliceNum+i] = bottom[i];
    }
    //錐底圓環
    for(var i=0; i<bottom.length; i++){
        this.vertices[2*3*sliceNum+i] = bottom[i];
    }
    //錐底圓心
    this.vertices.push(0, 0, 0);
    //圓錐面索引
    this.faces = [];
    for(var i=sliceNum; i<2*sliceNum-1; i++){
        //圓錐側面
        this.faces.push(i, i-sliceNum, i+1);
        //圓錐底面
        this.faces.push(3*sliceNum, sliceNum+i, sliceNum+i+1);
    }
    //補側面
    this.faces.push(2*sliceNum-1, sliceNum-1, sliceNum);
    //補底面
    this.faces.push(3*sliceNum, 3*sliceNum-1, 2*sliceNum);
    //計算全部頂點法向
    this.computeNormal4EachVertex();
};

/**
 * 圓柱
 * radius:底面半徑
 * height:圓柱高度
 * meshDensity:網格密度
 * */
var cylinderGeo = function(radius, height, segment){
    radius = radius || 1;
    height = height || 1;
    //根據網格密度來切割圓柱體底圓
    var sliceNum = segment || 3;
    //底面圓弧度
    var rad = Math.PI*2/sliceNum;
    //底面圓環頂點
    var bottomVertices = [];
    //頂面頂點
    var topVertices = [];
    //切割底面圓和底面圓
    for(var i=0; i<sliceNum; i++){
        bottomVertices[3*i] = radius * Math.cos(rad * i);
        bottomVertices[3*i+1] = 0;
        bottomVertices[3*i+2] = radius * Math.sin(rad * i);

        topVertices[3*i] = radius * Math.cos(rad * i);
        topVertices[3*i+1] = height;
        topVertices[3*i+2] = radius * Math.sin(rad * i);
    }
    //圓柱的頂點
    this.vertices = [];
    for(var i=0; i<bottomVertices.length; i++){
        //底面圓
        this.vertices[i] = bottomVertices[i];
        //頂面圓
        this.vertices[bottomVertices.length + i] = topVertices[i];
        //柱底圈
        this.vertices[2*bottomVertices.length + i] = bottomVertices[i];
        //柱頂圈
        this.vertices[3*bottomVertices.length + i] = topVertices[i];
    }
    //底面圓心;
    this.vertices.push(0, 0, 0);
    //頂面圓心
    this.vertices.push(0, height, 0);
    //圓柱的面
    this.faces = [];
    for(var i=0; i<sliceNum-1; i++){
        //底面圓
        this.faces.push(4*sliceNum, i, i+1);
        //頂面圓
        this.faces.push(4*sliceNum+1, sliceNum+i+1, sliceNum+i);
        //柱身
        this.faces.push(2*sliceNum+i, 3*sliceNum+i, 2*sliceNum+i+1);
        this.faces.push(3*sliceNum+i, 3*sliceNum+i+1, 2*sliceNum+i+1);
    }
    //補底面圓
    this.faces.push(4*sliceNum, sliceNum-1, 0);
    //補頂面圓
    this.faces.push(4*sliceNum+1, sliceNum, 2*sliceNum-1);
    //補柱身
    this.faces.push(3*sliceNum-1, 4*sliceNum-1, 2*sliceNum);
    this.faces.push(4*sliceNum-1, 3*sliceNum, 2*sliceNum);
    //頂點法向
    this.normals = [];
    //計算全部頂點法向
    this.computeNormal4EachVertex();
};

/**
 * 球體
 * radius:球體半徑
 * meshDensity:網格密度
 * */
var sphereGeo = function(radius, widthSegments, heightSegments){
    var phiStart = 0;
    var phiLength = Math.PI * 2;
    var thetaStart = 0;
    var thetaLength = Math.PI;
    var thetaEnd = thetaStart + thetaLength;
    var ix, iy;
    var index = 0;
    var grid = [];
    var vertex = {};
    var normal = {};
    //存儲
    var indices = [];
    var vertices = [];
    var normals = [];
    var uvs = [];
    //生成頂點,法向,uv
    for ( iy = 0; iy <= heightSegments; iy ++ ) {
        var verticesRow = [];
        var v = iy / heightSegments;
        for ( ix = 0; ix <= widthSegments; ix ++ ) {
            var u = ix / widthSegments;
            //頂點
            vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
            vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
            vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
            vertices.push( vertex.x, vertex.y, vertex.z );
            //法向
            normal.x = vertex.x; normal.y = vertex.y; normal.z = vertex.z;
            //單位化
            this.normalize([normal.x, normal.y, normal.z]);
            normals.push( normal.x, normal.y, normal.z );
            //uv
            uvs.push( u, 1 - v );
            verticesRow.push( index ++ );
        }
        grid.push( verticesRow );
    }
    //索引數組
    for ( iy = 0; iy < heightSegments; iy ++ ) {
        for ( ix = 0; ix < widthSegments; ix ++ ) {
            var a = grid[ iy ][ ix + 1 ];
            var b = grid[ iy ][ ix ];
            var c = grid[ iy + 1 ][ ix ];
            var d = grid[ iy + 1 ][ ix + 1 ];
            if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
            if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
        }
    }
    //構造geometry
    this.faces =  indices;
    this.vertices = vertices;
    this.normals = normals;
    //this.uv = uvs;
};

var cubeGeo = function(width, height, depth){
    this.vertices = [];
    this.faces = [];
    var bottom = [];
    bottom[0] = [width/2, 0, depth/2];
    bottom[1] = [-width/2, 0, depth/2];
    bottom[2] = [-width/2, 0, -depth/2];
    bottom[3] = [width/2, 0, -depth/2];
    var top = [];
    top[0] = [width/2, height, depth/2];
    top[1] = [-width/2, height, depth/2];
    top[2] = [-width/2, height, -depth/2];
    top[3] = [width/2, height, -depth/2];
    for(var i=0; i<4; i++){
        for(var j=0; j<3; j++){
            this.vertices.push(bottom[i][j]);
        }
    }
    for(var i=0; i<4; i++){
        for(var j=0; j<3; j++){
            this.vertices.push(top[i][j]);
        }
    }
    for(var i=0; i<3; i++){
        this.faces.push(i, i+4, i+1);
        this.faces.push(i+4, i+5, i+1);
    }
    //補面
    this.faces.push(3, 7, 0);
    this.faces.push(7, 4, 0);
    //補底面
    this.faces.push(0, 1, 2, 2, 3, 0);
    //補底面
    this.faces.push(4, 7, 6, 6, 5, 4);
};

var PolyhedronGeometry = function(){
    this.type = "PolyhedronGeometry";
};

PolyhedronGeometry.prototype = {
    //座標單位話
    normalize : function(arr){
        if(arr instanceof Array){
            var sum = 0;
            for(var i=0; i<arr.length; i++){
                sum += arr[i]*arr[i];
            }
            for(var i=0; i<arr.length; i++){
                arr[i] = arr[i]/sum;
            }
        }
    },
    //計算頂點法向
    computeVertexNormal: function(face3){
        //頂點逆時針繞向
        //向量v1-v0
        var v1_0 = {};
        v1_0.x = face3[1][0] - face3[0][0];
        v1_0.y = face3[1][1] - face3[0][1];
        v1_0.z = face3[1][2] - face3[0][2];
        //向量v2-v1
        var v2_1 = {};
        v2_1.x = face3[2][0] - face3[1][0];
        v2_1.y = face3[2][1] - face3[1][1];
        v2_1.z = face3[2][2] - face3[1][2];
        //v1_0 叉乘 v2_1
        var normal = {};
        normal.x = v1_0.y * v2_1.z - v2_1.y * v1_0.z;
        normal.y = v1_0.z * v2_1.x - v2_1.z * v1_0.x;
        normal.z = v1_0.x * v2_1.y - v2_1.x * v1_0.y;
        var normalArray = [normal.x, normal.y, normal.z];
        this.normalize(normalArray);
        return normalArray;
    },
    computeNormal4EachVertex:function(){
        //遍歷索引,經過hash插值構造normals數組
        var normalList = [];
        for(var i=0; i<this.faces.length; i=i+3){
            //頂點索引
            var vertex0 = this.faces[i];
            var vertex1 = this.faces[i+1];
            var vertex2 = this.faces[i+2];
            //頂點
            var v0 = [this.vertices[3*vertex0], this.vertices[3*vertex0+1], this.vertices[3*vertex0+2]];
            var v1 = [this.vertices[3*vertex1], this.vertices[3*vertex1+1], this.vertices[3*vertex1+2]];
            var v2 = [this.vertices[3*vertex2], this.vertices[3*vertex2+1], this.vertices[3*vertex2+2]];
            //取出索引指向的頂點座標
            var face3 = [v0, v1, v2];
            var normalArray = this.computeVertexNormal(face3);
            var normal0 = {index:vertex0, normal:normalArray};
            var normal1 = {index:vertex1, normal:normalArray};
            var normal2 = {index:vertex2, normal:normalArray};
            normalList.push(normal0, normal1, normal2);
        }
        //根據index屬性排序
        var sortedNormalList = [];
        var total = normalList.length;
        for(var i=0; i<total; i++){
            for(var j=0; j<normalList.length; j++){
                if(normalList[j].index === i){
                    sortedNormalList[i] = {index:normalList[j].index, normal:normalList[j].normal};
                    //刪掉該normal節點
                    normalList.splice(j, 1);
                    break;
                }
            }
        }
        for(var i=0; i<sortedNormalList.length; i++){
            var normal = sortedNormalList[i].normal;
            this.normals.push(normal[0], normal[1], normal[2]);
        }
    }
};

coneGeo.prototype = new PolyhedronGeometry();
cylinderGeo.prototype = new PolyhedronGeometry();
sphereGeo.prototype = new PolyhedronGeometry();
cubeGeo.prototype = new PolyhedronGeometry();

       以上就是幾何體的構造函數,咱們的圓錐和圓柱即將由今生成。接下來進入咱們今天的重點,如何將多個圓錐圓柱繪製進一個場景中去,直接上html代碼,場景代碼以下canvas

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=gb2312">
    <script type="text/JavaScript" src="minMatrix.js"></script>
    <script type="text/JavaScript" src="jquery-2.1.4.min.js"></script>
    <script type="text/javascript" src="polyhedron.js"></script>

    <script id="vs" type="x-shader/x-vertex">
        attribute vec3 position;
        attribute vec3 normal;
        attribute vec4 color;
        uniform   mat4 mvpMatrix;
        uniform   mat4 invMatrix;
        uniform   vec3 lightDirection;
        uniform   vec4 ambientColor;
        varying   vec4 vColor;
        uniform   float lightS;

        void main(void){
            vec3  invLight = normalize(invMatrix * vec4(lightDirection, 0)).xyz;
            float diffuse  = clamp(dot(normal, invLight), 0.0, 1.0) * lightS;
            vColor         = color * vec4(vec3(diffuse), 1.0) + ambientColor;
            gl_Position    = mvpMatrix * vec4(position, 1.0);
        }
    </script>

    <script id="fs" type="x-shader/x-fragment">
        precision mediump float;
        varying vec4 vColor;
        void main(void){
            gl_FragColor = vColor;
        }
    </script>

    <script>
        onload = function(){
            // canvas對象獲取
            var c = document.getElementById('canvas');
            c.width = 1000;
            c.height = 800;

            // webgl的context獲取
            var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
            //初始化gl
            initGL(gl);
            // 頂點着色器和片斷着色器的生成
            var v_shader = create_shader('vs');
            var f_shader = create_shader('fs');
            // 程序對象的生成和鏈接
            var prg = create_program(v_shader, f_shader);

            // attributeLocation的獲取
            var attLocation = new Array(2);
            attLocation[0] = gl.getAttribLocation(prg, 'position');
            attLocation[1] = gl.getAttribLocation(prg, 'normal');
            attLocation[2] = gl.getAttribLocation(prg, 'color');

            // 將元素數attribute保存到數組中
            var attStride = new Array(2);
            attStride[0] = 3;
            attStride[1] = 3;
            attStride[2] = 4;








            /**
             * 光
             * */
            // 環境光,漫反射光
            var ambientColor = [0.2, 0.2, 0.2, 1.0];
            // 光照強度
            var lightS = 1.6;
            // 平行光源的方向
            var lightDirection = [1, 1, 1];

            /**
             * 視圖矩陣
             */
            // matIV對象生成
            var m = new matIV();
            // 畫布的寬高比
            var aspect = c.width / c.height;
            var mMatrix = m.identity(m.create());
            var invMatrix = m.identity(m.create());
            var tmpMatrix = m.identity(m.create());
            var mvpMatrix = m.identity(m.create());
            // 將視圖矩陣根據寬高比進行反比,避免X/Y平面內出現變形
            tmpMatrix[0] = 1/aspect;
            // 獲得mvpMatrix定位座標矩陣
            //m.multiply(tmpMatrix, mMatrix, mvpMatrix);
            // mMatrix的逆矩陣
            //m.inverse(mMatrix, invMatrix);



            /**
             * 綁定shader的uniform
             * */
            // 取得uniformLocation
            var uniLocation = new Array();
            uniLocation[0] = gl.getUniformLocation(prg, 'mvpMatrix');
            uniLocation[1] = gl.getUniformLocation(prg, 'invMatrix');
            uniLocation[2] = gl.getUniformLocation(prg, 'lightDirection');
            uniLocation[3] = gl.getUniformLocation(prg, 'ambientColor');
            uniLocation[4] = gl.getUniformLocation(prg, 'lightS');
            // 向uniformLocation中傳入座標變換矩陣
            gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
            gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
            gl.uniform3fv(uniLocation[2], lightDirection);
            gl.uniform4fv(uniLocation[3], ambientColor);
            gl.uniform1f(uniLocation[4], lightS);



            //繪製座標系
            drawCoordinates(0, 1, 0, 0);



            // 清理gl
            gl.flush();











            /**
             * 交互
             * */

            //判斷是否鼠標左鍵按下
            var mouseLeftKeyDown = false;
            //判斷是否鼠標右鍵按下
            var mouseRightKeyDown = false;
            //標記鼠標x座標
            var mouseX;
            //標記鼠標y座標
            var mouseY;
            //標記鼠標z座標
            var mouseZ;
            //旋轉球的半徑
            var R = 250;









            $('#canvas').mousedown(function(e){

                var inCircle = false;

                if(e.which == 1){
                    mouseLeftKeyDown = true;
                    mouseRightKeyDown = false;

                    mouseX = e.clientX - 0.5*c.width;
                    mouseY = -(e.clientY - 0.5*c.height);
                    if(R*R - mouseX*mouseX - mouseY*mouseY > 0){
                        mouseZ = Math.sqrt(R*R - mouseX*mouseX - mouseY*mouseY);
                    } else {
                        mouseLeftKeyDown = false;
                    }






                    //轉動前向量座標
                    $('#cordX').val(mouseX);
                    $('#cordY').val(mouseY);
                    $('#cordZ').val(mouseZ);

                } else if(e.which == 3){
                    mouseRightKeyDown = true;
                    mouseLeftKeyDown = false;
                }
            });

            $('#canvas').mouseup(function(e){
                if(e.which == 1){
                    mouseLeftKeyDown = false;
                } else if(e.which == 3){
                    mouseRightKeyDown = false;
                }
            });

            $('#canvas').mouseout(function(e){
                mouseLeftKeyDown = false;
                mouseRightKeyDown = false;
            });

            $('#canvas').mousemove(function(e){
                if(mouseLeftKeyDown){//鼠標左鍵按下

                    var X_1 = e.clientX - 0.5*c.width;
                    var Y_1 = -(e.clientY - 0.5*c.height);
                    if(R*R - X_1*X_1 - Y_1*Y_1 > 0){
                        var Z_1 = Math.sqrt(R*R - X_1*X_1 - Y_1*Y_1);
                    } else {
                        mouseLeftKeyDown = false;
                    }



                    //轉動前向量座標
                    $('#cordX').val(mouseX);
                    $('#cordY').val(mouseY);
                    $('#cordZ').val(mouseZ);

                    //轉動後向量座標
                    $('#cordX1').val(X_1);
                    $('#cordY1').val(Y_1);
                    $('#cordZ1').val(Z_1);



                    //先算出轉動軸向量
                    var axisX = -(Z_1*mouseY-mouseZ*Y_1);
                    var axisY = -(X_1*mouseZ-mouseX*Z_1);
                    var axisZ = +(Y_1*mouseX-mouseY*X_1);
                    //軸向量單位化
                    var mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
                    axisX = axisX/mod_axis;
                    axisY = axisY/mod_axis;
                    axisZ = axisZ/mod_axis;

                    var a1 = mMatrix[0]*axisX + mMatrix[1]*axisY + mMatrix[2]*axisZ + mMatrix[3]*0;
                    var a2 = mMatrix[4]*axisX + mMatrix[5]*axisY + mMatrix[6]*axisZ + mMatrix[7]*0;
                    var a3 = mMatrix[8]*axisX + mMatrix[9]*axisY + mMatrix[10]*axisZ + mMatrix[11]*0;
                    var a4 = mMatrix[12]*axisX + mMatrix[13]*axisY + mMatrix[14]*axisZ + mMatrix[15]*0;


                    axisX = a1;
                    axisY = a2;
                    axisZ = a3;
                    //軸向量單位化
                    mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
                    axisX = axisX/mod_axis;
                    axisY = axisY/mod_axis;
                    axisZ = axisZ/mod_axis;



                    //法向座標
                    $('#axisX').val(axisX);
                    $('#axisY').val(axisY);
                    $('#axisZ').val(axisZ);


                    //計算轉軸向量和轉前向量的點積
                    $('#00').val(axisX*mouseX + axisY*mouseY + axisZ*mouseZ);
                    //計算轉軸向量和轉後向量的點積
                    $('#01').val(axisX*X_1 + axisY*Y_1 + axisZ*Z_1);

                    //再計算轉動角弧度
                    //a=(x1,y1,z1),b=(x2,y2,z2) a*b=x1x2+y1y2+z1z2 |a|=√(x1^2+y1^2+z1^2).|b|=√(x2^2+y2^2+z2^2)
                    //cosθ=a*b/(|a|*|b|) 角θ=arccosθ
                    //Math.acos(x) 反餘弦函數
                    var ab = X_1*mouseX + Y_1*mouseY + Z_1*mouseZ;
                    var mod_a = Math.sqrt(X_1*X_1 + Y_1*Y_1 + Z_1*Z_1);
                    var mod_b = Math.sqrt(mouseX*mouseX + mouseY*mouseY + mouseZ*mouseZ);
                    var cosθ = ab/(mod_a*mod_b);
                    var rad = Math.acos(cosθ);


                    //轉角弧度
                    $('#rad').val(rad);



                    rotateModel(axisX, axisY, axisZ, rad);


                    mouseX = X_1;
                    mouseY = Y_1;
                    mouseZ = Z_1;

                }
            });

            $('#rotate').click(function(){
                var axisX = $('.axisX').val();
                var axisY = $('.axisY').val();
                var axisZ = $('.axisZ').val();
                var rad = $('.rad').val();
                rad = rad * Math.PI / 180;


                var a1 = mMatrix[0]*axisX + mMatrix[1]*axisY + mMatrix[2]*axisZ + mMatrix[3]*0;
                var a2 = mMatrix[4]*axisX + mMatrix[5]*axisY + mMatrix[6]*axisZ + mMatrix[7]*0;
                var a3 = mMatrix[8]*axisX + mMatrix[9]*axisY + mMatrix[10]*axisZ + mMatrix[11]*0;
                var a4 = mMatrix[12]*axisX + mMatrix[13]*axisY + mMatrix[14]*axisZ + mMatrix[15]*0;


                axisX = a1;
                axisY = a2;
                axisZ = a3;
                //軸向量單位化
                mod_axis = Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
                axisX = axisX/mod_axis;
                axisY = axisY/mod_axis;
                axisZ = axisZ/mod_axis;


                rotateModel(axisX, axisY, axisZ, rad);
            });


            /**
             * 模型旋轉函數
             * x:旋轉軸向量的x軸份量
             * y:旋轉軸向量的y軸份量
             * z:旋轉軸向量的z軸份量
             * rad:繞旋轉軸旋轉的弧度
             */
            function rotateModel(x, y, z, rad){
                initGL(gl);

                // 模型旋轉6度
                //var rad = 1 * Math.PI / 180;
                // 模型座標變換矩陣的生成(沿着Y軸旋轉)
                //m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                //m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                //m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                //gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                //gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                // 使用索引進行繪圖,畫三角面
                //gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);

                drawCoordinates(x, y, z, rad);

                // context刷新
                gl.flush();
            }






            /**
             * 生成着色器的函數
             */
            function create_shader(id){
                // 用來保存着色器的變量
                var shader;

                // 根據id從HTML中獲取指定的script標籤
                var scriptElement = document.getElementById(id);

                // 若是指定的script標籤不存在,則返回
                if(!scriptElement){return;}

                // 判斷script標籤的type屬性
                switch(scriptElement.type){

                    // 頂點着色器的時候
                    case 'x-shader/x-vertex':
                        shader = gl.createShader(gl.VERTEX_SHADER);
                        break;

                    // 片斷着色器的時候
                    case 'x-shader/x-fragment':
                        shader = gl.createShader(gl.FRAGMENT_SHADER);
                        break;
                    default :
                        return;
                }

                // 將標籤中的代碼分配給生成的着色器
                gl.shaderSource(shader, scriptElement.text);

                // 編譯着色器
                gl.compileShader(shader);

                // 判斷一下着色器是否編譯成功
                if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){

                    // 編譯成功,則返回着色器
                    return shader;
                }else{

                    // 編譯失敗,彈出錯誤消息
                    alert(gl.getShaderInfoLog(shader));
                }
            }

            /**
             * 程序對象的生成和着色器鏈接的函數
             */
            function create_program(vs, fs){
                // 程序對象的生成
                var program = gl.createProgram();

                // 向程序對象裏分配着色器
                gl.attachShader(program, vs);
                gl.attachShader(program, fs);

                // 將着色器鏈接
                gl.linkProgram(program);

                // 判斷着色器的鏈接是否成功
                if(gl.getProgramParameter(program, gl.LINK_STATUS)){

                    // 成功的話,將程序對象設置爲有效
                    gl.useProgram(program);

                    // 返回程序對象
                    return program;
                }else{

                    // 若是失敗,彈出錯誤信息
                    alert(gl.getProgramInfoLog(program));
                }
            }

            /**
             * 生成VBO的函數
             */
            function create_vbo(data){
                // 生成緩存對象
                var vbo = gl.createBuffer();

                // 綁定緩存
                gl.bindBuffer(gl.ARRAY_BUFFER, vbo);

                // 向緩存中寫入數據
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);

                // 將綁定的緩存設爲無效
                gl.bindBuffer(gl.ARRAY_BUFFER, null);

                // 返回生成的VBO
                return vbo;
            }

            /**
             * 綁定VBO相關的函數
             */
            function set_attribute(vbo, attL, attS){
                // 處理從參數中獲得的數組
                for(var i in vbo){
                    // 綁定緩存
                    gl.bindBuffer(gl.ARRAY_BUFFER, vbo[i]);

                    // 將attributeLocation設置爲有效
                    gl.enableVertexAttribArray(attL[i]);

                    //通知並添加attributeLocation
                    gl.vertexAttribPointer(attL[i], attS[i], gl.FLOAT, false, 0, 0);
                }
            }

            /**
             * IBO的生成函數
             */
            function create_ibo(data){
                // 生成緩存對象
                var ibo = gl.createBuffer();

                // 綁定緩存
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);

                // 向緩存中寫入數據
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), gl.STATIC_DRAW);

                // 將緩存的綁定無效化
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);

                // 返回生成的IBO
                return ibo;
            }

            /**
             * 初始化gl
             * */
            function initGL(gl){
                // 設定canvas初始化的顏色
                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                // 設定canvas初始化時候的深度
                gl.clearDepth(1.0);
                // canvas的初始化
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
                // 將深度測試設置爲有效
                gl.enable(gl.DEPTH_TEST);
                // 指定通常深度測試的評價方法
                gl.depthFunc(gl.LEQUAL);
                // 將遮擋剔除設置爲有效
                gl.enable(gl.CULL_FACE);
            }

            /**
             * bindBuffer
             * */
            function bindBuffer(vertexArray, normalArray, colorArray, indices){
                /**
                 * 三角面
                 */
                    // 生成VBO
                var position_vbo = create_vbo(vertexArray);
                var normal_vbo = create_vbo(normalArray);
                var color_vbo = create_vbo(colorArray);
                // 將VBO進行綁定並添加
                set_attribute([position_vbo, normal_vbo, color_vbo], attLocation, attStride);
                // 生成IBO
                var ibo = create_ibo(indices);
                // IBO進行綁定並添加
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
            }

            /**
             * 畫座標系
             **/
            function drawCoordinates(x, y, z, rad){
                /**
                 * y軸
                 * */
                //空間變換
                mMatrix = m.identity(m.create());
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓柱模型
                var cylinder = new cylinderGeo(0.03, 0.5, 15);
                var cylinderPositionY = cylinder.vertices;
                var cylinderNormalY = cylinder.normals;
                var cylinderColor = [];
                for(var i=0; i<cylinderPositionY.length/3; i++){
                    cylinderColor.push(0.6, 1.0, 0.0, 1.0);
                }
                var cylinderIndexY = cylinder.faces;
                //寫緩存綁定vertex-shader
                bindBuffer(cylinderPositionY, cylinderNormalY, cylinderColor, cylinderIndexY);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, cylinderIndexY.length, gl.UNSIGNED_SHORT, 0);

                //空間變換
                mMatrix = m.identity(m.create());
                m.translate(mMatrix, [0, 0.5, 0], mMatrix);
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓錐模型
                var cone = new coneGeo(0.05, 0.25, 15);
                var conePositionY = cone.vertices;
                var coneNormalY = cone.normals;
                var coneColorY = [];
                for(var i=0; i<conePositionY.length/3; i++){
                    coneColorY.push(0.6, 1.0, 0.0, 1.0);
                }
                var coneIndexY = cone.faces;
                bindBuffer(conePositionY, coneNormalY, coneColorY, coneIndexY);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, coneIndexY.length, gl.UNSIGNED_SHORT, 0);




                /**
                 * x軸
                 * */
                //空間變換
                mMatrix = m.identity(m.create());
                m.rotate(mMatrix, -90*Math.PI/180, [0, 0, 1], mMatrix);
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓柱模型
                var cylinderPositionX = cylinder.vertices;
                var cylinderNormalX = cylinder.normals;
                var cylinderColorX = [];
                for(var i=0; i<cylinderPositionX.length/3; i++){
                    cylinderColorX.push(0.6, 0.1, 0.0, 1.0);
                }
                var cylinderIndexX = cylinder.faces;
                //寫緩存綁定vertex-shader
                bindBuffer(cylinderPositionX, cylinderNormalX, cylinderColorX, cylinderIndexX);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, cylinderIndexX.length, gl.UNSIGNED_SHORT, 0);

                //空間變換
                mMatrix = m.identity(m.create());
                m.translate(mMatrix, [0.5, 0, 0], mMatrix);
                m.rotate(mMatrix, -90*Math.PI/180, [0, 0, 1], mMatrix);
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓錐模型
                var conePositionX = cone.vertices;
                var coneNormalX = cone.normals;
                var coneColorX = [];
                for(var i=0; i<conePositionX.length/3; i++){
                    coneColorX.push(0.6, 0.1, 0.0, 1.0);
                }
                var coneIndexX = cone.faces;
                bindBuffer(conePositionX, coneNormalX, coneColorX, coneIndexX);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, coneIndexX.length, gl.UNSIGNED_SHORT, 0);


                /**
                 * z軸
                 * */
                //空間變換
                mMatrix = m.identity(m.create());
                m.rotate(mMatrix, 90*Math.PI/180, [1, 0, 0], mMatrix);
                //圓錐姿態
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓柱模型
                var cylinderPositionZ = cylinder.vertices;
                var cylinderNormalZ = cylinder.normals;
                var cylinderColorZ = [];
                for(var i=0; i<cylinderPositionZ.length/3; i++){
                    cylinderColorZ.push(0.0, 0.1, 0.6, 1.0);
                }
                var cylinderIndexZ = cylinder.faces;
                //寫緩存綁定vertex-shader
                bindBuffer(cylinderPositionZ, cylinderNormalZ, cylinderColorZ, cylinderIndexZ);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, cylinderIndexZ.length, gl.UNSIGNED_SHORT, 0);

                //空間變換
                mMatrix = m.identity(m.create());
                m.translate(mMatrix, [0, 0, 0.5], mMatrix);
                m.rotate(mMatrix, 90*Math.PI/180, [1, 0, 0], mMatrix);
                m.rotate(mMatrix, rad, [x, y, z], mMatrix);
                // 獲得mvpMatrix定位座標矩陣
                m.multiply(tmpMatrix, mMatrix, mvpMatrix);
                // mMatrix的逆矩陣
                m.inverse(mMatrix, invMatrix);
                // 向uniformLocation中傳入座標變換矩陣
                gl.uniformMatrix4fv(uniLocation[0], false, mvpMatrix);
                gl.uniformMatrix4fv(uniLocation[1], false, invMatrix);
                //圓錐模型
                var conePositionZ = cone.vertices;
                var coneNormalZ = cone.normals;
                var coneColorZ = [];
                for(var i=0; i<conePositionZ.length/3; i++){
                    coneColorZ.push(0.0, 0.1, 0.6, 1.0);
                }
                var coneIndexZ = cone.faces;
                bindBuffer(conePositionZ, coneNormalZ, coneColorZ, coneIndexZ);
                // 使用索引進行繪圖,畫三角面
                gl.drawElements(gl.TRIANGLES, coneIndexZ.length, gl.UNSIGNED_SHORT, 0);
            }
        };


    </script>
    <script src="polyhedron.js"></script>

</head>
<body>
<canvas id="canvas"></canvas>
<br/>
轉動前X座標:<input id="cordX">轉動前Y座標:<input id="cordY">轉動前Z座標:<input id="cordZ">和轉軸的點積:<input id="00">
<br/>
轉動後X座標:<input id="cordX1">轉動後Y座標:<input id="cordY1">轉動後Z座標:<input id="cordZ1">和轉軸的點積:<input id="01">
<br/>
旋轉軸X座標份量:<input id="axisX">旋轉軸Y座標份量:<input id="axisY">旋轉軸Z座標份量:<input id="axisZ">
<br/>
旋轉角度:<input id="rad">
<br/>
===============================================旋轉操做參數===============================================
<br/>
旋轉軸X座標份量:<input class='axisX'>旋轉軸Y座標份量:<input class="axisY">旋轉軸Z座標份量:<input class="axisZ">
旋轉角度:<input class="rad">
<button id="rotate">旋轉</button>
</body>
</html>

       以上是渲染場景的html代碼,咱們先來看一下最終結果,以下圖數組

 

 

 

 

 

 

 

 

 

 

       如圖能夠看到,咱們成功將3個圓柱,3個圓錐繪製到場景中去了,那麼這個實現的核心部分在哪裏呢,咱們來分析一下,其中繪圖是採用索引緩存的方式寫入的,而和頂點着色器attribute類型的變量進行傳值的數組每次繪製一個幾何體對象都會被覆寫,而後從新寫入索引緩存,而後從新gl.drawElements繪製。這就是向一個場景中繪入多個模型的核心思想,每次要寫入一個幾何體,就從新向頂點着色器的attribute變量傳值,從新寫入索引緩存,從新繪圖,而每次繪圖都不會將以前繪製完成的幾何體從場景中擦除(這就是增量渲染)。緩存

       經過記錄這個工程案例,對gl的緩存機制又有新的認識。引用本文請註明出處http://www.javashuo.com/article/p-aulomchh-ek.html      ide

相關文章
相關標籤/搜索