4
\$\begingroup\$

If I wanted to store extra data in a VBO for skinning (indices for indexing into an array of matrices of bones and floats for applying weights to those bones) How would I go about accessing that data in GLSL? I already know how to put the data in the buffer, interleaved with the rest of the data.

For example I want each vertex for a model to contain:

Vec3 position;
Vec3 normal;
Vec4 color;
Vec2 texCoords;
int boneCount;
int[3] boneIndex;
float[3] boneWeight;

Then drawing like:

bind(vertexBufferID);
glVertexPointer(3, GL11.GL_FLOAT, stridePlus, 0 * 4);
glNormalPointer(GL11.GL_FLOAT, stridePlus, 3 * 4);
glColorPointer(4, GL11.GL_FLOAT, stridePlus, (3 + 3) * 4);
glTexCoordPointer(2, GL11.GL_FLOAT, stridePlus, (3 + 3 + 4) * 4);
glVertexPointer(7, GL11.GL_FLOAT, stridePlus, (3 + 3 + 4 + 2) * 4);
glDrawArrays(GL11.GL_TRIANGLES, 0, VPNCTEnd);

Then in my vertex shader I want:

 //Get indices of bones
 //Get weights of bones
 //Get bone transforms
 //for each bone transform, apply it to gl_Position at the specified weight

What is the GLSL required for the last part of the process? It seems like I need to set a attribute pointer to the data somehow, but I'm not sure where to do that when the data is stored in the VBO.

\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

First of all, you probably want to use glVertexAttribPointer on the application side to specify all the components, including the bone stuff, rather than the deprecated glVertexPointer and friends. Something like:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0 * 4);  // Position
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, 3 * 4);  // Normals
// etc.
glVertexAttribPointer(4, 3, GL_INT, GL_FALSE, stride, (3 + 3 + 4 + 2) * 4);  // Bone indices
glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, stride, (3 + 3 + 4 + 2 + 3) * 4);  // Bone weights

You don't need a separate attribute for the bone count, since you can just zero the weights of unused slots (and set the index to 0 or something). The first argument to glVertexAttribPointer is the attribute index, and each attribute can store up to 4 values.

You'll also need to use glEnableVertexAttribArray to tell OpenGL which attributes you're using.

In the GLSL shader, you then access these by declaring them as attribute variables, like:

attribute vec3 Position;
attribute vec3 Normal;
// etc.
attribute vec3 BoneIndices;
attribute vec3 BoneWeights;

Finally, you can control which variables are mapped to which attribute by using glBindAttribLocation. You'd insert a bunch of these calls before linking the shader, which will tell OpenGL the desired correspondence between the variables and the attribute indices used in the glVertexAttribPointer calls. (There are also other ways to set up this mapping; a more in-depth discussion is at this StackOverflow question.)

\$\endgroup\$
3
  • \$\begingroup\$ Yeah, whenever I post any of my OpenGL code I hear how outdated it is :) When it comes to the graphics I usually just go with the first thing that works. I'll try out the more up-to-date calls :) I guess I might as well allow 4 bones for each vertex since I can stuff 4 values in the attribute anyway. \$\endgroup\$
    – House
    Aug 18, 2012 at 0:36
  • \$\begingroup\$ I see your shader code is Cg code? Do you know how to access the attributes in GLSL code instead of Cg? \$\endgroup\$
    – House
    Aug 18, 2012 at 3:45
  • \$\begingroup\$ @Byte56 Oops. You're right. Fixed! \$\endgroup\$ Aug 18, 2012 at 3:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .