Оптимизация
Обычно используют два метода для хранения данных в вершинах: массив структур и структура массивов. Массив структур хранит вершинные атрибуты в одном массиве. А структура массивов хранит каждый атрибут в отдельном буфере.
Возникает вопрос: какой способ более эффективен? В большинстве случаев это массив структур. Это объясняется тем, что данные могут читаться последовательно. Но у него есть недостаток, например, когда необходимо изменить определённые атрибуты.
В предыдущих статьях мы использовали структуру массивов. Поэтому сейчас рассмотрим, как изменится программа, если применить массив структур.
function initBuffers() { vertices_buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertices_buffer); var vertices = [ -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, -1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, -1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 0.0, 1.0, -1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 1.0, 0.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0, 1.0, -1.0, -1.0, -1.0, 0.0, 0.0, -1.0, -1.0, 1.0, 1.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 0.0, 1.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); index_buffer = gl.createBuffer(); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, index_buffer ); var indices = [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 ]; gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW ); }
Обратите внимание на то, как мы сгруппировали данные. Сначала идут три компоненты описывающие положение вершины, а затем идут две компоненты описывающие координаты текстуры. Так же мы избавились от трёх команд, так как мы объединили два массива в один.
function drawScene(delta) { gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); perspectiveMatrix = makePerspective(45, 600.0/400.0, 0.1, 100.0); loadIdentity(); mvPushMatrix(); mvTranslate([-0.0, 0.0, -6.0]); mvRotate(sqrRot, [1, 0, 0.6]); gl.bindBuffer(gl.ARRAY_BUFFER, vertices_buffer); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 20, 0); gl.enableVertexAttribArray(vertexPositionAttribute); gl.vertexAttribPointer(vertexCoordAttribute, 2, gl.FLOAT, false, 20, 12); gl.enableVertexAttribArray(vertexCoordAttribute); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, index_buffer ); setMatrixUniforms(); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(samplerUniform, 0); var vertices = 36; gl.drawElements( gl.TRIANGLES, vertices, gl.UNSIGNED_SHORT, 0 ); mvPopMatrix(); sqrRot -= delta * 40; }
Обратите внимание на то, как изменились параметры команд vertexAttribPointer(). Так как данные хранятся как тип float, то каждая компонента занимает 4 байта. Одну вершину описывает 5 компонент. Отсюда следует, что вершина описывается 20 байтами. Следующий параметр сообщает о смещении. Так как сначала описывается положение, то смещение равно 0. А для координат текстуры смещение будет равно 12, так как перед ними стоят 3 компоненты описывающие положение вершины.