所以我正在使用 2D 骨骼动画系统。
有 X 个骨骼,每个骨骼至少有 1 个部分(一个四边形,两个三角形)。平均而言,我大概有 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 上,渲染 10 个这样的骨骼可能会达到 15fps。
我发现大部分性能都被每帧复制这么多顶点数据消耗掉了。我决定走另一个极端,并“预先计算”动画,在开始时为每个角色建立一个顶点缓冲区,其中包含单个角色中每一帧、每一部分的 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 上失去一些精度来优化它,现在是 ushorts。
还有一个问题是骨骼依赖性丢失了。如果有两个骨骼,一个父子,一个子子在0s和2s有一个关键帧,父子在0s,0.5s,1.5s,2s有一个关键帧,那么子子在0.5s和2s之间不会改变1.5s 应该的。
我想出了一个解决这个骨骼问题的解决方案——通过强迫孩子在与父母相同的点上拥有关键帧。但这使用更多的内存,并且基本上杀死了骨骼层次结构的点。
这就是我现在的位置。我试图在性能和内存使用之间找到平衡。我知道这里有很多冗余信息(特定部分的所有帧的 UV 坐标都是相同的,所以重复了大约 30 次)。并且必须为每组零件创建一个新的缓冲区(具有唯一的 XYUV 坐标——位置会发生变化,因为不同的零件尺寸不同)
现在,我将尝试为每个角色设置一个顶点数组,其中包含所有部分的 xyuv,并计算每个部分的矩阵,并在着色器中重新定位它们。我知道这会起作用,但我担心性能不会比我刚开始时为每一帧上传 XYUV 更好。
有没有更好的方法来做到这一点而不会失去我所获得的性能?
有什么疯狂的想法我可以尝试吗?