PDA

View Full Version : Why use a Uniform Buffer?



Septimra
07-04-2015, 05:35 PM
I already have a mesh that sits on the GPU and is instanced.
I need the mesh skeleton to go the gpu as uniform data.

But..

Why use a uniform buffer if I could just put the mesh skeleton behind the mesh data in the same buffer, and line up the attributes accordingly?

GClements
07-04-2015, 06:06 PM
How were you planning on accessing that data?

I don't see anything in the specification that prohibits binding a single buffer to multiple targets, but it does say that the implementation may optimise storage based upon the first target to which a buffer is bound. In any case, I don't see the advantage to having both the attribute data and uniform values in the same buffer.

Septimra
07-04-2015, 07:10 PM
I am thinking it would be easier to just have one buffer to hold all my information for a model, the geometry and skeletal data.
Then I will use VertexAttribPointers to access them in the shader.

I wont be binding 1 buffer to multiple targets. I am going to have one buffer bound to GL_ARRAY_BUFFER and fill it with all the data of the model--geometry and skeletal.

I have read up on uniform arrays, it looks like the only reason to use them is if you are going to be using uniform blocks and if you want to access that buffer with different array programs? That's a question.. im not entirely sure what the deal is with uniform buffers


In any case, I don't see the advantage to having both the attribute data and uniform values in the same buffer.
Is there a down side?

Alfonse Reinheart
07-04-2015, 07:28 PM
What do you mean by "skeletal" data?

If you mean the list of transforms needed to display a skinned model, that is not something you can adequately access via vertex attributes (https://www.opengl.org/wiki/Vertex_Attribute). Under skinning, each vertex gets its matrix by a combination of transforms from several transforms. So your vertex shader will have to look something like this:



vec4 position = vec4(0.0);

for(int i = 0; i < N; ++i)
{
position += (Transform[i] * in_position) * in_weight[i];
}


`Transform` is an array of transformations. Every vertex could access any transformation in this array. But vertex attributes only change per-vertex or per-instance. So there's no real way you can provide each vertex with a palette of matrices.

So what information exactly are you trying to pass here?

Septimra
07-04-2015, 08:28 PM
Yes that is exactly what I am trying to pass, the transforms and weights.
I was thinking I could use glVertexAttribDivisor less than zero to get the data to stay for all the instances of the models.

I looked at the spec and its GLuint so I can't. Uniforms are for information for all instances, or per draw call. Since the skeleton is for all the instances and not per instance or vertex it needs to be in a uniform format. Thanks.

GClements
07-04-2015, 08:30 PM
Then I will use VertexAttribPointers to access them in the shader.

How?

The vertex shader doesn't get to decide what data to read from an attribute array. It gets invoked once for each vertex, with one element from each enabled attribute array stored in the corresponding attribute variable.



I have read up on uniform arrays, it looks like the only reason to use them is if you are going to be using uniform blocks and if you want to access that buffer with different array programs? [/B]That's a question.. im not entirely sure what the deal is with uniform buffers

It sounds like you're not entirely sure what the deal is with attributes versus uniforms.

An attribute is a variable which has different values for each vertex. If you had a C "struct" for each vertex, an attribute would be one of its fields.

A uniform variable is a variable whose value is constant (uniform) for the duration of a draw call, i.e. it has the same value for each vertex and fragment processed by the shaders.

Septimra
07-04-2015, 08:34 PM
Alright. I wanted to delete my other post but i was too late. I understand the vertex-fetching system. But glVertexAttribDivisor: could that be used if we make the second parameter the number of instances sent to glDrawArraysInstanced?

So create one skeletal data, send that to the GPU for all instances

eg.glDrawArraysInstanced(1, num_instnaces)

GClements
07-04-2015, 11:39 PM
I understand the vertex-fetching system. But glVertexAttribDivisor: could that be used if we make the second parameter the number of instances sent to glDrawArraysInstanced?

So create one skeletal data, send that to the GPU for all instances
You'd have one instance containing all of the vertices. The skeleton would be per-instance data.

But the main problem with that is that you probably can't fit a non-trivial skeleton into the maximum number of vertex attributes. At one point, even fitting a skeleton into uniforms was problematic, so you'd use a texture.

Alfonse Reinheart
07-05-2015, 05:25 AM
You'd have one instance containing all of the vertices. The skeleton would be per-instance data.

But the main problem with that is that you probably can't fit a non-trivial skeleton into the maximum number of vertex attributes. At one point, even fitting a skeleton into uniforms was problematic, so you'd use a texture.

To elaborate on this point a bit, most skeleton data for any humanoid figure contains lots of transforms. For example, a fully articulated hand requires no less than 15 bones (transformations) each.

The largest limit on the number of vertex attributes I have seen... is 32 vec4's. In terms of mat4x3's, that's less than 10, and that's ignores your vertex data. So doing things the way you want can't even give you a functioning hand, let alone a whole human figure.

Dark Photon
07-05-2015, 06:27 AM
Alright. I wanted to delete my other post but i was too late. I understand the vertex-fetching system. But glVertexAttribDivisor: could that be used if we make the second parameter the number of instances sent to glDrawArraysInstanced?

So create one skeletal data, send that to the GPU for all instances

Septimra, it would help motivate your question if you'd detail your requirements and how you plan (algorithmically) to implement skeletal animation on the GPU before we start debating whether GL widget A versus widget B is better (or even possible) for your algorithm.

You keep talking about "skeleton data". Some "skeleton data" is defined on the mesh and some is defined elsewhere. What skeleton data are you talking about? Just the joint final transforms for a single animation track? Or something else? Again, back to your algorithm.

Answers to these questions will help make your original question concrete and allow folks to offer more specific advice:

* How many skeletal meshes do you have?
* How many joint skeletons are these meshes rigged to?
* How many animation tracks can be played on each skeleton?
* Are your meshes rigged for simple skinning or more conventional smooth skinning?
* If the latter, how many joint influences do your mesh vertices have?
* Do you want to support animation blending or IK?
* Do you want to support keyframe interpolation?
* Do you want to compute per-frame poses on the GPU or CPU?

Septimra
07-05-2015, 05:23 PM
I understand what I did wrong now. But your questions got me thinking.

1) around 30
2) 30
3) maybe 7-10
4) smooth skinning
5) around 3
6) yes I will support IK, but latter and most likely on the CPU side as i dont want to do it per vertex or worse--per fragment
7) Yes keyframe interpolation again on the CPU
8) compute on the CPU, aka IK and interpolation--skin on the GPU

But like I said before I understand my mishap.. it now looks pretty silly that i didnt see it. But I'm on the right path for this render system?

Dark Photon
07-06-2015, 06:52 PM
Ok, good. Yeah, you can use whatever kind of uniform storage you want to pass this into the shader (textures, simple uniforms, buffers, etc.) Since you'll be changing it potentially every frame for every character (with your CPU pose calc appoach), you should prefer a type of uniform which performs well on your GPUs with frequent updates.

Also, for the simple keyframe interp scenario, you might put your post transform interp on the GPU, computed in vertex shaders. That can be quite a bit faster than doing it on the CPU, and greatly reduces the amount of uniform data that needs to stream to the GPU per frame per skeletal instance.