«GL_INVALID_OPERATION: недостаточный размер буфера». после переменного количества вызовов рендеринга

#javascript #3d #webgl #mapbox-gl-js #webgl2

#javascript #3D #webgl #mapbox-gl-js #webgl2

Вопрос:

Я использую MapboxGL для рендеринга geojson в виде полигона на карте. Страница загружается и отображается правильно, но когда я перемещаю карту, я получаю эту ошибку после некоторого числа (обычно между ~ 30-100) вызовов рендеринга, и полигон исчезает.

В Chrome:

 GL_INVALID_OPERATION: Insufficient buffer size. (Chrome)
  

В Firefox:

 WebGL warning: drawElementsInstanced: Index buffer too small. (FF)
  

Мне удалось (я думаю) сузить его до проблемы с:

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

Используя Spector.js расширение Я видел, что второй аргумент (count) в методе drawElements изменяется при каждом вызове (TResult.triangleIndices.длина не меняется, когда я ее регистрирую). Это может быть отвлекающим маневром, потому что он работает для 30-100 рендеров.

Я пробовал различные комбинации типов данных для типа буфера в BufferData() и drawElements(), но безуспешно.

Я пробовал использовать сетки с более низкой поляризацией.

Я пробовал вызывать различные методы gl.clear для каждого прохода рендеринга.

Это, вероятно, не имеет значения, но, черт возьми, это приложение 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);                   
}
  

Ответ №1:

Мне кажется, что проблема заключается в том, что вы не устанавливаете ELEMENT_ARRAY_BUFFER при рендеринге.

Смотрите эту диаграмму состояния webgl

если вы не используете массивы вершин (чего вы не делаете), тогда атрибуты и привязки буфера являются глобальным состоянием. Итак, если что-то изменяет это состояние между временем инициализации объектов и временем рендеринга объектов (например, рендеринг mapbox), то при рендеринге вы будете использовать другие буферы, чем вы настроили в init.

Попробуйте добавить

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

Перед вызовом drawElements

Аналогично, другое состояние, которое вы настраиваете, например, отбраковка лиц, может длиться или не длиться до времени рендеринга, если что-то еще происходит в том же контексте webgl.

Если это не так, вы могли бы попробовать также webgl-lint для получения незначительной информативной ошибки. Особенно, если вы помечаете свои буферы

Комментарии:

1. Спасибо, это помогло! Мне явно нужно многому научиться, потому что я не понимаю, почему это будет работать для первого x числа рендерингов, а затем останавливаться. Я посмотрю на ссылки, которые вы включили. Спасибо!

2. Спасибо, у меня было много времени, чтобы определить причину этого.