"GL_INVALID_OPERATION: Insufficient buffer size." 在可变数量的渲染调用之后

"GL_INVALID_OPERATION: Insufficient buffer size." after variable number of render calls

我正在使用 MapboxGL 将 geojson 作为多边形渲染到地图上。页面正确加载和呈现,但是当我四处移动地图时,在一定数量(通常在 ~30-100 之间)的呈现调用和多边形消失后出现此错误。

GL_INVALID_OPERATION: 缓冲区大小不足。 (Chrome)

WebGL 警告:drawElementsInstanced:索引缓冲区太小。 (FF)

我已经设法(我认为)将其缩小到

的问题
gl.drawElements(gl.TRIANGLES, tResult.triangleIndices.length, gl.UNSIGNED_SHORT, 0);

使用 Spector.js 扩展,我看到 drawElements 方法中的第二个参数(计数)在每次调用时都不同(tResult.triangleIndices.length 在我登录时 而不是 它)。这可能是个误会,因为它适用于 30-100 次渲染。

我在 bufferData() 和 drawElements() 中尝试了缓冲区类型的各种数据类型组合,但没有成功。

我试过使用较低的多边形网格。

我尝试在每个渲染过程中调用各种 gl.clear 方法。

这可能不相关,但 fwiw 它是一个 vue-cli 应用程序,所以它正在从 npm 加载库。

相关代码如下:

初始化:

                    [...setting up shaders and stuff]
                    // link the two shaders into a WebGL program
                    this.program = gl.createProgram();
                    gl.attachShader(this.program, vertexShader);
                    gl.attachShader(this.program, fragmentShader);
                    gl.linkProgram(this.program);

                    this.aPos = gl.getAttribLocation(this.program, 'a_pos');
                    gl.clearColor(1.0, 1.0, 1.0, 1.0);  // Clear to black, fully opaque

                    // create and initialize a WebGLBuffer to store vertex and color data
                    this.buffer = gl.createBuffer();
                    gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
                    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tResult.triangleLocations), gl.STATIC_DRAW);

                    this.verticesIndexBuffer = gl.createBuffer();
                    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.verticesIndexBuffer);
                    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(tResult.triangleIndices), gl.STATIC_DRAW); 
                    gl.clear(gl.COLOR_BUFFER_BIT);
                    gl.enable(gl.CULL_FACE);
                    gl.cullFace(gl.BACK);

渲染:

render: function (gl, matrix) {

                    gl.useProgram(this.program);
                    gl.uniformMatrix4fv(
                        gl.getUniformLocation(this.program, 'u_matrix'),
                        false,
                        matrix
                    );

                    gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
                    gl.enableVertexAttribArray(this.aPos);
                    gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
                    gl.drawElements(gl.TRIANGLES, tResult.triangleIndices.length, gl.UNSIGNED_SHORT, 0);
                    
                }

这个问题在我看来就像你在渲染时没有设置 ELEMENT_ARRAY_BUFFER

this webgl state diagram

如果您没有使用顶点数组(您没有),那么属性和缓冲区绑定是全局状态。因此,如果在您初始化事物和渲染事物(例如 mapbox 渲染它的东西)之间改变了状态,那么当您渲染时,您将使用与您在 init 中设置的不同的缓冲区。

尝试添加

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.verticesIndexBuffer);

调用前drawElements

类似地,如果在相同的 webgl 上下文中发生任何其他事情,您设置的其他状态(如面部剔除)可能会或可能不会持续到渲染时间。

如果不行你也可以试试webgl-lint for slightly informative error. Especially if you label your buffers