I'm having troubles with properly animating a skin mesh from an .fbx file. I feel like the issue is in the shader, but not sure what is going on. All I know is that I am getting unexpected results where it feels like I'm providing all of the proper information.
If i use a single bone for all positions instead of the ones that are passed in the layout location, it puts the vertices in the right spot, so the calculations are correct.
From the looks of everything, my bone calculations are correct, bone ids are loaded, and weights are loaded fine, but it seems like they don't keep their values.
What it seems like is happening: BoneIDS and/or BoneWeights are being zeroed or set to something else.
For reference:
typedef struct sFloat4
{
float x, y, z, w;
} sFloat4;
typedef struct sInt4
{
int x, y, z, w;
} sInt4;
typedef struct sVertex_p4t4n4b4i4
{
sFloat4 Pos;
sFloat4 TexUVx2;
sFloat4 Normal;
sInt4 BoneIDs;
sFloat4 BoneWeights;
} sVertex_p4t4n4b4i4;
and
unsigned int totalVertBufferSizeBYTES = numIndicesInIndexArray * sizeof ( sVertex_p4t4n4b4i4 ); ;
glBufferData ( GL_ARRAY_BUFFER, totalVertBufferSizeBYTES, pTempVertArray, GL_STATIC_DRAW );
CheckGLError();
unsigned int bytesInOneVertex = sizeof( sVertex_p4t4n4b4i4 );
unsigned int byteOffsetToPosition = offsetof( sVertex_p4t4n4b4i4, Pos );
unsigned int byteOffsetToUVCoords = offsetof( sVertex_p4t4n4b4i4, TexUVx2 );
unsigned int byteOffsetToNormal = offsetof( sVertex_p4t4n4b4i4, Normal );
unsigned int byteOffsetToBoneIDs = offsetof( sVertex_p4t4n4b4i4, BoneIDs );
unsigned int byteOffsetToBoneWeights = offsetof( sVertex_p4t4n4b4i4, BoneWeights );
glEnableVertexAttribArray ( 0 ); // Position
glEnableVertexAttribArray ( 1 ); // TexCoord
glEnableVertexAttribArray ( 2 ); // Normal
glEnableVertexAttribArray ( 3 ); // BoneIDs
glEnableVertexAttribArray ( 4 ); // BoneWeights
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, bytesInOneVertex, (GLvoid*)byteOffsetToPosition );
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, bytesInOneVertex, (GLvoid*)byteOffsetToUVCoords );
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, bytesInOneVertex, (GLvoid*)byteOffsetToNormal );
glVertexAttribPointer(3, 4, GL_INT, GL_FALSE, bytesInOneVertex, (GLvoid*)byteOffsetToBoneIDs );
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, bytesInOneVertex, (GLvoid*)byteOffsetToBoneWeights );
CheckGLError();
I have dumped all of the information into log files like this:
On mesh load: (V:ertex, T:excoord, N:ormal, W:eight, I:d)
V: ( -10.7595, -90.5606, 10.2667, 1)
T: ( 0.800398, 0.961321, 0, 0)
N: ( -0.43245, -0.568786, -0.699621, 0)
W: ( 1, 0, 0, 0)
I: ( 1, 0, 0, 0)
------------------------------------
V: ( -13.78, -90.5591, 15.3024, 1)
T: ( 0.791644, 0.936781, 0, 0)
N: ( -0.786336, -0.582521, -0.205779, 0)
W: ( 1, 0, 0, 0)
I: ( 1, 0, 0, 0)
------------------------------------
V: ( -12.0146, -80.7495, 15.3008, 1)
T: ( 0.842778, 0.927585, 0, 0)
N: ( -0.994609, 0.0540453, -0.0884974, 0)
W: ( 0.5, 0.5, 0, 0)
I: ( 0, 1, 0, 0)
------------------------------------
V: ( -12.0146, -80.7495, 15.3008, 1)
T: ( 0.842778, 0.927585, 0, 0)
N: ( -0.994609, 0.0540453, -0.0884974, 0)
W: ( 0.5, 0.5, 0, 0)
I: ( 0, 1, 0, 0)
------------------------------------
V: ( -9.78351, -80.4126, 10.7916, 1)
T: ( 0.84573, 0.957308, 0, 0)
N: ( -0.517826, -0.0239735, -0.85515, 0)
W: ( 0.5, 0.5, 0, 0)
I: ( 0, 1, 0, 0)
------------------------------------
...
...
...
Walk Animation @ 0.1 seconds.log
...
...
...
RigLArmPinky1
Scaling: 0.999793, 1.00015, 1.00005
Rotation: -0.00196581, -0.000597763, -0.301885, 0.953342
Position: 11.2164, -0.0247269, -1.10963
>> [ Bone #35 ]
Global Transformation
> Translation: 37.7533, 75.6701, 35.4029
> Scaling: 0.999963, 1.00049, 1.00026
> Rotation: 0.159073, 0.536706, 0.58563, 0.586242
--------------------
...
...
...
--------------------
RigRArmIndex2
Scaling: 1.00019, 0.999862, 0.999948
Rotation: 2.10373e-005, -4.84573e-005, -0.399209, 0.91686
Position: 2.76004, 3.8147e-006, -9.53674e-007
>> [ Bone #20 ]
Global Transformation
> Translation: -37.1777, 57.9378, -6.8726
> Scaling: 1.00027, 1.00014, 0.999923
> Rotation: -0.96948, 0.194101, 0.141847, 0.0482982
...
...
...
Pictures
If I use povided bone ids from the layout location:
--
If I use all bone ids as 20 position += BoneMatrices[20] * in_Position * in_BoneWeights[0];
:
--
If I use all bone ids as 35 position += BoneMatrices[35] * in_Position * in_BoneWeights[0];
:
Vertex Shader
#version 400
layout(location=0) in vec4 in_Position; // x,y,z,1.0f
layout(location=1) in vec4 in_UV_x2;
layout(location=2) in vec4 in_Normal; // x,y,z,0.0f
layout(location=3) in ivec4 in_BoneIDs;
layout(location=4) in vec4 in_BoneWeights;
out vec4 ex_Position;
out vec4 ex_PositionWorld;
out vec4 ex_Normal;
out vec4 ex_UV_x2;
out vec4 ex_BoneWeights;
out vec4 ex_BoneIDs;
uniform mat4 RotationMatrix;
uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;
const int MAX_BONES = 100;
uniform mat4 BoneMatrices[MAX_BONES];
//uniform mat4 BoneRotationMatrices[47];
uniform bool bHasBones;
void main(void)
{
// Calculate MVP Matrix
mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
if ( bHasBones == false )
{
gl_Position = MVP * in_Position;
ex_Position = in_Position;
ex_PositionWorld = ModelMatrix * in_Position;
ex_Normal = RotationMatrix * normalize(in_Normal);
ex_UV_x2 = in_UV_x2;
return;
}
int BoneID0 = in_BoneIDs[0];
int BoneID1 = in_BoneIDs[1];
int BoneID2 = in_BoneIDs[2];
int BoneID3 = in_BoneIDs[3];
// calculate positionworld
vec4 position = vec4(0.0f, 0.0f, 0.0f, 0.0f);
position += BoneMatrices[BoneID0] * in_Position * in_BoneWeights[0];
position += BoneMatrices[BoneID1] * in_Position * in_BoneWeights[1];
position += BoneMatrices[BoneID2] * in_Position * in_BoneWeights[2];
position += BoneMatrices[BoneID3] * in_Position * in_BoneWeights[3];
gl_Position = MVP * position;
ex_Normal = RotationMatrix * in_Normal;
ex_Position = position;
ex_PositionWorld = ModelMatrix * position;
ex_UV_x2 = in_UV_x2;
ex_BoneWeights = in_BoneWeights;
ex_BoneIDs = in_BoneIDs;
return;
}
If you need me to provide anything else, I am more than happy to post more code, pictures, or dump any information for you
Edit #1
So i'm working on the theory that the ids are getting altered (set to 0). What i did was this:
int BoneID0 = in_BoneIDs[0] + 46;
int BoneID1 = in_BoneIDs[1] + 46;
int BoneID2 = in_BoneIDs[2] + 46;
int BoneID3 = in_BoneIDs[3] + 46;
// calculate positionworld
vec4 position = vec4(0.0f, 0.0f, 0.0f, 0.0f);
position += BoneMatrices[BoneID0] * in_Position * in_BoneWeights[0];
position += BoneMatrices[BoneID1] * in_Position * in_BoneWeights[1];
position += BoneMatrices[BoneID2] * in_Position * in_BoneWeights[2];
position += BoneMatrices[BoneID3] * in_Position * in_BoneWeights[3];
That has the same result as the first picture. If I add 47 (The size of the bone array) it throws INVALID_OPERATION
. Does that prove that the ids are not being set properly then?
Edit #2
Changed sVertex_p4t4n4b4i4
to be all floats, and changed layout locations to be vec4
instead of ivec4
. Casted the ids to be ints, and everything works perfectly now.
Can delete/close this
Thanks in advance to anyone who can point anything out