WebGL vertexAttribPointer指向错误的VBO

问题描述 投票:1回答:1

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

我首先为第一个网格创建一个着色器程序“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个回答
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);

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

请参阅代码段:

// 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
<canvas id="canvas" width="500" height="450" style="border:1px solid black"></canvas>
© www.soinside.com 2019 - 2024. All rights reserved.