我正在我的Android手机中实现骨骼动画,这就是我的工作方式:
计算CPU端的所有骨骼转换矩阵
创建一个浮动纹理来存储这些矩阵(所以这是在每个帧的开头完成的)。代码如下所示:
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);
在顶点着色器中,从此纹理中获取矩阵并应用于顶点位置
这种方法在使用POWERVR GPU的Motorola Milestone XT-701中运行良好。但是当我在Qualcomm snapdragon(SE Xperia X10i和Google Nexus one)上运行它时,有很多三角形消失了(看起来是随机的),所以看起来模型是闪烁的。
我还尝试通过仅渲染一个动画模型来降低场景复杂度,并且闪烁变小但仍然存在。有谁知道我可能做错了什么?这是某种同步问题吗?
你可以在这里看到snapshots(前两张图片是正确的,后两张图片是错误的)。我的grogram的APK文件可以下载here。 (它不需要任何许可,所以不要担心)
这是我使用的顶点着色器:
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;
}
答案 0 :(得分:5)
每帧重新创建纹理效率不高。您可以使用相同的texID
,并且每帧只调用glTexImage*
。
为什么不使用1D纹理?这将消除tex-coord转换为2D的负担。
您的关节矩阵是4x4,但您将其存储为4个GL_RGBA向量。此内部格式仅允许[0,1]范围,这不适合您的任务。请尝试使用GL_RGBA_16f作为内部格式。