OpenGL ES 3.0 matrix array only using first matrix

1.5k views Asked by At

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 :/

1

There are 1 answers

0
Rajveer On BEST ANSWER

In the end this looks to be a limitation of the Adreno driver, which doesn't support indexing a uniform array of matrices without a constant integer contrary to what is mandatory within the OpenGL ES spec. A workaround however is to just use a uniform array of vec4s, as it does seem to support indexing these with variables (as is done within their SDK).