Рисование множества фигур в WebGL

Я читал учебники изВот.

<script class = "WebGL">
var gl;
function initGL() {
  // Get A WebGL context
  var canvas = document.getElementById("canvas");
  gl = getWebGLContext(canvas);
  if (!gl) {
    return;
  }
}
var positionLocation;
var resolutionLocation;
var colorLocation;
var translationLocation;
var rotationLocation;
var translation = [50,50];
var rotation = [0, 1];
var angle = 0;
function initShaders() {
  // setup GLSL program
  vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
  fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
  program = createProgram(gl, [vertexShader, fragmentShader]);
  gl.useProgram(program);

  // look up where the vertex data needs to go.
  positionLocation = gl.getAttribLocation(program, "a_position");

  // lookup uniforms
  resolutionLocation = gl.getUniformLocation(program, "u_resolution");
  colorLocation = gl.getUniformLocation(program, "u_color");
  translationLocation = gl.getUniformLocation(program, "u_translation");
    rotationLocation = gl.getUniformLocation(program, "u_rotation");

  // set the resolution
  gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
}
function initBuffers() {
  // Create a buffer.
  var buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.enableVertexAttribArray(positionLocation);
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

  // Set Geometry.
  setGeometry(gl);
}

function setColor(red, green, blue) {
    gl.uniform4f(colorLocation, red, green, blue, 1);
}
// Draw the scene.
function drawScene() {
    // Clear the canvas.
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Set the translation.
    gl.uniform2fv(translationLocation, translation);
    // Set the rotation.
    gl.uniform2fv(rotationLocation, rotation);

    // Draw the geometry.
    gl.drawArrays(gl.TRIANGLES, 0, 6);
}


// Fill the buffer with the values that define a letter 'F'.
function setGeometry(gl) {
/*Assume size1 is declared*/
    var vertices = [
         -size1/2, -size1/2,
         -size1/2, size1/2,
         size1/2, size1/2,
         size1/2, size1/2,
         size1/2, -size1/2,
         -size1/2, -size1/2 ];
      gl.bufferData(
         gl.ARRAY_BUFFER,
         new Float32Array(vertices),
         gl.STATIC_DRAW);
}
function animate() {
    translation[0] += 0.01;
    translation[1] += 0.01;
    angle += 0.01;
    rotation[0] = Math.cos(angle);
    rotation[1] = Math.sin(angle);
}
function tick() {
    requestAnimFrame(tick);
    drawScene();
    animate();
}
function start() {

    initGL();
    initShaders();
    initBuffers();
    setColor(0.2, 0.5, 0.5);
    tick();
}

</script>

<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;

    uniform vec2 u_resolution;
    uniform vec2 u_translation;
    uniform vec2 u_rotation;
    void main() {
        vec2 rotatedPosition = vec2(
        a_position.x * u_rotation.y + a_position.y * u_rotation.x,
        a_position.y * u_rotation.y - a_position.x * u_rotation.x);

       // Add in the translation.
       vec2 position = rotatedPosition + u_translation;

       // convert the position from pixels to 0.0 to 1.0
       vec2 zeroToOne = position / u_resolution;

       // convert from 0->1 to 0->2
       vec2 zeroToTwo = zeroToOne * 2.0;

       // convert from 0->2 to -1->+1 (clipspace)
       vec2 clipSpace = zeroToTwo - 1.0;

       gl_Position = vec4(clipSpace, 0, 1);
    }
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
    precision mediump float;

    uniform vec4 u_color;

    void main() {
       gl_FragColor = u_color;
    }
</script>

Моя программа WebGL для 1 фигуры работает примерно так:

Получить контекст (gl) из элемента canvas.инициализировать буферы с формой моего объектаdrawScene() : вызовgl.drawArrays()Если есть анимация, функция обновления, которая обновляет углы, положение моей фигуры, а затемdrawScene() оба вtick(), так что он вызывается неоднократно.

Теперь, когда мне нужно более 1 фигуры, я должен заполнить один буфер сразу несколькими объектами, а затем использовать его для последующего вызоваdrawScene() рисовать все объекты одновременно[ИЛИ ЖЕ] я должен повторить вызовinitBuffer а такжеdrawScene() изrequestAnimFrame().

Ответы на вопрос(3)

гоgl.drawArrays() как вы и предполагали), обеспечивает более высокую производительность в сложных сценах, но очевидно, что в этот момент вы не сможете изменять форму шейдера (например, преобразования) на сетку.

Если вы хотите, чтобы сетки работали независимо, вам придется рендерить каждую из них по отдельности. Вы все еще можете хранить все сетки в одном буфере, чтобы избежатьgl.bindBuffer() звонки, но имхо, это не поможет так много, по крайней мере, не в простых сценах.

 Petr Broz23 окт. 2012 г., 19:45
На ваш вопрос к ответу Delta: вам не нужно заполнять буферы снова и снова. Вы просто инициализируете буфер для каждой фигуры (gl.createBuffer ->gl.bindBuffer ->gl.bufferData) один раз, а затем в цикле вы переключаетесь только между ними.
 Petr Broz24 окт. 2012 г., 21:59
Да, вы могли бы сделать это. Или, если вы хотите использовать один и тот же шейдер для всех фигур, достаточно просто использоватьbindBuffer иvertexAttribPointer методы.enableVertexAttribArray используется только для «настройки» текущей шейдерной программы.
 batman24 окт. 2012 г., 20:48
«выключатель» - это вызовbindBuffer , enableVertexAttribArray а такжеvertexAttribPointer каждый раз, когда я что-то рисую, верно? Таким образом, буфер для этого объекта формы достигнет вершины. Правильно?
 gman31 дек. 2013 г., 03:09
FYI,enableVertexAttribArray настраивает атрибуты и не зависит от шейдерной программы. Другими словами, он настраивает глобальное состояние, а не текущую шейдерную программу.

иначе они не смогут перемещаться и использовать эффекты шейдера независимо.

Но это в том случае, если ваши объекты разные. Из того, что я получил здесь, я думаю, вы просто хотите нарисоватьтакой же формировать более одного раза на разных позициях не так ли?

То, как вы делаете это, вы просто устанавливаете этоtranslationLocation сразу же с другой матрицей перевода после рисования формы в первый раз. Таким образом, когда вы снова нарисуете фигуру, она будет расположена где-то еще, а не поверх другой, чтобы вы могли ее видеть. Вы можете установить все эти матрицы преобразования по-разному, а затем просто вызватьgl.drawElements снова, так как вы собираетесь рисовать те же буферы, которые уже используются.

 batman23 окт. 2012 г., 13:27
Нет, я хочу нарисовать много разных фигур в разных местах.
 batman23 окт. 2012 г., 13:29
Итак, теперь, если это так, я должен [заполнить буферы, gl.drawArray, заполнить буферы, gl.drawArray, заполнить буферы, gl.drawArray ....] для каждого объекта?
Решение Вопроса

Во время инициации

Получить контекст (gl) из элемента canvas.для каждого шейдерасоздать шейдерискать атрибуты и унифицированные локациидля каждой фигурыинициализировать буферы с формойдля каждой текстурысоздавать текстуры и / или заполнять их данными.

Во время розыгрыша

для каждой фигурыесли последний использованный шейдер отличается от шейдера, необходимого для вызова формыgl.useProgramДля каждого атрибута необходим шейдервызовgl.enableVertexAttribArray, gl.bindBuffer а такжеgl.vertexAttribPointer для каждого атрибута, необходимого для формы, с расположением атрибутов для текущего шейдера.Для каждой формы необходим шейдервызовgl.uniformXXX с желаемыми значениями, используя местоположения для текущего шейдеравызовgl.drawArrays или если данные проиндексированы, называетсяgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferOfIndicesForCurrentShape) с последующимgl.drawElements

Общие оптимизации

1) Часто вам не нужно устанавливать каждую форму. Например, если вы рисуете 10 фигур стакой же шейдер и этот шейдер использует viewMatrix или cameraMatrix, вероятно, что форма viewMatrix или cameraMatrix одинакова для каждой фигуры, поэтому просто установите ее один раз.

2) Вы можете часто перемещать звонки наgl.enableVertexAttribArray время инициализации.

Ваш ответ на вопрос