适用于Android OpenGL ES的GPU上的骨骼动画

Joh*_*son 5 android gpu opengl-es

我正在我的Android手机中实现骨骼动画,这就是我的方法:

  1. 计算CPU端的所有骨骼转换矩阵

  2. 创建一个浮动纹理来存储这些矩阵(所以这是在每个帧的开头完成的).代码如下所示:

    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);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在顶点着色器中,从此纹理中获取矩阵并应用于顶点位置

这种方法在使用POWERVR GPU的Motorola Milestone XT-701中运行良好.但是当我在Qualcomm snapdragon(SE Xperia X10i和Google Nexus one)上运行它时,有许多三角形消失(看起来是随机的),所以看起来模型是闪烁的.

我还尝试通过仅渲染一个动画模型来降低场景复杂度,并且闪烁变小但仍然存在.有谁知道我可能做错了什么?这是某种同步问题吗?

你可以在这里看到快照(前两张图片是正确的,后两张图片是错误的).我的grogram的APK文件可以在这里下载.(它不需要任何许可,所以不要担心)

这是我使用的顶点着色器:

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;
}
Run Code Online (Sandbox Code Playgroud)

kva*_*ark 5

  1. 每帧重新创建纹理效率不高.你可以使用相同的texID,只需调用glTexImage*每一帧.

  2. 你为什么不使用1D纹理?它将消除tex-coord转换为2D的负担.

  3. 您的关节矩阵是4x4,但您将其存储为4个GL_RGBA向量.此内部格式仅允许[0,1]范围,这不适合您的任务.请尝试使用GL_RGBA_16f作为内部格式.