greggman / twgl.js

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

specifying vector length with setUniforms #172

Closed orazdow closed 3 years ago

orazdow commented 3 years ago

In the documentation here It shows that the call to set the uniform's type is inferred by the array length. What if I wanted to pass an array of 4 vec2s to a fragment shader? It seems that twgl would interpret the array as having 2 vec4 elements. Is specifying numComponents allowed in a uniform object, ot is there some other way to do this?

greggman commented 3 years ago

It is not inferred by the array length. The types are looked up from the uniform types when the program is compiled. It will work just fine

Example:

https://jsgist.org/?src=b6f1cf93b7feb74ab268331f28215ff0

orazdow commented 3 years ago

I must have assumed the length idea from somewhere else in the docs. I guess my real question is: if I have an array of 12 floats for example, I could declare it as a uniform array of 3 vec4s or 6 vec2s in the shader. I assume it will work both ways, but does it matter what the underlying gl.uniform...fv function is called? I had the impression that there is flexibility if the input data is an array of permissible size than declaring as different vector lengths could still work even if the gl uniform call doesn't match.

In the program I'm testing, I have a float array of length sixteen, and declares the uniform as 8 vec2s which works. So when you say the types are looked up when the program is compiled, does that referer to the the webgl api, or is that something twgl is doing. If you could point me to that part of the source I'd be interested to see. Sorry for the long question, I'm just trying to get an understanding these cases with uniforms and how they work in webg and using twgl.

greggman commented 3 years ago

twgl and webgl both take arrays of input so [1, 2, 3, 4, 5, 6] will work as input to float[6], vec2[3] and vec3[2] uniforms. That the same in OpenGL as well. All you give those functions gl.uniform1fv, gl.uniform2fv, and gl.uniform3fv is a flat array of values.

On the other hand WebGL is strict about which function you use. You can't use gl.uniform3fv(locationOfArrayOf3Vec2s, arrayOf6Float) It will complain that you're trying to use a function for vec3s on a uniform of vec2s.

As for the code it's "open source" 😉 and not that long. I think if you looked at this list of files

https://github.com/greggman/twgl.js/tree/master/src

You'd figure out it's in this file

https://github.com/greggman/twgl.js/blob/master/src/programs.js

You could search for uniform2f and you'd find this

https://github.com/greggman/twgl.js/blob/6cb3d8f57a3fc9f2ca87aaa3b142f23ad33202b2/src/programs.js#L146

Which would get you to search for floatVec2Setter leading you here

https://github.com/greggman/twgl.js/blob/6cb3d8f57a3fc9f2ca87aaa3b142f23ad33202b2/src/programs.js#L332

and maybe eventually you'd arrive at this function

https://github.com/greggman/twgl.js/blob/master/src/programs.js#L881

orazdow commented 3 years ago

Ah, that clears it up. What I missed looking earlier was getActiveUniform() which I wasn't aware of. I didn't know you could query the shader program about it's uniforms.

Knowing the uniform function can't mismatch the shaders uniform type is important. Thinking the shader program might have leeway to 'interpret' input might have come from not realizing the shader can actually be queried, rather than being functional in one direction. Since it's compiled before the setting the uniforms, nothing is inferred and it can be determined from the shader. Thanks pointing that out.