5

だから私は 2D スケルトン アニメーション システムで作業しています。

X 個のボーンがあり、各ボーンには少なくとも 1 つの部分 (四角形、2 つの三角形) があります。平均して、骨は 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 個レンダリングすると、おそらく 15 fps を得ることができます。

フレームごとに非常に多くの頂点データをコピーすることで、ほとんどのパフォーマンスが損なわれていることがわかりました。私は別の極端に行くことに決め、アニメーションを「事前計算」し、各キャラクターの開始時に頂点バッファーを構築しました。これには、単一のキャラクターのすべてのフレーム、すべてのパーツの xyuv 座標が含まれていました。次に、特定の時間に使用する必要があるフレームのインデックスを計算し、現在のフレームと次のフレームの 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 個が画面に表示され、50 fps で快適に使用できます。しかし今では、1 トンのメモリを使用しています。現在は ushort になっている xyuv の精度をいくらか落とすことで、これを最適化しました。

ボーン依存性が失われるという問題もあります。親と子の 2 つのボーンがあり、子のキーフレームが 0 秒と 2 秒で、親のキーフレームが 0 秒、0.5 秒、1.5 秒、2 秒の場合、子は 0.5 秒と 2 秒の間で変更されません。 1.5秒です。

私は、この骨の問題を解決する解決策を思いつきました。つまり、子に親と同じポイントにキーフレームを持たせることです。しかし、これはさらに多くのメモリを使用し、基本的にボーン階層のポイントを殺します。

これが私が今いるところです。パフォーマンスとメモリ使用量のバランスを見つけようとしています。ここには冗長な情報がたくさんあることはわかっています (特定のパーツのすべてのフレームで UV 座標が同一であるため、約 30 回繰り返されます)。また、パーツのセットごとに新しいバッファーを作成する必要があります (一意の XYUV 座標を持ちます。パーツによってサイズが異なるため、位置が変わります)。

現時点では、キャラクターごとに 1 つの頂点配列を設定して、すべてのパーツの xyuv を設定し、各パーツのマトリックスを計算して、シェーダーで再配置してみます。これが機能することはわかっていますが、最初に行っていた各フレームの XYUV をアップロードするよりもパフォーマンスが良くならないのではないかと心配しています。

得たパフォーマンスを失わずにこれを行うより良い方法はありますか?

私が試すことができるワイルドなアイデアはありますか?

4

1 に答える 1

1

これを行うためのより良い方法は、30 個のパーツをオンザフライで変換することです。さまざまな位置にパーツのコピーを何千も作成するのではありません。頂点バッファーには頂点データの 1 つのコピーが含まれるため、大量のメモリが節約されます。次に、各フレームは、 への呼び出しで描画する各ボーンの頂点シェーダーにユニフォームとして渡される一連の変換によって表すことができますglDrawElements()。各従属ボーンの変換は、親ボーンを基準にして構築されます。次に、手作業で作成されたアニメーションと手続き的に生成されたアニメーションの間の連続体のどこにアニメーションが必要かによって、一連の変換が多かれ少なかれスペースと CPU 計算時間を消費する可能性があります。

Jason L. McKesson の無料の本、Learning Modern 3D Graphics Programmingでは、第 6 章でこれを達成する方法について適切な説明が提供されています。この章の最後にあるサンプル プログラムは、マトリックス スタックを使用して階層モデルを実装する方法を示しています。このプログラムの iOS ポートで OpenGL ES 2.0 を利用できます

于 2012-12-14T19:44:10.427 に答える