PDA

View Full Version : Updating the model-matrices when drawing multiple objects



Aliii
04-11-2016, 05:56 AM
Speaking of OpenGL 3.3, let's say I want to draw multiple objects. They have different geometry so I can't use instanced rendering. Before each draw call I need to update the model-matrix uniform of the object.

-where should I calculate the model-view-projection matrices? I mean the M * VP multiplication. On CPU side or in the shader? On the CPU side I need to do it once per object while in the shader once per every vertex but the GPU is supposed to be fast.
-how should I update the uniforms of these matrices? just normally update them with glUniform before each draw call, or put them in an UBO that I update once per frame and then change its offset with glBindBufferRange before each draw call?
As far as I know there is no way to send some sort of "index" into the shader with the draw call that I could use to index an UBO or something like that.
Thanks!

GClements
04-11-2016, 11:17 PM
Speaking of OpenGL 3.3, let's say I want to draw multiple objects. They have different geometry so I can't use instanced rendering. Before each draw call I need to update the model-matrix uniform of the object.

If you want to coalesce objects into fewer draw calls, you could use a uniform array of matrices and add a one-byte vertex attribute to hold the index.



-where should I calculate the model-view-projection matrices? I mean the M * VP multiplication. On CPU side or in the shader? On the CPU side I need to do it once per object while in the shader once per every vertex but the GPU is supposed to be fast.

If you don't need eye coordinates in the vertex shader (e.g. for lighting), you should probably compose the matrices on the CPU and just upload the composed model-view-projection matrix as a uniform.

If you have separate matrices within the shader, it's more efficient to transform twice Vclip=Mp*(Mmv*Vobj) than to compose the matrices Vclip=(Mp*Mmv)*Vobj. If you have separate matrices, it's normally because you need both eye and clip coordinates: Veye=Mmv*Vobj, Vclip=Mp*Veye.



-how should I update the uniforms of these matrices? just normally update them with glUniform before each draw call, or put them in an UBO that I update once per frame and then change its offset with glBindBufferRange before each draw call?
As far as I know there is no way to send some sort of "index" into the shader with the draw call that I could use to index an UBO or something like that.

The index can be a uniform variable. That replaces the glBindBufferRange() per draw call with glUniform1ui() per draw call. The downside is that you need to index within the vertex shader, but I can't imagine that the difference would be significant.

Aliii
04-12-2016, 05:39 PM
If you want to coalesce objects into fewer draw calls, you could use a uniform array of matrices and add a one-byte vertex attribute to hold the index.
Thanks! I guess this is the least bad solution to index if there are already 20 or so bytes per vertex then 1 more is acceptable, except if I draw the same mesh twice.


If you have separate matrices within the shader, it's more efficient to transform twice Vclip=Mp*(Mmv*Vobj) than to compose the matrices Vclip=(Mp*Mmv)*Vobj. If you have separate matrices, it's normally because you need both eye and clip coordinates: Veye=Mmv*Vobj, Vclip=Mp*Veye.
Yes, I have both fog and directional lighting. I will let the shader do it for now.


The index can be a uniform variable. That replaces the glBindBufferRange() per draw call with glUniform1ui() per draw call. The downside is that you need to index within the vertex shader, but I can't imagine that the difference would be significant.
I have no idea which is faster, glBindBufferRange or setting an uniform. I think it doesn't matter if I set a 16 float matrix or an uint because the overhead of the glUniform call must be much more. I don't get why they didn't add something like this to the draw functions:S ...a simple index. It could have many uses.

GClements
04-12-2016, 11:45 PM
I have no idea which is faster, glBindBufferRange or setting an uniform. I think it doesn't matter if I set a 16 float matrix or an uint because the overhead of the glUniform call must be much more. I don't get why they didn't add something like this to the draw functions:S ...a simple index. It could have many uses.
It doesn't make much difference either way. It's not that changing a uniform is expensive by itself, it's that it requires splitting what might otherwise be a single draw call into multiple draw calls.

What could be useful in this situation is a predefined variable similar to gl_InstanceID but which holds the outermost index for glMultiDraw* calls. For glMultiDrawArrays(), it should be possible to emulate this (at a cost) by looking up gl_VertexID in a sorted list of offsets using a binary search. That won't work for glMultiDrawElements() as gl_VertexID is the value from the element array.

Aliii
04-13-2016, 06:52 AM
For glMultiDrawArrays(), it should be possible to emulate this (at a cost) by looking up gl_VertexID in a sorted list of offsets using a binary search. That won't work for glMultiDrawElements() as gl_VertexID is the value from the element array.

I tried something like that once but I used baseVertex calls and it turned out that many drivers don't work as the spec says and some add the base-vertex to gl_VertexID and some don't. So I couldn't make that work.

This is maybe a stupid idea but since in a normal environment most objects are static, so their model matrices don't change, I could store those in a large uniform buffer and add a 2 byte index as a vertex attribute. This could work fast provided the GPU has no problem with random-accessing a large uniform buffer.

elect
06-16-2016, 01:25 AM
I tried something like that once but I used baseVertex calls and it turned out that many drivers don't work as the spec says and some add the base-vertex to gl_VertexID and some don't. So I couldn't make that work.

This is maybe a stupid idea but since in a normal environment most objects are static, so their model matrices don't change, I could store those in a large uniform buffer and add a 2 byte index as a vertex attribute. This could work fast provided the GPU has no problem with random-accessing a large uniform buffer.


Which drivers?

Aliii
10-20-2016, 01:05 PM
Which drivers?

Oi!, sorry for this very late answer. I don't know which drivers specifically. My driver didn't give the right value. (Which was nvidia 340 or 304 on linux)
I did some research and saw that I'm not alone with this, so I gave up on that. One post here:
http://stackoverflow.com/questions/7453235/basevertex-and-gl-vertexid
"Unfortunately, some old drivers didn't implement it correctly."