I'm implementing skeletal animation in my android phone, and here is how I do it:
Calcualte all bone transformation matrices on the CPU side
Create a float texture to store these matrices (so this is done at the beginning of each frame). The codes look like below:
if(texID) { glDeleteTextures(1, &texID); texID = 0; } glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, p);
In vertex shader, fetch matrix from this texture and apply to vertex position
This approach works fine in my Motorola Milestone XT-701 using a POWERVR GPU. But when I run it on a Qualcomm snapdragon (SE Xperia X10i and Google Nexus one), there are many triangles disappeared (looks randomly), so it seems the model is flickering.
I also tried to reduce the scene complexity by rendering only one animated model, and the flicker become less but still exists. Does anyone know what I may be doing wrong? Is this some kind of synchronization problem?
You can see the snapshots here (the first two pictures is correct, and the later two are wrong). The APK file of my grogram can be downloaded here. (it does not require any permission so don't worry)
Here is the vertex shader I used:
struct light {
lowp vec4 position; // light position for a point/spot light or
// normalized dir. for a directional light
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec3 spot_direction;
lowp vec3 attenuation_factors;
lowp float spot_exponent;
lowp float spot_cutoff_angle;
bool compute_distance_attenuation;
};
struct material {
lowp vec4 ambient_color;
lowp vec4 diffuse_color;
lowp vec4 specular_color;
lowp vec4 emissive_color;
lowp float specular_exponent;
};
// uniforms used by the vertex shader
// uniform vec4 u_color;
uniform highp mat4 u_mvMatrix;
uniform highp mat4 u_projMatrix;
uniform bool u_enable_lighting;
uniform light u_light_state;
uniform material u_material_state;
uniform bool u_enable_texture;
uniform highp sampler2D s_jointTex; // use highp for float texture
// attributes input to the vertex shader
// attribute lowp vec4 a_color;
attribute highp vec3 a_position;
attribute lowp vec3 a_normal;
attribute mediump vec2 a_texCoord;
attribute highp float a_jointID;
// varying variables – input to the fragment shader
varying lowp vec4 v_front_color;
varying mediump vec2 v_texCoord;
vec2 mapTo2D(float idx)
{
vec2 st = vec2(idx + 0.5, 0.5);
return st / 256.0;
}
void main()
{
mat4 joint = mat4(1.0);
if(a_jointID >= 0.0)
{
float idx = a_jointID * 4.0;
joint = mat4( texture2D(s_jointTex, mapTo2D(idx)),
texture2D(s_jointTex, mapTo2D(idx+1.0)),
texture2D(s_jointTex, mapTo2D(idx+2.0)),
texture2D(s_jointTex, mapTo2D(idx+3.0)) );
gl_Position = (u_projMatrix * u_mvMatrix) * joint * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(1.0, 0.0, 0.0, 1.0);
}
else
{
gl_Position = (u_projMatrix * u_mvMatrix) * vec4(a_position, 1.0); // hint compiler to extract uniform calculation
// v_front_color = vec4(0.0, 1.0, 0.0, 1.0);
}
if(u_enable_lighting)
{
lowp vec4 computed_color = vec4(0.0);
vec3 normal = normalize( vec3(u_mvMatrix * joint * vec4(a_normal, 0.0) ) );
vec3 lightDir = normalize( vec3(u_mvMatrix * u_light_state.position) );
float NdotL = max(dot(normal, lightDir), 0.0);
computed_color += u_light_state.ambient_color * u_material_state.ambient_color + NdotL * u_light_state.diffuse_color * u_material_state.diffuse_color;
if(NdotL > 0.0) {
vec3 half_vec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); // why?
float NdotHV = dot(normal, half_vec);
if(NdotHV > 0.0)
computed_color += u_light_state.specular_color * u_material_state.specular_color * pow(NdotHV, u_material_state.specular_exponent);
}
v_front_color = computed_color;
}
else
v_front_color = vec4(1.0, 1.0, 1.0, 1.0); // u_material_state.ambient_color; // TODO?
v_texCoord = a_texCoord;
}