greggman / twgl.js

A Tiny WebGL helper Library
http://twgljs.org
MIT License
2.61k stars 258 forks source link

Always call vertexAttribDivisor #208

Closed dominicprior closed 1 year ago

dominicprior commented 1 year ago

Previously, if the divisor property was absent, the gl.vertexAttribDivisor call would be omitted, which caused the divisor value to be inherited from the previous program.

With this change, an absent divisor causes an explicit call to gl.vertexAttribDivisor with parameter zero.

Note this is a breaking change if people have been deliberately or accidentally carrying divisor values forward from one program to the next.

dominicprior commented 1 year ago

In this program, the second call to drawBufferInfo was failing due to the divisor value of 1 being inherited from the previous vertex attribute, which confused me for a while.

As mentioned in the commit, this is a breaking change, and, also, I have to admit there is a simple workaround, which is to add divisor: 0 (as shown near the end of the program). Finally, somewhat embarrassingly, I haven't been able to test this thoroughly, so I am just offering this pull request in case it is useful.

Either way, thank you for creating such a beautiful library. It is a work of art!

gl = document.querySelector('canvas').getContext('webgl2')
gl.clearColor(0,0,0.4, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
//------
vs = `#version 300 es
in float r;
in vec2 c;
void main() {
  gl_Position = vec4(r * c, 0, 1);
}`;
fs = `#version 300 es
precision mediump float;
out vec4 finalCol;
void main() {
    finalCol = vec4(0,1,1, 1);
}`;
p = twgl.createProgramInfo(gl, [vs, fs])
gl.useProgram(p.program)
arrays = {
  r:  { size: 1, data: [ 0.5 ], divisor: 1 },
  c:  { size: 2, data: [ -1,-1, 1,-1, 1,1, ] }
}
b = twgl.createBufferInfoFromArrays(gl, arrays)
twgl.setBuffersAndAttributes(gl, p, b)
twgl.drawBufferInfo(gl, b, gl.TRIANGLES, 3, 0, 1)
//------
vs = `#version 300 es
in vec2 pos;
void main() {
  gl_Position = vec4(pos, 0, 1);
}`
fs = `#version 300 es
precision mediump float;
out vec4 finalCol;
void main() {
  finalCol = vec4(1, 0.5, 0.5, 1);
}`
p = twgl.createProgramInfo(gl, [vs, fs])
gl.useProgram(p.program)
arrays = {
  pos: { size: 2, data: [ 0, 0, 0, -1, -1, 0 ],
    // divisor: 0
  }
}
b = twgl.createBufferInfoFromArrays(gl, arrays)
twgl.setBuffersAndAttributes(gl, p, b)
twgl.drawBufferInfo(gl, b)
greggman commented 1 year ago

This has been a problem forever 😢

Unfortunately the PR will break on WebGL1 if the user's device/browser doesn't have ANGLE_instanced_arrays (unlikely) and if they haven't called twgl.addExtensionsToContext (likely)

I guess you could check if gl.vertexAttribDivisor exists and add a comment that for the divisor to work at all you either have to be on WebGL2 or you have to have called twgl.addExtensionsToContext and checked for ANGLE_instanced_arrays

dominicprior commented 1 year ago

Thanks for the feedback. It's more complicated than I realized! I am happy to close this PR.

BTW, your https://webgl2fundamentals.org/webgl/lessons/resources/webgl-state-diagram.html was a life-saver for figuring out what was going on!

dominicprior commented 1 year ago

On second thoughts, I will see if I can improve this PR. I like the idea of checking for gl.vertexAttribDivisor etc.

dominicprior commented 1 year ago

I've added a commit that checks that gl.vertexAttribDivisor exists and also a comment about needing WebGL2 or ANGLE_instanced_arrays. Is that what you had in mind?

greggman commented 1 year ago

Yea, that works. Thanks!