-1

我对 WebGL 有另一个问题 - 学习曲线很陡,我很抱歉 :( - 无论如何,我正在尝试制作一个显示彩色金字塔和纹理立方体的程序。我使用了基于 Nehe 的 OpenGL 教程的 WebGL 教程并且基本上尝试过将教程 4 和 5 组合在一起,看看如果我只是使用着色器程序的东西,它会如何工作,但由于某种原因它不起作用......有什么想法吗?另外,我想知道是否有人可以让我知道如何牢牢掌握 WebGL 需要多长时间?我已经掌握了很多基本概念,但要彻底学习它似乎是一座陡峭的山……

<html><head>
    <title>Learning WebGL Lesson 5</title>


    <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">
        precision mediump float;

        varying vec2 vTextureCoord;

        uniform sampler2D uSampler;

        void main(void) {
            gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
        }
        </script>

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

        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;

        varying vec2 vTextureCoord;


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




    <script id="shader-fcol" type="x-shader/x-fragment">
        precision mediump float;

        varying vec4 vColor;

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

    <script id="shader-vcol" 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;
        var shaderProgram2;

        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.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
            gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

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






            ////////////

            var colorShader = getShader(gl, "shader-fcol");
            var vertcolorShader = getShader(gl, "shader-vcol");

            shaderProgram2 = gl.createProgram();
            gl.attachShader(shaderProgram2, vertcolorShader);
            gl.attachShader(shaderProgram2, colorShader);
            gl.linkProgram(shaderProgram2);

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

            gl.useProgram(shaderProgram2);

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

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

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






        }


        function handleLoadedTexture(texture) {
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.bindTexture(gl.TEXTURE_2D, null);
        }


        var neheTexture;

        function initTexture() {
            neheTexture = gl.createTexture();
            neheTexture.image = new Image();
            neheTexture.image.onload = function () {
                handleLoadedTexture(neheTexture)
            }

            neheTexture.image.src = "nehe.gif";
        }


        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 cubeVertexPositionBuffer;
        var cubeVertexTextureCoordBuffer;
        var cubeVertexIndexBuffer;

        function initBuffers() {
            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;

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

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

                                 // Top face
                                 0.0, 1.0,
                                 0.0, 0.0,
                                 1.0, 0.0,
                                 1.0, 1.0,

                                 // Bottom face
                                 1.0, 1.0,
                                 0.0, 1.0,
                                 0.0, 0.0,
                                 1.0, 0.0,

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

                                 // Left face
                                 0.0, 0.0,
                                 1.0, 0.0,
                                 1.0, 1.0,
                                 0.0, 1.0,
                                 ];
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
            cubeVertexTextureCoordBuffer.itemSize = 2;
            cubeVertexTextureCoordBuffer.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;







            ///////////////


            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;



















        }


        var xRot = 0;
        var yRot = 0;
        var zRot = 0;

        function drawScene() {



            gl.useProgram(shaderProgram2);

            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, [-3.7, 0.0, -15.0]);

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

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

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

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

            mvPopMatrix();





            gl.useProgram(shaderProgram);



            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, [2.7, 0.0, -15.0]);

            mat4.rotate(mvMatrix, degToRad(xRot), [1, 0, 0]);
            mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]);
            mat4.rotate(mvMatrix, degToRad(zRot), [0, 0, 1]);

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

            gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
            gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, neheTexture);
            gl.uniform1i(shaderProgram.samplerUniform, 0);

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
            setMatrixUniforms();
            gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);




                    }


        var lastTime = 0;

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

                xRot += (90 * elapsed) / 1000.0;
                yRot += (90 * elapsed) / 1000.0;
                zRot += (90 * elapsed) / 1000.0;
            }
            lastTime = timeNow;
        }


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


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

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

            tick();
        }


        </script>



</head>

<body onload="webGLStart();">

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


    </body></html>
4

2 回答 2

2

一种技术是打开/关闭属性并使用 1 像素白色纹理。例如,给定一个同时使用纹理和顶点颜色的着色器,如下所示

顶点着色器

attribute vec4 a_position;
attribute vec2 a_texcoord;
attribute vec4 a_color;
uniform mat4 u_worldViewProjection;
varying vec2 v_texcoord;
varying vec4 v_color;

void main() {
  gl_Position = u_worldviewProjection * a_position;
  v_color = a_color;
  v_texcoord = a_texcoord;
}

片段着色器

precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
uniform sampler2D u_texture;

void main() {
    gl_FragColor = texture2D(u_texture, v_texcoord) * v_color;
}

假设您查找这样的位置

var colorLoc = gl.getAttribLocation("a_color");
var texcoordLoc = gl.getAttribLocatoin("a_texcoord");

然后,对于仅使用纹理的模型,关闭颜色属性并将其设置为白色

gl.disableVertexAttribArray(colorLoc);
gl.vertexAttrib4f(colorLoc, 1, 1, 1, 1);

对于仅使用顶点颜色的模型,请关闭纹理坐标属性并使用 1x1 像素白色纹理。

// at init time make a 1x1 white texture.
whiteTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, whiteTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
              new Uint8Array([1, 1, 1, 1]));


// at draw time...
// bind the white texture
gl.bindTexture(gl.TEXTURE_2D, whiteTex);
// turn off texcoords.
gl.disableVertexAttribArray(texcoordLoc);

这种技术经常在游戏中使用,因为切换着色器程序很慢。

于 2013-10-09T14:30:21.773 回答
-1

可以在一个着色器中同时拥有两者,但随之而来的编码量(空/冗余缓冲区)和性能问题(GPU 在分支方面非常糟糕)不值得付出努力,所以实际上不值得。要将两者都放在同一个场景中,建议对每个渲染过程使用专门的着色​​器。您将在第 13 课中遇到这一点。

大概需要多少时间才能掌握,嗯……这取决于你最终想用它做什么。如果你只是想做一些更简单的东西,比如 3D 模型的陈列室或一些漂亮的图像和视频效果,那么你可以跳过核心并使用three.js来节省大量时间;但是,如果您想编写自己的引擎,那么要做的不仅仅是翻转缓冲区以在屏幕上显示内容。

虽然 javascript 更强大,但也需要更多的创造性思维,在继续之前,您可能想看看Douglas Crockford 关于 javascript的知识。

于 2013-07-03T15:05:20.120 回答