-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 つのテクニックは、アトリビュートのオン/オフを切り替え、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);

頂点カラーのみを使用するモデルの場合、テクスチャ coord アトリビュートをオフにして、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

1 つのシェーダーで両方を使用することは可能ですが、それに伴うコーディングの量 (空の/冗長なバッファー) とパフォーマンスの問題 (GPU は分岐が非常に苦手) は、努力する価値がないため、事実上ノーです。両方を同じシーンに含めるには、レンダリング手順ごとに専用のシェーダーを使用することをお勧めします。これについては、レッスン 13で説明します。

把握するのにどれくらいの時間がかかるかというと、それは最終的に何をしたいかによって異なります。3D モデルのショールームや画像や動画の気の利いた効果など、もっとシンプルなものを作りたいだけなら、コアをスキップしてthree.jsを使用することで多くの時間を節約できます。しかし、独自のエンジンを作成したい場合は、単にバッファーを切り替えて画面に表示するだけでなく、やるべきことがたくさんあります。

より強力な JavaScript は、より創造的な思考も必要としますが、先に進む前にJavaScript について Douglas Crockfordを参照することをお勧めします。

于 2013-07-03T15:05:20.120 に答える