2012-10-25 24 views
5

したがって、私は2D骨格アニメーションシステムで作業しています。OpenGL ESでの骨格アニメーションの頂点の最適化

骨がX個あり、各骨には少なくとも1つの部分(四角形、2つの三角形)があります。私は平均して20本の骨と30本の骨を持っています。ほとんどの骨は親に依存し、骨はすべてのフレームに移動します。アニメーションごとに合計で1000フレームあり、私は約50のアニメーションを使用しています。一度に合計約50,000フレームがメモリにロードされます。パーツはスケルトンのインスタンス間で異なります。

私がかかった第1のアプローチは、各骨の位置/回転を計算し、各部分のこのから成る頂点配列を、構築した:

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

そしてglDrawElementsそれぞれに介してこれを通過フレーム。

これはうまく見えますが、私が必要とするすべてのシナリオをカバーし、メモリをあまり使わず、犬のように動作します。 iPod 4では、これらのスケルトンのうち10個がレンダリングされて15fpsになることがあります。

各フレームで非常に多くの頂点データをコピーすることで、ほとんどのパフォーマンスが低下していたことがわかりました。私は別の極端に行き、アニメーションを「あらかじめ計算」することに決めました。各キャラクタの先頭に頂点バッファを構築しました。各フレームのxyuv座標がすべてのパーツで1文字になっていました。次に、特定の時間に使用されるべきフレームのインデックスを計算し、デルタ値を計算します。デルタ値は、現在のフレームXY位置と次のフレームの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です。

骨依存性が失われるという問題もあります。 2つのボーン(親と子)があり、その子が0と2のキーフレームを持っている場合、親は0、0.5、1.5、2のキーフレームを持ち、0.5と1.5秒かかるはずです。

私は、この骨の問題を解決するソリューションを考え出しました。子供が親と同じポイントでキーフレームを持つようにすることによって解決しました。しかしこれはより多くの記憶を使用し、基本的に骨の階層構造のポイントを殺します。

これは私が今いるところです。私は、パフォーマンスとメモリ使用のバランスを見つけることを試みています。私はここに冗長な情報がたくさんあることを知っています(UV座標は特定のパーツのすべてのフレームで同じですので、〜30回繰り返されます)。そして、新しいパーツを作成する必要があります(ユニークなXYUV座標を持っています - 異なるパーツが異なるため位置が変わります)

今は文字ごとに1つの頂点配列を設定しようとします。これはすべての部分にxyuvを持ち、各部分の行列を計算し、それらをシェーダで再配置します。私はこれがうまくいくことは知っていますが、私が最初にやっていたフレームごとにXYUVをアップロードするだけではパフォーマンスはそれほど良くないとは心配です。

私が得たパフォーマンスを失うことなくこれを行うより良い方法はありますか?

私が試してみたい野生のアイデアはありますか?

+0

nice question sir – Weacked

+0

すべてのボーンは、すべてのフレームで「自分自身で動く」か、親が動いたために移動したばかりのボーンが多いですか? – Dirk

+0

骨のうち1つを除くすべてが親と一緒に動きます。親とは無関係にほとんど何もしない骨がいくつかありますが、親が移動するよりも何倍も動くものがあります。 –

答えて

1

これを実行するより良い方法は、30個のパーツをオンザフライで変換することです。異なる位置にある部品を何千もコピーすることはできません。頂点バッファには頂点データの1つのコピーが含まれ、膨大なメモリが節約されます。次に、各フレームは、glDrawElements()を呼び出して描画する各ボーンに対して、頂点シェーダに均一なものとして渡される一連の変換によって表現できます。それぞれの依存する骨の変形は、親の骨に対して相対的に構築されます。手作業と手続き的に生成された手作りの連続のどこにアニメーションが必要なのかに応じて、変換のセットは多かれ少なかれ空間とCPUの計算時間を要する可能性があります。

ジェイソンL.マッケソンの無料の本、Learning Modern 3D Graphics Programmingは、この章の終わりの例のプログラムは、階層モデルを実装するために行列スタックを使用する方法を示し6.章でこれを実現する方法についての良い説明を提供します。 I have an OpenGL ES 2.0 on iOS port of this program available

+0

残念ながら、それは私の元のバージョンが正確にどのように働いたかです。そして、現在の実装と同じくらい速くどこでも実行しました。私はこれをやっていることが面倒な大量のメモリを使い、ローディング時間を増やすことを知っていましたが、スクリーン上に多くの文字を置くと少なくとも50%速くなりました。しかし、提案のおかげで、投票しました。 –

関連する問題