3

ライン ストリップとして使用される頂点のセットが 2 つあります。

  1. 頂点1
  2. 頂点2

これらの頂点は動的であるため、以前は不明な値を持っていることを知っておくことが重要です。

これら 2 つの間にアニメーションのトランジション (モーフ) を作成したいと考えています。私はこれを行うための2つの異なる方法を思いつきました:

オプション1:

頂点シェーダーで0 - 1の Time ユニフォームを設定します。ここで、次のようなことができます。

// Inside main() in the vertex shader
float originX = Position.x;
float destinationX = DestinationVertexPosition.x;
float interpolatedX = originX + (destinationX - originX) * Time;

gl_Position.x = interpolatedX;

ご覧のとおり、これには 1 つの問題があります。 「DestinationVertexPosition」を取得するにはどうすればよいですか?

オプション 2:

頂点シェーダーの外側で補間計算を行います。各頂点をループし、補間された値の 3 番目の頂点セットを作成し、それを使用してレンダリングします。

// Pre render
// Use this vertex set to render
InterpolatedVertexes

for (unsigned int i = 0; i < vertexCount; i++) {
   float originX = Vertexes1[i].x;
   float destinationX = Vertexes2[i].x;
   float interpolatedX = originX + (destinationX - originX) * Time;

   InterpolatedVertexes[i].x = interpolatedX;
}

アイデアを明確にするために、これら 2 つのコード スニペットを非常に単純化しました。

さて、2 つのオプションから、シェーダー レベルで何かが発生することを考えると、最初のオプションがパフォーマンスの点で明らかに優れているように感じます。また、 「時間」が更新されるたびに新しい頂点のセットを作成する必要はありません。.

問題の概要を説明したので、次の 3 つのことのいずれかを評価します。

  1. OpenGL ES 2 (iOS) で望ましい結果を達成するためのより良い方法についての議論。
  2. 「DestinationVertexPosition」を提供するか、何らかの方法でアイデアを変更して、同じ結果をより適切に達成することにより、オプション 1を適切に実装する方法についての説明。
  3. オプション 2の実装方法に関するディスカッション。
4

2 に答える 2

10

ES 2 では、このような属性を好きなように指定します。したがって、 と の両方originに属性を指定destinationし、頂点シェーダーでそれらの間の線形補間を行うことに問題はありません。mixただし、GPU はベクトル プロセッサであり、 GLSL 関数は必要な線形ブレンドを実行するため、コードが示唆しているように、コンポーネントごとに行うべきではありません。たとえば、(明らかに非効率で仮定があります)

int sourceAttribute = glGetAttribLocation(shader, "sourceVertex");
glVertexAttribPointer(sourceAttribute, 3, GL_FLOAT, GL_FALSE, 0, sourceLocations);

int destAttribute = glGetAttribLocation(shader, "destVertex");
glVertexAttribPointer(destAttribute, 3, GL_FLOAT, GL_FALSE, 0, destLocations);

と:

gl_Position = vec4(mix(sourceVertex, destVertex, Time), 1.0);
于 2011-12-30T15:38:20.420 に答える
3

ここでの 2 つのオプションにはトレードオフがあります。2 倍のジオメトリを 1 回提供し、その間を補間するか、ジオメトリのセットを 1 つだけ提供しますが、フレームごとに行います。ジオメトリ サイズとアップロード帯域幅を比較検討する必要があります。

iOS デバイスでの経験から、オプション 1 を強くお勧めします。すべてのフレームに新しいジオメトリをアップロードすると、これらのデバイスでは非常にコストがかかる可能性があります。

GL_STATIC_DRAW頂点が一定の場合、フラグを設定して 1 つまたは 2 つの頂点バッファー オブジェクト (VBO) に一度アップロードできます。PowerVR SGX シリーズには、静的 VBO を処理するためのハードウェアの最適化があるため、最初のアップロード後は非常に高速に動作します。

1 つのシェーダーで使用するために 2 セットの頂点をアップロードする方法に関しては、ジオメトリはシェーダーのもう 1 つの入力属性にすぎません。1 つ、2 つ、またはそれ以上の頂点セットを 1 つの頂点シェーダーに供給することができます。次のようなコードを使用して属性を定義するだけです

attribute vec3 startingPosition;
attribute vec3 endingPosition;

次のようなコードを使用してそれらの間を補間します

vec3 finalPosition = startingPosition * (1.0 - fractionalProgress) + endingPosition * fractionalProgress;

編集:mix()トミーは、私が忘れていた操作を指摘しており、上記の頂点補間を行うためのより良い方法です。

シェーダー プログラムに頂点の 2 番目のセットを取得する場所を通知するには、ジオメトリの 2 番目のセットに対して最初のセットとほぼ同じglVertexAttribPointer()呼び出しを使用し、その VBO と属性のみを指定します。

この計算は、3 つのコンポーネントすべてを個別に分割するのではなく、ベクトルとして実行できることに注意してください。これは、現在の PowerVR SGX チップのデフォルトの精度ではあまり得られませんがhighp、一度に 1 つのコンポーネントを実行するよりも、将来のチップでは高速になる可能性があります。

また、頂点スキニングに使用される他の手法を調べることもできます。これは、2 つの完全な頂点セットをアップロードする必要のない、頂点をアニメートする方法が他にある可能性があるためです。

オプション 2 (各フレームに新しいジオメトリをアップロードする) が望ましいと私が聞いた 1 つのケースは、Accelerate フレームワークを使用してジオメトリのベクトル操作を行う方が、GPU でスキニングを行うよりも高速になる特定のケースです。Unity 関係者がこれについて一度話していたことを覚えていますが、それが非常に小さいジオメトリ セットのためだったのか、非常に大きなジオメトリ セットのためだったのか思い出せません。オプション 1 は、私が自分で作業したすべてのケースで高速でした。

于 2011-12-30T15:44:09.000 に答える