1

I am trying to port some OpenGL code to WebGL2 and I have some problems with Uniform Buffers. Everything I render with the shader the buffer is attached to is no longer displayed. I get no errors or warnings in the console. This is my code:

var data = new Float32Array(1);
data[0] = 1.0;

var uniformBuffer = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferData(gl.UNIFORM_BUFFER, 4, gl.STATIC_DRAW);
gl.bindBufferRange(gl.UNIFORM_BUFFER, 0, uniformBuffer, 0, 4);

gl.uniformBlockBinding(mapShader.getProgram(), gl.getUniformBlockIndex(mapShader.getProgram(), "test"), 0);


gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, data);
gl.bindBuffer(gl.UNIFORM_BUFFER, null);

Once I add this to my shader the problems I described earlier appear:

layout (std140) uniform test {
    float testFloat;
};
user11914177
  • 885
  • 11
  • 33

1 Answers1

3

Next time please be kind and save us from having to manually make a repo! Thanks ‍♂️

When I run your code in Chrome I get

:GL_INVALID_OPERATION : glDrawArrays: uniform buffers : buffer or buffer range at index 0 not large enough

The problem is there are padding and alignment issues

See the spec section 2.12.6.4

Changing your buffer and range size to 16 and it works. Also note there are alignment requirements for valid offsets to BindBufferRange you can look up with gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT)

const gl = document.querySelector('canvas').getContext('webgl2');

const vs = `#version 300 es
void main() {
  gl_PointSize = 100.0;
  gl_Position = vec4(0, 0, 0, 1);
}
`;

const fs = `#version 300 es
precision highp float;

layout (std140) uniform test {
    float testFloat;
};

out vec4 outColor;

void main() {
  outColor = vec4(testFloat, 0, 0, 1);
}
`;

const prg = twgl.createProgram(gl, [vs, fs]);
gl.useProgram(prg);
const mapShader = {
  getProgram: _ => prg,
};

var data = new Float32Array(1);
data[0] = 1.0;

var uniformBuffer = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferData(gl.UNIFORM_BUFFER, 16, gl.STATIC_DRAW);
gl.bindBufferRange(gl.UNIFORM_BUFFER, 0, uniformBuffer, 0, 16);

gl.uniformBlockBinding(mapShader.getProgram(), gl.getUniformBlockIndex(mapShader.getProgram(), "test"), 0);


gl.bindBuffer(gl.UNIFORM_BUFFER, uniformBuffer);
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, data);
gl.bindBuffer(gl.UNIFORM_BUFFER, null);

gl.drawArrays(gl.POINTS, 0, 1);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

<canvas></canvas>
gman
  • 100,619
  • 31
  • 269
  • 393
  • Thanks that worked, I tested it a bit and every additional float adds 4 to the size right? – user11914177 Nov 01 '20 at 08:09
  • 3
    floats are padded to a vec4 so 1 float is 16bytes, 2 floats is 16 bytes, 4 is 16 bytes, 5 is 32bytes. etc... The rules are spelled out in the spec linked in the answer. – gman Nov 01 '20 at 12:46