Вам не нужно делать это в таком порядке.
Простейший пример:
'use strict';
const vs = `#version 300 es
void main() {
gl_PointSize = 128.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision mediump float;
uniform Color {
vec4 u_color;
};
out vec4 outColor;
void main() {
outColor = u_color;
}
`;
const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) alert('need webgl2');
const program = twgl.createProgram(gl, [vs, fs]);
const color = new Float32Array([1, 0.5, 0.7, 1]);
const buffer = gl.createBuffer();
// there's only 1 so I believe it's safe to guess index 0
const uniformBlockIndex = 0;
const uniformBlockBinding = 0;
gl.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
// at render time
gl.useProgram(program);
// for each block
{
const uniformBlockBufferOffset = 0;
const uniformBlockBufferOffsetByteLength = 16; // 4 floats
gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding, buffer, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);
// set the data
gl.bufferData(gl.UNIFORM_BUFFER, color, gl.DYNAMIC_DRAW);
}
gl.drawArrays(gl.POINTS, 0, 1);
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Если вы хотите увидеть сложный пример, вы можете просмотреть в этом примере . Он запрашивает все данные о единообразных буферах при создании программы. Сколько их, как их зовут, какую форму они используют, какие типы этих форм. Это происходит, когда вы звоните twgl.createProgramInfo
, который вы можете заглянуть внутрь и увидеть, что информация создается в createUniformBlockSpecFromProgram
Затем, используя спецификацию блока, вы можете создать типизированный массив с предварительно подготовленными представлениями в этом массиве для всех униформ, вызвав twgl.createUniformBlockInfo
const ubi = twgl.createUniformBlockInfo(...)
Вы можете установить единообразные значения в типизированном массиве через представления напрямую, используя
ubi.uniforms.nameOfUniform.set(newValue)
но это было бы хрупко, так как блоки могут быть оптимизированы во время отладки, поэтому вы можете использовать менее хрупкие
twgl.setBlockUniforms(ubi, {nameOfUniform: newValue});
Когда вы действительно хотите, чтобы данные в набранном массиве загружались в графический процессор, который вы называете
twgl.setUniformBlock(...);
Который связывает унифицированный блок с назначенной привязкой И загружает данные в графический процессор.
Если вы просто хотите связать существующий блок (нет необходимости загружать новые данные), тогда
twgl.bindUniformBlock(gl, programInfo, ubi);
Хотя образец такой, как вы видите в примере
- bindBufferRange
- bufferData
bindBufferRange уже связывает буфер, поэтому мы можем просто использовать эту привязку для загрузки данных.
Тест (без twgl)
'use strict';
const vs = `#version 300 es
void main() {
gl_PointSize = 128.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision mediump float;
uniform Color1 {
vec4 u_color1;
};
uniform Color2 {
vec4 u_color2;
};
out vec4 outColor;
void main() {
outColor = u_color1 + u_color2;
}
`;
const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) alert('need webgl2');
const program = twgl.createProgram(gl, [vs, fs]);
const color1 = new Float32Array([1, 0, 0, 1]);
const buffer1 = gl.createBuffer();
const color2 = new Float32Array([0, 0, 1, 1]);
const buffer2 = gl.createBuffer();
// there's only 2 and they are the same format so we don't really
// care which is which to see the results.
const uniformBlockIndex = 0;
const uniformBlockBinding = 0;
gl.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
gl.uniformBlockBinding(program, uniformBlockIndex + 1, uniformBlockBinding + 1);
// at render time
gl.useProgram(program);
{
const uniformBlockBufferOffset = 0;
const uniformBlockBufferOffsetByteLength = 16; // 4 floats
gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding, buffer1, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);
// set the data
gl.bufferData(gl.UNIFORM_BUFFER, color1, gl.DYNAMIC_DRAW);
gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding + 1, buffer2, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);
// set the data
gl.bufferData(gl.UNIFORM_BUFFER, color2, gl.DYNAMIC_DRAW);
}
gl.drawArrays(gl.POINTS, 0, 1);
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
В приведенном выше примере показано, что bindBufferRange
делает 2 вещи.
- связывает буфер с
UNIFORM_BUFFER
точкой привязки
- связывает часть буфера с единым индексом буфера.
Мы знаем, что это сработало, потому что результат фиолетовый. Если бы он не работал, он был бы красным или синим
Из раздела 2.10.1.1 спецификации OpenGL ES 3.0 относительно bindBufferRange
Каждая цель представляет индексированный массив точек привязки буферного объекта,
в качестве единой общей точки привязки, которая может использоваться другими функциями манипулирования буферными объектами