「 OpenGL 」一覧

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


今までのものは GL_transform_feedback_NVのやつでやっていた。
しかし、今回AMDのRadeon 5450環境を手に入れられたのでこちらについても
ちょっと試してみた。GL_transform_feedback_EXT をサポートしているようなのでこちらを使うことになりそう。

APIの置き換え(その1)

NVIDIA AMD
glBeginTransformFeedbackNV glBeginTransformFeedbackEXT
glEndTransformFeedbackNV glEndTransformFeedbackEXT

こんな感じで単純に置き換えておけば、NV->EXT使用になる

APIの置き換え(その2)

glTransformFeedbackVaryingsNV は glTransformFeedbackVaryingsEXT を使用することに。
中身が違うので単純に置き換えてはいけない。

以前 ”GLchar**を受け取る!?ヘッダ正しいですか?”と書いていた部分が間違っていたことに気づいた。

  • EXT版ではGLchar**を受け取る。
  • NV版ではGLintを受け取るべき

という差異があった。これが仕様。

EXT版では、varying変数名を設定できるが、
NV版ではvarying変数のロケーションIdを受け取る
という仕様の違いがあったためであった。

NVIDIAとAMDと両方のデバイスをさわってみて初めて納得がいった。

感想

やっぱりOpenGLのTransform Feedback(StreamOut機能相当)は情報が少ない。
使っている人が少ないのかもしれないので、これからがんばる人のために
ここに情報を書いておきます。

近いうちにNVIDIAとAMDと両方で動くtransform_feedbackのサンプルを作って公開する予定です。


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


ようやく動作自体は出来たのでメモしておきたいと思います。
サンプルプログラムはまた後日に。

準備

  1. GLSLシェーダーをコンパイル
  2. シェーダープログラムをリンク処理
  3. glTransformFeedbackVaryingsNV でストリームアウトとして書き込むデータの設定
  4. 格納先のバッファオブジェクトを生成

描画フェーズ

  1. ラスタライズ処理の無効化(GL_RASTERIZER_DISCARD_NV)
  2. glBindBufferOffsetNV, glBeginTransformFeedbackNV らで書き込み先のバッファオブジェクトを設定
  3. 描画処理.
  4. glEndTransformFeedbackNVで終了処理.
  5. GL_RASTERIZER_DISCARD_NVのステートを戻す

描画の前後でクエリー発行しておくことで書き込まれたデータ(プリミティブ数)を取得することが出来ます。

ここまでくるのに色々と試行錯誤しましたがようやく動かせる状態にきました。
注意のポイントは以下の点だと思います。

  • シェーダープログラムのリンク後の処理
  • GLSLなのか、固定機能による処理なのか

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


GL_NV_transformfeedbackのspecテキスト

こう書いてあった。

なるほど、1つ疑問が解けた。
今までTransformFeedbackAttribsNVを実行していたが、
これは固定機能での描画時に使うもののようだ。
(VSもGSも存在しないときと書いてある)。

つまりGLSLでやるならば、TransformFeedbackVaryingsNVを使って設定することが必要ということ。

こちらで試してみる。
ネット探してのサンプルだけを頼りに試行錯誤していましたが、
本家ドキュメントもしっかり読まないとダメですね。反省。

その他

昨日のGLchar*とint*の差違問題はどうやらNVIDIAからglext.hを持ってくると、int*となっている。
OpenGLのサイトから持ってくるとGLchar*となっている。

とりあえずNVIDIAのほうからヘッダ持ってくるとしよう。


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


OpenGLを用いてもDirectX10のストリームアウト相当の機能を使うことが出来ます。この機能のためにまず最初に拡張されたのが GL_NV_transform_feedback というエクステンションです。
最近ではこれがEXTになったようですが、単純にNVから格が上がっただけとはいえないようです。
APIが変更されているからです。

EXT版で試行錯誤しましたが、うまくいかず、NVのほうでまず動作を試してみようと思います。

目標

これらの点から次のことを目標にしています。

  • Cgを用いずにGLSLを使う
  • ひとまずNV拡張のほうを使ってみる
  • ストリームアウトの結果を見るために、ジオメトリシェーダーでは入力頂点を増やして出力する
  • 出力頂点を確認してみて、動作を確認する

OpenGLでのストリームアウト

OpenGLではVertexBufferObject(VBO)に対して結果を書き込むことができます。*1

他にも、tranform_feedback2, 3とかあったりしますが、
これらはOpenGL4系で追加だそうです。

*1 : バッファオブジェクトであれば書き込み先に出来るようです

GL_EXT_transform_feedbackの不審点

glBindBufferOffsetが関数実体を持っていなさそう。
glBindBufferOffsetNVだと関数実体は取れる。
こんな状態なのに、GetStringでエクステンション名は取れてしまう。
不思議です。

GL_NV_transform_feedback 拡張の罠

今のところいくつかの怪しい点で動作せず状態です。

  • glext.h内でglTransformFeedbackAttribsNVが const GLchar* *varyings の引数になっている。
    • ExtensionRegistryでは、ここはGLint*なはずなのに。

現時点での動作不良点

  • 書き込んだプリミティブ数が0のままで取れない…。
    • 書き込み先バッファは何かデータがかかれているようだが。
    • (glMapBufferのREAD_ONLYにて値を確認)

完全に動作するサンプルを検索しても見つからないので苦労しています。
NVIDIAではCgつかったサンプル例となっているし、そのほかもCg使ってしまっているし。
GLSLでやった例ってホント見あたらず。


Scissorによる挙動違い(DX vs GL)


DirectXとOpenGLとで、シザーの設定時のクリア挙動が異なるようです。座標系がそれぞれ異なるってのもあるけど、
そこは上下を逆転して対処したとしても、それだけでは互換動作は不可能。

フレームバッファの縦横と、ビューポートの縦横と、シザー設定の縦横
それぞれ違う設定にしてみて、双方のAPIで実行してみるとわかりやすいかと。

DirectXではビューポートとシザー設定のお互い被っている領域でクリア
GLではシザー設定に従ってクリア。

同じような振る舞いにさせるならシザー領域とビューポートの領域のAND集合を取るようにして、
できあがった矩形でシザーテストするようにしてクリア処理を入れるようにする。

GL面倒だけど、こういうった細かいことをきちんと実装できるだけ
柔軟性はあると思う。


GLSLスキニング


GLSLでスキニングシェーダー書いてみた

わりとGLSLでスキニングシェーダーをやったという記事を見かけないので
ここで書いてみます。

大変だった点はGLSLでは、Cのようなキャストを受け付けない点。
そのためブレンドインデックスをどうやってint型にするかで悩みました。
実際には、下記のソースコードに示すように int( )で囲ってやる程度で済む話なのですが、
知らないと結構悩みます。

備考

マトリックスを使わずにfloat4 (すなわちvec4)でやっているのは
単に自分のスタイルなだけです。
先輩のシェーダースタイルに影響された可能性が大です。
matrix型のほうが変換がmulで書ける分だけソースコードはすっきりします。
float4の4つという表現だと、シェーダー定数設定をするコードがすっきりします。
またMatrixをfloat4x3型として使っているような場合で効率よくシェーダー定数を使うことが出来ます。

他にはライティングが適当です。
平行光源と若干のアンビエント成分いれたつもりのコードです。

ソースコード(VertexProgram)

1頂点あたり4ボーンのスキニングシェーダーです。
1回のマトリックスパレットは36個です。

36個にした理由は、tiny.xがこの個数で描けるからです。


アルファブレンディングについて【教えてほしい】


アルファブレンドで下記の合成はわかった

  • 通常合成(1*srcColor + 0*destColor)
  • 加算合成(1*srcColor + 1*destColor)
  • 半加算合成(srcA * srcColor + 1*destColor)
  • 半透明合成(srcA * srcColor + (1-srcA) * destColor)

しかしこれらがアルファ値だけ別の計算が出来るという仕組みが用意されていたりする。
これの有効な利用が思いつかない。

OpenGLやDirectXではアルファブレンドセパレートとして機能があったりするが。

D3DRS_SEPARATEALPHABLENDENABLE を有効化して
なにかやっているサンプルもまた見つからなかったし。
有効に使えている例、使える例を知っている人は是非教えてください。


テクスチャアドレッシングモード


テクスチャアドレッシングモード

テクスチャを張ったときに、1.0以上の値をどう扱って、
テクスチャを張るかのモード設定です。

出来ることの代表的なものとして、

  • 繰り返し貼る(リピート)
  • 反転しながら貼る(ミラー)
  • 繰り返さずに残った部分は引き延ばし

というのがあります。

OpenGL vs DirectX

で今回感じたのが、OpenGLとDirectXでこれらの機能の差違。
同じ挙動をする設定でも、画面の描画結果が違うということになりました。
もっとも大まかな挙動という点では一緒で、
今回の違いというのは、描画ピクセルが完全一致しないということを示しています。

どうも境界あたりの処理でそれぞれ差違が出ていました。
GL_CLAMP_TO_EDGEやGL_CLAMP_TO_BORDERなど標準機能ではなく
拡張機能で試したのですがうまくいきませんでした。

どうでもいいこと

テクスチャラッピングモードというとまた別のことを指すようです。
少しわかりにくい気がするのは自分だけでしょうか…


OpenGLのメモ


テクスチャのアドレッシングモードで、
境界色へのクランプってソフトウェア処理と思っていたが、
ちょっと前からそれは違っていたらしい。発覚したのは GL_CLAMP_TO_BORDER について調べてみたからで、
ある海外サイトによると、GeForce2のころはソフトウェア処理となっていたようだ。

あと、GL_CLAMP_TO_BORDERが3.0仕様では deprecatedになっている!という
記述を見かけたけど、OpenGL 3.1の仕様書を見てみたところ、
普通に記載があった。海外サイトのコメントをみていたら廃止というのがミスだったようで…

廃止になったのは、GL_CLAMP のようです。