Following a tutorial on importing animations using ASSIMP I’ve come across a problem in that the developers code was intended for a mesh where every vertex was affected by no more than 4 bones, which he thusly passed as two vec4’s in the layout section.
Here is presumably his code:
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[BONE_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Bones[0]) * Bones.size(), &Bones[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(BONE_ID_LOCATION);
glVertexAttribIPointer(BONE_ID_LOCATION, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
glEnableVertexAttribArray(BONE_WEIGHT_LOCATION);
glVertexAttribPointer(BONE_WEIGHT_LOCATION, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)16);
VertexBoneData is a struct:
struct VertexBoneData
{
uint IDs[NUM_BONES_PER_VEREX];
float Weights[NUM_BONES_PER_VEREX]; }
and Bones is a vector of VertexBoneData, his shader looks like:
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in ivec4 BoneIDs;
layout (location = 4) in vec4 Weights;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
const int MAX_BONES = 100;
uniform mat4 gWVP;
uniform mat4 gWorld;
uniform mat4 gBones[MAX_BONES];
void main()
{
mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
BoneTransform += gBones[BoneIDs[1]] * Weights[1];
BoneTransform += gBones[BoneIDs[2]] * Weights[2];
BoneTransform += gBones[BoneIDs[3]] * Weights[3];
vec4 PosL = BoneTransform * vec4(Position, 1.0);
gl_Position = gWVP * PosL;
TexCoord0 = TexCoord;
vec4 NormalL = BoneTransform * vec4(Normal, 0.0);
Normal0 = (gWorld * NormalL).xyz;
WorldPos0 = (gWorld * PosL).xyz;
}
I believe my mesh ends up with 6 bones but I had 12 as the max size to be safe.
My idea to get around this is to pass two matrices and have the shader look like this:
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in mat4 BoneIDs;
layout (location = 4) in mat4 Weights;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
const int MAX_BONES = 100;
uniform mat4 gWVP;
uniform mat4 gWorld;
uniform mat4 gBones[MAX_BONES];
void main()
{
ivec4 BoneIDvec1 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
ivec4 BoneIDvec2 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
ivec4 BoneIDvec3 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
ivec4 BoneIDvec4 = ivec4(BoneIDs[0][0], BoneIDs[0][1], BoneIDs[0][2], BoneIDs[0][3]);
mat4 BoneTransform = gBones[BoneIDvec1[0]] * Weights[0][0];
BoneTransform += gBones[BoneIDvec1[1]] * Weights[0][1];
BoneTransform += gBones[BoneIDvec1[2]] * Weights[0][2];
BoneTransform += gBones[BoneIDvec1[3]] * Weights[0][3];
BoneTransform += gBones[BoneIDvec2[0]] * Weights[1][0];
BoneTransform += gBones[BoneIDvec2[1]] * Weights[1][1];
BoneTransform += gBones[BoneIDvec2[2]] * Weights[1][2];
BoneTransform += gBones[BoneIDvec2[3]] * Weights[1][3];
BoneTransform += gBones[BoneIDvec3[0]] * Weights[2][0];
BoneTransform += gBones[BoneIDvec3[1]] * Weights[2][1];
BoneTransform += gBones[BoneIDvec3[2]] * Weights[2][2];
BoneTransform += gBones[BoneIDvec3[3]] * Weights[2][3];
vec4 PosL = BoneTransform * vec4(Position, 1.0);
gl_Position = gWVP * PosL;
TexCoord0 = TexCoord;
vec4 NormalL = BoneTransform * vec4(Normal, 0.0);
Normal0 = (gWorld * NormalL).xyz;
WorldPos0 = (gWorld * PosL).xyz;
}
Would this work in theory? It seems like a lot of work, as I would need I think, to enter in all of his vertex data into two 4v4 matrices, and even then that’s a maximum of 16 slots.
Thoughts?