【问题标题】:WebGL vertexAttribPointer points to the wrong VBOWebGL vertexAttribPointer 指向错误的 VBO
【发布时间】:2017-12-21 01:14:37
【问题描述】:

我正在尝试创建两个网格,一个正方形和一个三角形。代码在底部。

我首先为第一个网格创建一个着色器程序“program1”、数组缓冲区“vertexBuffer1”和一个元素数组缓冲区“indexBuffer1”。第一个网格是正方形。

然后我对第二个网格做同样的事情。第二个网格是三角形。

当我运行代码时出现错误:

[.Offscreen-For-WebGL-000002B76A973870]GL 错误:GL_INVALID_OPERATION:glDrawElements:尝试访问属性 0 中超出范围的顶点

如果我注释掉这一行,我不会收到错误消息:

//gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0); // <- problem!

我认为正在发生的事情是三角形的 vbo(“vertexBuffer2”)以某种方式连接到正方形的着色器程序(“program1”)。这导致

gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_SHORT, 0);

失败,因为它试图从三角形顶点缓冲区中绘制一个正方形。

我不明白为什么

gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0); // <- problem!

导致“program1”连接到“vertexBuffer2”,如果这甚至是问题的话。如何让这两个程序(“program1”和“program2”)分别连接到它们的缓冲区?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
</head>
<body>
    <canvas id="canvas" width="500" height="450" style="border:1px solid black"></canvas>
    <script>
        // setup gl
        var canvas = document.getElementById("canvas");
        var gl = canvas.getContext("webgl");
        gl.enable(gl.DEPTH_TEST);
        gl.depthFunc(gl.LEQUAL);
        gl.clearColor(0.5, 0.5, 0.5, 0.9);
        gl.clearDepth(1.0);

        gl.viewport(0.0, 0.0, canvas.width, canvas.height);

        // setup mesh 1
        // // vertex shader
        var vertexShader1 = gl.createShader(gl.VERTEX_SHADER);
        var vertexShaderCode = `
            // in
            attribute vec3 position;

            void main(void) {
                gl_Position = vec4(position, 1.);
            }
        `;
        gl.shaderSource(vertexShader1, vertexShaderCode);
        gl.compileShader(vertexShader1);
        // // fragment shader
        var fragmentShader1 = gl.createShader(gl.FRAGMENT_SHADER);
        var fragmentShaderCode = `
            precision mediump float;
            // in
            void main(void) {
                gl_FragColor = vec4(1., 0., 0., 1.);
            }
        `;
        gl.shaderSource(fragmentShader1, fragmentShaderCode);
        gl.compileShader(fragmentShader1);
        // // program1
        var program1 = gl.createProgram();
        gl.attachShader(program1, vertexShader1);
        gl.attachShader(program1, fragmentShader1);
        gl.linkProgram(program1);
        gl.useProgram(program1);

        // // create buffer 1
        var vertices1 = [ // suqare
            -0.5, -0.5, 0,
            0.5, -0.5, 0,
            0.5, 0.5, 0,
            -0.5, 0.5, 0,
        ];
        var vertexBuffer1 = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices1), gl.STATIC_DRAW);
        var loc = gl.getAttribLocation(program1, "position");
        gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(loc);

        var indices1 = [
            0,1,2,
            0,2,3,
        ];
        var indexBuffer1 = gl.createBuffer ();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices1), gl.STATIC_DRAW);

        // setup mesh 2
        // // vertex shader
        var vertexShader2 = gl.createShader(gl.VERTEX_SHADER);

        gl.shaderSource(vertexShader2, vertexShaderCode); // uses same vertexShaderCode as above
        gl.compileShader(vertexShader2);
        // // fragment shader
        var fragmentShader2 = gl.createShader(gl.FRAGMENT_SHADER);

        gl.shaderSource(fragmentShader2, fragmentShaderCode);
        gl.compileShader(fragmentShader2);
        // // program2
        var program2 = gl.createProgram();
        gl.attachShader(program2, vertexShader2);
        gl.attachShader(program2, fragmentShader2);
        gl.linkProgram(program2);
        gl.useProgram(program2);

        // // create buffer 2
        var vertices2 = [ // triangle one less vertex than in buffer 1
            -0.5, -0.5, 0,
            0.5, -0.5, 0,
            0.5, 0.5, 0,
        ];
        var vertexBuffer2 = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices2), gl.STATIC_DRAW);
        var loc = gl.getAttribLocation(program2, "position");
        // On the line below it seems like program1 instead of program2 gets connected to the vertexBuffer2
        gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0); // <- problem!
        gl.enableVertexAttribArray(loc);

        var indices2 = [
            0,1,2,
        ];
        var indexBuffer2 = gl.createBuffer ();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer2);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices2), gl.STATIC_DRAW);

        // render
        // // clear
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        // // render mesh 1 (the square)
        gl.useProgram(program1);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
        gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_SHORT, 0); // <- this line fail
    </script>
</body>
</html>

【问题讨论】:

    标签: webgl shader


    【解决方案1】:

    注意,gl.vertexAttribPointer 指定通用顶点属性数组的状态。

    首先创建并绑定vertexBuffer1indexBuffer1program1。你指定:

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1);
    ....
    var loc = gl.getAttribLocation(program1, "position"); // loc == 0
    gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(loc);
    

    第二次创建并绑定vertexBuffer2indexBuffer2program2。你指定:

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
    ....
    var loc = gl.getAttribLocation(program2, "position"); // loc == 0
    gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(loc);
    

    你终于打电话了:

    gl.useProgram(program1);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
    gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_SHORT, 0);
    

    此时顶点缓冲区状态仍指向vertexBuffer2,因为这是您为索引为 0 的通用顶点属性指定的最后一个状态。

    像这样更改你的代码:

    gl.linkProgram(program1);
    var loc1 = gl.getAttribLocation(program1, "position");
    
    ....
    
    gl.useProgram(program1);
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1);
    gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(loc);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
    gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_SHORT, 0);
    

    注意,在绘制网格之前设置顶点属性就足够了。要管理顶点属性的不同状态,您可以使用 VertexArrayObjects,它在 WebGL 2.0 中受支持,或者在 WebGL 1.0 中通过 extension 提供。


    见代码sn -p:

    // setup gl
            var canvas = document.getElementById("canvas");
            var gl = canvas.getContext("webgl");
            gl.enable(gl.DEPTH_TEST);
            gl.depthFunc(gl.LEQUAL);
            gl.clearColor(0.5, 0.5, 0.5, 0.9);
            gl.clearDepth(1.0);
    
            gl.viewport(0.0, 0.0, canvas.width, canvas.height);
    
            // setup mesh 1
            // // vertex shader
            var vertexShader1 = gl.createShader(gl.VERTEX_SHADER);
            var vertexShaderCode = `
                // in
                attribute vec3 position;
    
                void main(void) {
                    gl_Position = vec4(position, 1.);
                }
            `;
            gl.shaderSource(vertexShader1, vertexShaderCode);
            gl.compileShader(vertexShader1);
            // // fragment shader
            var fragmentShader1 = gl.createShader(gl.FRAGMENT_SHADER);
            var fragmentShaderCode = `
                precision mediump float;
                // in
                void main(void) {
                    gl_FragColor = vec4(1., 0., 0., 1.);
                }
            `;
            gl.shaderSource(fragmentShader1, fragmentShaderCode);
            gl.compileShader(fragmentShader1);
            // // program1
            var program1 = gl.createProgram();
            gl.attachShader(program1, vertexShader1);
            gl.attachShader(program1, fragmentShader1);
            gl.linkProgram(program1);
            var loc1 = gl.getAttribLocation(program1, "position");
            
            // // create buffer 1
            var vertices1 = [ // suqare
                -0.5, -0.5, 0,
                0.5, -0.5, 0,
                0.5, 0.5, 0,
                -0.5, 0.5, 0,
            ];
            var vertexBuffer1 = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices1), gl.STATIC_DRAW);
                        
            var indices1 = [
                0,1,2,
                0,2,3,
            ];
            var indexBuffer1 = gl.createBuffer ();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices1), gl.STATIC_DRAW);
    
            // setup mesh 2
            // // vertex shader
            var vertexShader2 = gl.createShader(gl.VERTEX_SHADER);
    
            gl.shaderSource(vertexShader2, vertexShaderCode); // uses same vertexShaderCode as above
            gl.compileShader(vertexShader2);
            // // fragment shader
            var fragmentShader2 = gl.createShader(gl.FRAGMENT_SHADER);
    
            gl.shaderSource(fragmentShader2, fragmentShaderCode);
            gl.compileShader(fragmentShader2);
            // // program2
            var program2 = gl.createProgram();
            gl.attachShader(program2, vertexShader2);
            gl.attachShader(program2, fragmentShader2);
            gl.linkProgram(program2);
            var loc2 = gl.getAttribLocation(program2, "position");
            
            // // create buffer 2
            var vertices2 = [ // triangle one less vertex than in buffer 1
                -0.5, -0.5, 0,
                0.5, -0.5, 0,
                0.5, 0.5, 0,
            ];
            var vertexBuffer2 = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices2), gl.STATIC_DRAW);
    
            var indices2 = [
                0,1,2,
            ];
            var indexBuffer2 = gl.createBuffer ();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer2);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices2), gl.STATIC_DRAW);
    
            // render
            // // clear
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            // // render mesh 1 (the square)
            gl.useProgram(program1);
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1);
            gl.vertexAttribPointer(loc1, 3, gl.FLOAT, false, 0, 0); // <- problem!
            gl.enableVertexAttribArray(loc1);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer1);
            gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_SHORT, 0); // <- this line fail
    &lt;canvas id="canvas" width="500" height="450" style="border:1px solid black"&gt;&lt;/canvas&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      相关资源
      最近更新 更多