I am doing GPU skinning in my vertex shader which works fine on PC, and which I'm porting to Android. My vertex shader is below, and the problem is that the creation of the matTransform matrix seems to only use the first matrix in boneMatrices:
#version 300 es
precision highp float;
precision highp int;
//Uniform count: projectionMatrix(16) + modelViewMatrix(16) + MVPMatrix(16) + textureMatrix(16) + normalMatrix(9) + lightMVPMatrices(16*5) + nShadowLights(1) + boneMatrices(16*boneMax) = 73 + 1 + 16*shadowLightMax + 16*boneMax = (out of ~1024 components)
//GLSL ES (vectors): projectionMatrix(4) + modelViewMatrix(4) + MVPMatrix(4) + textureMatrix(4) + normalMatrix(3) + lightMVPMatrices(4*5) + nShadowLights(1) + boneMatrices(4*boneMax) = 19 + 4*shadowLightMax + 4*boneMax = 239 out of 256 vectors on Nexus 5 (shadowLightMax = 5, boneMax = 50, 17 vec4s remain, or 4 matrices and 1 vec4)
//Matrices
//uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 MVPMatrix;
uniform mat4 textureMatrix;
uniform mat3 normalMatrix;
uniform mat4 lightMVPMatrices[5];
uniform int nShadowLights;
//Bones
uniform mat4 boneMatrices[50];
//Vertex information
in vec3 position;
in vec4 colour;
in vec2 texCoord;
in vec3 normal;
in vec3 boneWeights;
in vec4 boneIndices;
out vec4 _colour;
out vec2 _texCoord;
out vec3 _normal;
out vec3 _eyePos;
out vec4 _lightPos[5];
void main(void)
{
vec4 positionSkinned;
vec4 normalSkinned;
mat4 matTransform = boneMatrices[int(boneIndices[0])] * boneWeights[0];
matTransform += boneMatrices[int(boneIndices[1])] * boneWeights[1];
matTransform += boneMatrices[int(boneIndices[2])] * boneWeights[2];
float finalWeight = 1.0 - (boneWeights[0] + boneWeights[1] + boneWeights[2]);
matTransform += boneMatrices[int(boneIndices[3])] * finalWeight;
positionSkinned = matTransform * vec4(position, 1.0);
//positionSkinned.w = 1.0;
normalSkinned = matTransform * vec4(normal, 0.0);
gl_Position = MVPMatrix * positionSkinned;
_colour = colour;
_texCoord = (textureMatrix * vec4(texCoord, 0.0, 1.0)).xy;
_normal = normalize(normalMatrix * normalize(normalSkinned.xyz));
_eyePos = (modelViewMatrix * positionSkinned).xyz;
for(int i = 0; i < nShadowLights; i++)
_lightPos[i] = lightMVPMatrices[i] * positionSkinned;
}
I have verified that:
1) the correct matrices get pushed into boneMatrices
2) the correct bone indexes exist within boneIndices
3) the correct boneWeights exist within boneWeights
4) accessing components of boneIndices with dot notation (.x, .y, .z and .w) doesn't make a different
5) There are no OpenGL errors at all, as I check for errors after every call, and uniform size isn't an issue (if I increase boneMatrices by 5 extra matrices, I get invalid operation errors after each time I push matrices to the shader, but at this size and lower it's fine)
I have checked points 1, 2 and 3 (boneMatrices, boneIndices and boneWeights are correct) by doing the following:
1) using a specific animation which modified a few bones only (e.g. boneMatrix[6]), then hard-coding boneMatrix[6] and verifying that all vertices get properly modified by this single matrix, with the same result on PC and Android
2) drawing out boneIndices by doing the following in the vertex shader:
_colour = vec4(boneIndices[0], boneIndices[1], boneIndices[2], boneIndices[3]);
and the following in the fragment shader:
gl_FragColor = _colour
with the same colours on PC and Android
3) doing the same as above but with setting _colour to:
_colour = vec4(boneWeights[0], boneWeights[1], boneWeights[2], finalWeight);
I have no idea what else to try, and it definitely seems to be that only the first matrix is used and that for some reason, int(boneIndices[x]) results in 0 for any x. This is on a Nexus 5 with an OpenGL ES 3.0. Help!
EDIT: Taking Andon's advice of using ivec4's instead of vec4's for boneIndices unfortunately results in the same result, however at least this clears up that it isn't a casting issue from float. Now I feel like a cop without any leads :/
ivec4would make a lot more sense. You can supply data to an integer vertex attribute usingglVertexAttribIPointer (...). You may also be coming close to running out of uniform locations in this GLSL program, an array of 50mat4s by itself uses 200 uniform locations and GL ES 3.0 is only required to give you 256 total. If this were a fragment shader, you would already be over the limit of 224. - Andon M. Coleman_colour = vec4(float(boneIndices.x), float(boneIndices.y), float(boneIndices.z), float(boneIndices.w));. Here is an image of it on Windows showing all bone matrices being used, and here is a screenshot from Android showing only the first being used (with bone indices used for colour). - RajveerglUniform4fv(boneUniformLocation, bones.size()*16, (GLfloat*) &bones[0].values[0]);where bones is an array of matrices with 16 GLfloats. - Rajveer