View Full Version : Passing bone matrices to the shader

06-29-2016, 05:20 AM

I try to move from CPU skinning to GPU skinning.
So far I managed to load the model and animation files without any problems.
I`ve rendered the bones and the model on the CPU to make sure that everything moves as supposed.

But when I`m passing the bone matrix, weights and indices to the shader everything gets messed up.

I think the problem is the way I have build the bone Matrix..
I use a std:vector that contains mat4`s (I can access the elements of the matrix by their "elements[0 - 15]" parameter).

While passing single matrices works like a charm, passing a vector of matrices might not work as I think it does.

This is how I pass the matrix (my matrices are row major so I have to transpose them):

GLuint boneLoc = glGetUniformLocation(m_Effect.getProgram(), "boneMatrix");
glUniformMatrix4fv(boneLoc, m_boneMatrix.size(), GL_TRUE, &m_boneMatrix[0].elements[0]);

Then I`m trying to use the bone matrices in the shader to calculate the final positions..
( this part is following the tutorial at www.3Dgep.com )

#version 410 core

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoords;
layout(location = 3) in vec4 weight;
layout(location = 4) in ivec4 boneIndex;

out vec2 outTexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 boneMatrix[100]; //a fixed size for testing.. will be dynamic as soon as the rest works

void main(void)

mat4 matTransform = boneMatrix[boneIndex.x] * weight.x;
matTransform += boneMatrix[boneIndex.y] * weight.y;
matTransform += boneMatrix[boneIndex.z] * weight.z;

float finalWeight = 1.0f - ( weight.x + weight.y + weight.z );
matTransform += boneMatrix[boneIndex.w] * finalWeight;

vec4 objPos = matTransform * vec4( position, 1.0 );
vec4 objNormal = matTransform * vec4( normal, 0.0 ) ;

gl_Position = projection * view * model * objPos;
outTexCoords = texCoords;

(.. normals, lightning etc...)


Is it the way I store and pass the matrices? Or is there something obviously wrong with my shader?


06-29-2016, 01:45 PM
What is the format of this "mat4" type you mention? Given the glUniformMatrix4fv() call, it needs to contain 16 floats (no other members, no virtual method table, no virtual base classes, i.e. sizeof(mat4) must be 64), and the elements need to be in row-major order.

Also: 100 mat4's might be too much for the default uniform block. 100 mat4's = 400 vec4's = 1600 components. The value of GL_MAX_VERTEX_UNIFORM_COMPONENTS isn't required to be more than 1024. Try making the boneMatrix array smaller. If you need a larger array, you'll need to use either a named uniform block backed by a uniform buffer object, or e.g. a buffer texture.

If you want to make the array size dynamic, you'll need to either use a texture or recompile the shader if the array size changes. Uniform arrays (either in the default uniform block or in a named uniform block) must have a fixed size (this can be specified either explicitly in the array declaration or implicitly by indexing the array using only integral constant expressions).

06-30-2016, 02:51 AM
Hey GClements,

yes the size of mat4 is 64. It is a simple 16 float array in row major order.
I have printed out the matrices on the console that are send to the shader as well as converting them to a single mat4[] array instead of an vector containing mat4`s but nothing helped.
It seems that the data itself is alright.. maybe my calculations in the shader are wrong? Removing all of the bone calculations from the shadercode will draw the model in bind pose just fine....

You are right the size of the boneMatrix array in the shader is waaay to big.. it was for testing only..
I think I will try using a texture later on but for now I just want to concentrate on the GPU skinning.

06-30-2016, 02:13 PM
maybe my calculations in the shader are wrong?

I can't see anything wrong with the shader.

You could try using transform feedback mode to capture the transformed position and normal along with matTransform itself and compare the results to your CPU-based version.