WebGl - 只能绘制一个对象

时间:2011-04-10 12:21:46

标签: javascript opengl opengl-es shader webgl

我正在尝试编写一个立方体函数来解决这个问题example - 为什么在我多次调用makeCube()函数时只显示一个多维数据集。当我做推/弹矩阵时,我有一种奇怪的感觉。我是webgl的新手,已经编写了一个已经使用canvas2d的游戏,并希望通过Web浏览器进入opengl。救命!我保证你可以测试我的第一场3D游戏我做错了什么? (我的代码如下所示)

        <html> 

        <head> 
        <title>Learning WebGL &mdash; lesson 4</title> 
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> 

        <script type="text/javascript" src="glMatrix-0.9.5.min.js"></script> 
        <script type="text/javascript" src="webgl-utils.js"></script> 

        <script id="shader-fs" type="x-shader/x-fragment"> 
            #ifdef GL_ES
            precision highp float;
            #endif

            varying vec4 vColor;

            void main(void) {
                gl_FragColor = vColor;
            }
        </script> 

        <script id="shader-vs" type="x-shader/x-vertex"> 
            attribute vec3 aVertexPosition;
            attribute vec4 aVertexColor;

            uniform mat4 uMVMatrix;
            uniform mat4 uPMatrix;

            varying vec4 vColor;

            void main(void) {
                gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
                vColor = aVertexColor;
            }
        </script> 


        <script type="text/javascript"> 

            var gl;

            function initGL(canvas) {
                try {
                    gl = canvas.getContext("experimental-webgl");
                    gl.viewportWidth = canvas.width;
                    gl.viewportHeight = canvas.height;
                } catch (e) {
                }
                if (!gl) {
                    alert("Could not initialise WebGL, sorry :-(");
                }
            }


            function getShader(gl, id) {
                var shaderScript = document.getElementById(id);
                if (!shaderScript) {
                    return null;
                }

                var str = "";
                var k = shaderScript.firstChild;
                while (k) {
                    if (k.nodeType == 3) {
                        str += k.textContent;
                    }
                    k = k.nextSibling;
                }

                var shader;
                if (shaderScript.type == "x-shader/x-fragment") {
                    shader = gl.createShader(gl.FRAGMENT_SHADER);
                } else if (shaderScript.type == "x-shader/x-vertex") {
                    shader = gl.createShader(gl.VERTEX_SHADER);
                } else {
                    return null;
                }

                gl.shaderSource(shader, str);
                gl.compileShader(shader);

                if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                    alert(gl.getShaderInfoLog(shader));
                    return null;
                }

                return shader;
            }

            var shaderProgram;
            function initShaders() {
                var fragmentShader = getShader(gl, "shader-fs");
                var vertexShader = getShader(gl, "shader-vs");

                shaderProgram = gl.createProgram();
                gl.attachShader(shaderProgram, vertexShader);
                gl.attachShader(shaderProgram, fragmentShader);
                gl.linkProgram(shaderProgram);

                if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
                    alert("Could not initialise shaders");
                }

                gl.useProgram(shaderProgram);

                shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
                gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

                shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
                gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);

                shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
                shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
            }

            var mvMatrix = mat4.create();
            var mvMatrixStack = [];
            var pMatrix = mat4.create();

            function mvPushMatrix() {
                var copy = mat4.create();
                mat4.set(mvMatrix, copy);
                mvMatrixStack.push(copy);
            }

            function mvPopMatrix() {
                if (mvMatrixStack.length == 0) {
                    throw "Invalid popMatrix!";
                }
                mvMatrix = mvMatrixStack.pop();
            }

            function setMatrixUniforms() {
                gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
                gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
            }


            function degToRad(degrees) {
                return degrees * Math.PI / 180;
            }


            var pyramidVertexPositionBuffer;
            var pyramidVertexColorBuffer;
            var cubeVertexPositionBuffer;
            var cubeVertexColorBuffer;
            var cubeVertexIndexBuffer;

            function initBuffers() {
                pyramidVertexPositionBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
                var vertices = [
                    // Front face
                     0.0,  1.0,  0.0,
                    -1.0, -1.0,  1.0,
                     1.0, -1.0,  1.0,

                    // Right face
                     0.0,  1.0,  0.0,
                     1.0, -1.0,  1.0,
                     1.0, -1.0, -1.0,

                    // Back face
                     0.0,  1.0,  0.0,
                     1.0, -1.0, -1.0,
                    -1.0, -1.0, -1.0,

                    // Left face
                     0.0,  1.0,  0.0,
                    -1.0, -1.0, -1.0,
                    -1.0, -1.0,  1.0
                ];
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
                pyramidVertexPositionBuffer.itemSize = 3;
                pyramidVertexPositionBuffer.numItems = 12;

                pyramidVertexColorBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
                var colors = [
                    // Front face
                    1.0, 0.0, 0.0, 1.0,
                    0.0, 1.0, 0.0, 1.0,
                    0.0, 0.0, 1.0, 1.0,

                    // Right face
                    1.0, 0.0, 0.0, 1.0,
                    0.0, 0.0, 1.0, 1.0,
                    0.0, 1.0, 0.0, 1.0,

                    // Back face
                    1.0, 0.0, 0.0, 1.0,
                    0.0, 1.0, 0.0, 1.0,
                    0.0, 0.0, 1.0, 1.0,

                    // Left face
                    1.0, 0.0, 0.0, 1.0,
                    0.0, 0.0, 1.0, 1.0,
                    0.0, 1.0, 0.0, 1.0
                ];
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
                pyramidVertexColorBuffer.itemSize = 4;
                pyramidVertexColorBuffer.numItems = 12;


                cubeVertexPositionBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
                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
                ];
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
                cubeVertexPositionBuffer.itemSize = 3;
                cubeVertexPositionBuffer.numItems = 24;

                cubeVertexColorBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
                colors = [
                    [1.0, 0.0, 0.0, 1.0], // Front face
                    [1.0, 1.0, 0.0, 1.0], // Back face
                    [0.0, 1.0, 0.0, 1.0], // Top face
                    [1.0, 0.5, 0.5, 1.0], // Bottom face
                    [1.0, 0.0, 1.0, 1.0], // Right face
                    [0.0, 0.0, 1.0, 1.0]  // Left face
                ];
                var unpackedColors = [];
                for (var i in colors) {
                    var color = colors[i];
                    for (var j=0; j < 4; j++) {
                        unpackedColors = unpackedColors.concat(color);
                    }
                }
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
                cubeVertexColorBuffer.itemSize = 4;
                cubeVertexColorBuffer.numItems = 24;

                cubeVertexIndexBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
                var cubeVertexIndices = [
                    0, 1, 2,      0, 2, 3,    // Front face
                    4, 5, 6,      4, 6, 7,    // Back face
                    8, 9, 10,     8, 10, 11,  // Top face
                    12, 13, 14,   12, 14, 15, // Bottom face
                    16, 17, 18,   16, 18, 19, // Right face
                    20, 21, 22,   20, 22, 23  // Left face
                ];
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
                cubeVertexIndexBuffer.itemSize = 1;
                cubeVertexIndexBuffer.numItems = 36;
            }


            var rPyramid = 0;
            var rCube = 0;

            function drawScene() {
              gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
              gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

              mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

              mat4.identity(mvMatrix);

              mat4.translate(mvMatrix, [-1.5, 0.0, -8.0]);



              mvPushMatrix();
              mat4.rotate(mvMatrix, degToRad(rPyramid), [0, 1, 0]);

              gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
              gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pyramidVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

              gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
              gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, pyramidVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

              setMatrixUniforms();
              gl.drawArrays(gl.TRIANGLES, 0, pyramidVertexPositionBuffer.numItems);

              mvPopMatrix();


              makeCube(
                 {'r':0.3,'g':0.3,'b':0.87,'a':1.0},  // color
                 {'x':3.5,'y':1.0,'z':2.0},       // position
                 {'x':0.0,'y':0.0,'z':0.0},       // rotation
                 0.5                     // length
              );
               makeCube(
                 {'r':0.9,'g':0.7,'b':0.17,'a':1.0},  // color
                 {'x':3.5,'y':1.0,'z':2.0},       // position
                 {'x':0.0,'y':0.0,'z':0.0},       // rotation
                 0.5                     // length
              );
               makeCube(
                 {'r':0.3,'g':0.3,'b':0.87,'a':1.0},  // color
                 {'x':3.5,'y':1.0,'z':2.0},       // position
                 {'x':0.0,'y':0.0,'z':0.0},       // rotation
                 0.1                     // length
              );
               makeCube(
                 {'r':0.3,'g':0.5,'b':0.87,'a':1.0},  // color
                 {'x':0.5,'y':3.0,'z':12.0},       // position
                 {'x':0.0,'y':0.0,'z':0.0},       // rotation
                 0.8                     // length
              );
               makeCube(
                 {'r':0.5,'g':0.3,'b':0.87,'a':1.0},  // color
                 {'x':0.1,'y':-3.0,'z':5.0},       // position
                 {'x':0.0,'y':0.0,'z':0.0},       // rotation
                 0.4                     // length
              );
            }

           var oCubeColorBuffer = null;
           function _makeCubeColorBuffer(aColor){


               oCubeColorBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, oCubeColorBuffer);
                var aColors = [
                    [aColor.r, aColor.g, aColor.b, aColor.a], // Front face
                    [aColor.r, aColor.g, aColor.b, aColor.a], // Back face
                    [aColor.r, aColor.g, aColor.b, aColor.a], // Top face
                    [aColor.r, aColor.g, aColor.b, aColor.a], // Bottom face
                    [aColor.r, aColor.g, aColor.b, aColor.a], // Right face
                    [aColor.r, aColor.g, aColor.b, aColor.a]  // Left face
                ];
                var unpackedColors = [];
                for (var i in aColors) {
                    var color = aColors[i];
                    for (var j=0; j < 4; j++) {
                        unpackedColors = unpackedColors.concat(color);
                    }
                }
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
                oCubeColorBuffer.itemSize = 4;
                oCubeColorBuffer.numItems = 24;        

              return oCubeColorBuffer;
           }

           var oCubePositionBuffer = null;    
           function _makeCubePositionBuffer(fLength){


              oCubePositionBuffer = gl.createBuffer();
              gl.bindBuffer(gl.ARRAY_BUFFER, oCubePositionBuffer);
              var aVertices = [
                 // Front face
                 -1.0*fLength, -1.0*fLength,  1.0*fLength,
                  1.0*fLength, -1.0*fLength,  1.0*fLength,
                  1.0*fLength,  1.0*fLength,  1.0*fLength,
                 -1.0*fLength,  1.0*fLength,  1.0*fLength,

                 // Back face
                 -1.0*fLength, -1.0*fLength, -1.0*fLength,
                 -1.0*fLength,  1.0*fLength, -1.0*fLength,
                  1.0*fLength,  1.0*fLength, -1.0*fLength,
                  1.0*fLength, -1.0*fLength, -1.0*fLength,

                 // Top face
                 -1.0*fLength,  1.0*fLength, -1.0*fLength,
                 -1.0*fLength,  1.0*fLength,  1.0*fLength,
                  1.0*fLength,  1.0*fLength,  1.0*fLength,
                  1.0*fLength,  1.0*fLength, -1.0*fLength,

                 // Bottom face
                 -1.0*fLength, -1.0*fLength, -1.0*fLength,
                  1.0*fLength, -1.0*fLength, -1.0*fLength,
                  1.0*fLength, -1.0*fLength,  1.0*fLength,
                 -1.0*fLength, -1.0*fLength,  1.0*fLength,

                 // Right face
                  1.0*fLength, -1.0*fLength, -1.0*fLength,
                  1.0*fLength,  1.0*fLength, -1.0*fLength,
                  1.0*fLength,  1.0*fLength,  1.0*fLength,
                  1.0*fLength, -1.0*fLength,  1.0*fLength,

                 // Left face
                 -1.0*fLength, -1.0*fLength, -1.0*fLength,
                 -1.0*fLength, -1.0*fLength,  1.0*fLength,
                 -1.0*fLength,  1.0*fLength,  1.0*fLength,
                 -1.0*fLength,  1.0*fLength, -1.0*fLength
              ];
              gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(aVertices), gl.STATIC_DRAW);
              oCubePositionBuffer.itemSize = 3;
              oCubePositionBuffer.numItems = 24;

              return oCubePositionBuffer;
           }

          var oCubeIndexBuffer = null;   
           function _makeCubeVertexIndexBuffer(){

                oCubeIndexBuffer = gl.createBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, oCubeIndexBuffer);
                var cubeVertexIndices = [
                    0, 1, 2,      0, 2, 3,    // Front face
                    4, 5, 6,      4, 6, 7,    // Back face
                    8, 9, 10,     8, 10, 11,  // Top face
                    12, 13, 14,   12, 14, 15, // Bottom face
                    16, 17, 18,   16, 18, 19, // Right face
                    20, 21, 22,   20, 22, 23  // Left face
                ];
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
                oCubeIndexBuffer.itemSize = 1;
                oCubeIndexBuffer.numItems = 36;      
              return oCubeIndexBuffer;
           }





           function makeCube(aColor, aPosition, aRotation, fLength){
                 mvPushMatrix();
                mat4.translate(mvMatrix, [aPosition.x, aPosition.y, aPosition.z]);

               // mat4.rotate(mvMatrix, degToRad(rCube), [aRotation.x, aRotation.y, aRotation.z]);

                var oCubeVertexPositionBuffer = _makeCubePositionBuffer(fLength);
                gl.bindBuffer(gl.ARRAY_BUFFER, oCubeVertexPositionBuffer);
                gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, oCubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

                var oCubeVertexColorBuffer = _makeCubeColorBuffer(aColor);
                gl.bindBuffer(gl.ARRAY_BUFFER, oCubeVertexColorBuffer);
                gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, oCubeVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);

                var oCubeVertexIndexBuffer = _makeCubeVertexIndexBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, oCubeVertexIndexBuffer);
                setMatrixUniforms();
                gl.drawElements(gl.TRIANGLES, oCubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

                mvPopMatrix();

           }





            var lastTime = 0;

            function animate() {
                var timeNow = new Date().getTime();
                if (lastTime != 0) {
                    var elapsed = timeNow - lastTime;

                    rPyramid += (90 * elapsed) / 1000.0;
                    rCube -= (75 * elapsed) / 1000.0;
                }
                lastTime = timeNow;
            }


            function tick() {
                requestAnimFrame(tick);
                drawScene();
                animate();
            }


            function webGLStart() {
                var canvas = document.getElementById("lesson04-canvas");
                initGL(canvas);
                initShaders()
                initBuffers();

                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                gl.enable(gl.DEPTH_TEST);

                tick();
            }

        </script> 


        </head> 


        <body onload="webGLStart();"> 
            <a href="http://learningwebgl.com/blog/?p=370">&lt;&lt; Back to Lesson 4</a><br /> 

            <canvas id="lesson04-canvas" style="border: none;" width="500" height="500"></canvas> 

            <br/> 
            <a href="http://learningwebgl.com/blog/?p=370">&lt;&lt; Back to Lesson 4</a><br /> 

            <!-- Google Analytics stuff, please ignore - nothing to do with WebGL :-) --> 
            <script type="text/javascript"> 
                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
            </script> 
            <script type="text/javascript"> 
                try {
                    var pageTracker = _gat._getTracker("UA-2240015-5");
                    pageTracker._trackPageview();
                } catch(err) {
                }
            </script> 

        </body> 

        </html> 

1 个答案:

答案 0 :(得分:2)

他们实际上都被吸引了。前三个是“在彼此之上”意味着它们呈现为好像它们是一个立方体。最后两个在视口的视锥之外。尝试以下调用makeCube(),你会看到两个:

      makeCube(
         {'r':0.3,'g':0.3,'b':0.87,'a':1.0},  // color
         {'x':3.5,'y':1.0,'z':2.0},       // position
         {'x':0.0,'y':0.0,'z':0.0},       // rotation
         0.5                     // length
      );
      makeCube(
         {'r':0.3,'g':0.3,'b':0.87,'a':1.0},  // color
         {'x':1.5,'y':1.0,'z':2.0},       // position
         {'x':0.0,'y':0.0,'z':0.0},       // rotation
         0.5                     // length
      );