Help: Telling one mesh from another in the vertex shader

Started by
6 comments, last by Brother Bob 11 years, 4 months ago
Sorry if this is vague, but I don't really know what I'm looking for to solve this, and I don't really know what to ask. I have a couple different meshes that I am rendering with different vbos. What I want is to give each mesh a position vector (and possibly more info later on, such as a skeleton animation) that it will use to calculate the new position of the mesh in the vertex shader. Right now I am giving each vertex an attribute called meshID which then gets the mesh's position vector from a uniform vec3 array. I feel like there must be a better way of telling each mesh apart or even assigning attributes to each mesh, but I don't know what it would be.
Advertisement
The normal way of doing this would be to get rid of your meshID vertex attribute and use a single vec3 for the position vector (often a world matrix would be used instead of a position vector). Your vertex shader would never need to know which mesh it is rendering, you'd simply upload a different value into your position vec3 before you render each mesh.

The only reason I can think of for using a meshID which looks up into an array of position uniforms would be if you were trying to achieve instance rendering. The goal of instance rendering is to draw multiple meshes with a single draw call to improve performance. It sounds like you're not trying to do this, but you're maybe basing your code on a sample that did do instance rendering.
Well I was also hoping to add more then just the position vector and also give it information about the mesh's skeleton. Where if I have 200 vertices per mesh and only 10 bones per mesh it would be a waist of memory to repeat the bones for each vertex. I'm trying to minimize the about of information I have to update and store on the graphics card.

I did got the idea from instance rendering.
For skinning, yes, the approach of having a vertex attribute for the bone index is pretty standard. For smooth skinning, most implementations allow for a vertex to be associated with up to 4 bones, so there's often up to four integers which are indices into your bone matrix uniforms and four floats which are the weights for each of those bones.

In DirectX you can squeeze the 4 bone indices into four bytes (assuming your bone count is <= 255). I would be surprised if that's not also possible in OpenGL.

In some cases it can be worth having different versions of your vertex shader for different numbers of weighting, so that you use a simpler shader in the event that each vertex is associated with fewer than 4 bones.
I understand that, but what I'm confused about is how you tell each skeleton apart, what I have is

[font=courier new,courier,monospace]uniform mat4 skeleton[][];
uniform vec4 worldpos[];[/font]
[font=courier new,courier,monospace]in int joint;[/font]
[font=courier new,courier,monospace]void main(void)[/font]
[font=courier new,courier,monospace]{
mat4 mjoint = skeleton[meshID][joint];
vec4 new_vertex = gl_vertex + worldpos[meshID];
....
}[/font]

but I don't know where to get the meshID from to tell the skeletons and worldpos apart, should it just be a vector attribute, or am I doing this wrong?
Ordinarily, I'd expect you to just upload a whole new array of bones and have a separate draw call for each mesh.

Your vertex shader would only need to know a mesh ID if you're specifically trying to implement instanced rendering for hardware skinned objects, which is a perfectly viable thing to try and achieve, but is a bit exotic and perhaps not a 'for beginners' topic. In DirectX I suppose you could use SetStreamSourceFreq to get per vertex data into your vertex shader without having to duplicate it into each and every vertex, In OpenGL you might be looking at using something like http://www.opengl.org/registry/specs/ARB/instanced_arrays.txt or http://www.opengl.org/registry/specs/ARB/draw_instanced.txt, availability of these will depend on your OpenGL version and implementation. The simpler approach would be to just create multiple copies of your mesh in your vertex buffer, incrementing the per-vertex mesh ID for each one.
Okay, I think I realized what my problem was. I didn't realize that you could change uniforms between draw calls, I thought everything was drawn once glFlush was called or something like that, so I thought it would be pointless to change the uniform. But if I understand right I can do something like this...

[font=courier new,courier,monospace]glBindBuffer(GL_ARRAY_BUFFER, vbo_1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_1);
glUniform1fv(uniform_ skeleton, 10, skeleton_1);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

glBindBuffer(GL_ARRAY_BUFFER, vbo_2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_2);
glUniform1fv(uniform_ skeleton, 10, skeleton_2);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

glutSwapBuffers();[/font]

...If that is true then everything just made a whole lot more sense.
Yes, that works just fine.

In case it was the command buffering that threw you off and things were only drawn once the command buffer was flushed, then that is a different story and I can understand your concern. Commands may be buffered as much as the driver likes, but the observed behavior must be as if everything was drawn immediately though.

This topic is closed to new replies.

Advertisement