RaenirSalazar

07-21-2014, 04:03 PM

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?

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?