在OpenGL ES中优化骨架动画的顶点

时间:2012-10-25 13:34:27

标签: opengl-es opengl-es-2.0 skeletal-animation

所以我正在使用2D骨骼动画系统。

有X个骨骼,每个骨骼至少有一个部分(一个四边形,两个三角形)。平均而言,我可能有20块骨头,30块。大多数骨骼依赖于父母,骨骼将每帧移动。每个动画总共有1000帧,我使用了大约50个动画。任何时候内存中总共加载大约50,000帧。这些部分在骨架的实例之间有所不同。

我采用的第一种方法是计算每个骨骼的位置/旋转,并为每个部分构建一个由此组成的顶点数组:

[x1,y1,u1,v1],[x2,y2,u2,v2],[x3,y3,u3,v3],[x4,y4,u4,v4]

并将每个帧传递给glDrawElements。

看起来很好,涵盖了我需要的所有场景,不会占用太多内存,但却像狗一样表现。在iPod 4上,可能会获得15fps,其中有10个骨架被渲染。

我发现大部分性能都是通过每帧复制如此多的顶点数据来消耗掉的。我决定转到另一个极端,并“预先计算”动画,在每个角色的开头建立一个顶点缓冲区,其中包含每个帧的xyuv坐标,每个部分都在一个字符中。然后,我计算应该在特定时间内使用的帧的索引,并计算一个delta值,该值传递给用于在当前帧和下一帧XY位置之间进行插值的着色器。

每帧的顶点看起来像这样

[--------------------- Frame 1 ---------------------],[------- Frame 2 ------]
[x1,y1,u1,v1,boneIndex],[x2, ...],[x3, ...],[x4, ...],[x1, ...][x2, ...][....]

顶点着色器如下所示:

attribute vec4 a_position;
attribute vec4 a_nextPosition;
attribute vec2 a_texCoords;
attribute float a_boneIndex;

uniform mat4 u_projectionViewMatrix;
uniform float u_boneAlpha[255];

varying vec2 v_texCoords;

void main() {
    float alpha = u_boneAlpha[int(a_boneIndex)];
    vec4 position = mix(a_position, a_nextPosition, alpha);
    gl_Position = u_projectionViewMatrix * position;
    v_texCoords = a_texCoords;  
}

现在,性能非常出色,其中10个在屏幕上,它可以舒适地以50fps的速度运行。但现在,它使用了一公吨的内存。我已经通过在xyuv上失去一些精确度来优化它,现在这些精确度很高。

还存在骨依赖性丢失的问题。如果有两个骨骼,父母和孩子,并且孩子的关键帧为0s和2s,则父级的关键帧为0s,0.5s,1.5s,2s,则子项不会在0.5s和0.5s之间更改。应该1.5s。

我想出了一个解决方案来解决这个骨骼问题 - 强迫孩子在与父母相同的点上拥有关键帧。但是这会占用更多的内存,并且基本上会杀死骨骼层次结构。

这就是我现在所处的位置。我试图在性能和内存使用之间找到平衡点。我知道这里有很多冗余信息(特定部分的所有帧的UV坐标都相同,所以重复约30次)。并且必须为每组零件创建一个新的缓冲区(具有唯一的XYUV坐标 - 位置发生变化,因为不同的零件尺寸不同)

现在我将尝试为每个角色设置一个顶点数组,其中包含所有部分的xyuv,并计算每个部分的矩阵,并在着色器中重新定位它们。我知道这会有效,但我担心性能不会比仅仅为我开始时做的每一帧上传XYUV更好。

有没有更好的方法来做到这一点而不会失去我获得的表现?

我可以尝试一些疯狂的想法吗?

1 个答案:

答案 0 :(得分:1)

更好的方法是动态转换30个零件,而不是在不同位置制作数千份零件。顶点缓冲区将包含顶点数据的一个副本,从而节省了大量内存。然后,每个帧都可以通过一组变换来表示,这些变换作为一个均匀的方式传递给您通过调用glDrawElements()绘制的每个骨骼的顶点着色器。每个依赖骨骼的转换都是相对于父骨骼构建的。然后,根据手工制作和程序生成之间连续性的位置,您需要动画,您的变换集可以占用更多或更少的空间和CPU计算时间。

Jason L. McKesson的免费书籍 Learning Modern 3D Graphics Programming ,就如何在第6章中完成此任务给出了一个很好的解释。本章末尾的示例程序说明了如何使用矩阵堆栈实现分层模型。 I have an OpenGL ES 2.0 on iOS port of this program available