Wednesday, July 27, 2016

opengl - Access vertex data stored in VBO in the shader


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.



Answer



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.)


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...