OpenGLでのストリームアウト その5

AMD(ATI)で動くOpenGLのストリームアウト(transform_feedback拡張)が一応できました。GL_EXT_transform_feedback のエクステンションを利用します。

■準備するもの

  • 頂点データのためにVBOを使えるようにすること
  • GLSLによるシェーダーを使えるようにすること
  • クエリー発行できること

■シェーダーの準備

GLSLシェーダーを準備します。
glAttachでオブジェクトを設定し、glLinkProgramまで終わらせておきます。

その後そのシェーダーからストリームアウトするのに必要なvarying変数を設定します。
変数名による配列を準備して、
それをglTransformFeedbackVaryingsEXTにて設定します。
この例を下記に示します。

// 変数の名前を配列で格納しておく
const char* varying[] = {
  "gl_Position",
  "vColor",
};
glTransformFeedbackVaryingsEXT(
  program,
  2,
  varyings,
  GL_INTERLEAVED_ATTRIBS_EXT );

■ストリームアウト実行部

シェーダーをセットするほか、いくつかの設定を行います。

// ストリームアウト用の設定
glUseProgramObjectARB( program );
glEnable( GL_RASTERIZER_DISCARD_NV );
glBindBufferOffsetEXT(
  GL_TRANSFORM_FEEDBACK_BUFFER,
  0,
  streamOutId,
  NULL );
glBeginTransformFeedbackEXT( GL_TRIANGLES );
glBeginQuery(
  GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV,
  query );

ストリームアウトするため、ラスタライズ処理の無効化をします。
また、書き出す先のVBOをバインドしておきます(streamOutIdが対象VBOです)。
続いて、ストリームアウトの開始を宣言し、同時に書き込んだプリミティブ数を取得するためのクエリを発行しておきます。

この後、通常の描画と同じように実行します。
終了時には設定を戻します。以下に例を示します。

glEndQuery( GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV );
glEndTransformFeedbackEXT();
glDisable( GL_RASTERIZER_DISCARD );
GLuint nPrimitivesWritten = 0;
glGetQueryObjectuiv(
  query,
  GL_QUERY_RESULT,
  &nPrimitivesWritten );

各種終了を宣言し、クエリの結果を取得します。
ここでプリミティブの数を取得しないとその後結果をうまく使うことができません。
OpenGLにはDrawAutoは存在しないためです*1

この後描画するのであれば、GL_ARRAY_BUFFERにバインドして通常と同じように描画できます。
ただし、インデックスバッファと併用できるかは現在未確認です。
頂点の増減がGSで行われてしまうため(行われる可能性があるため)です。
頂点を増やさなかったら、インデックスバッファ使える可能性はあるのかも。

*1 : transform_feedback2拡張らで含まれるらしいですが

■NVIDIAで使えない理由

glBindBufferOffsetEXT のAPIだけが取得できません。
取得しようとするとNULLが返ってきます。
そのため、同様の機能を探すとglBindBufferOffsetNVとなるため、
それだったらNV拡張のほうを使うか、ということになるわけです。

多くの部分でEXTと共通ですが、ストリームアウトするvarying変数らの設定が異なります。
NVIDIA版では、変数のLocationIdで設定するようになります。

■感想

とりあえずNVIDIAの今後のドライバでこのAPI取得ができるようになるなら、
どの環境であれEXT拡張に統一できるんですが・・・。
また、一部のAPIが欠落しているのにもかかわらず、GetString( EXTENSION )でサポートしている旨を返してきてほしくはないですね。

OpenGL プログラミング
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました