ようこそゲストさん

すらりん日記

メッセージ欄

分類 【プログラミング::OpenGL】 で検索

一覧で表示する

2007/07/28(土) OpenGL実験

[プログラミング] OpenGL実験中

OpenGLでシェーダーが使えるようになって、ちょっと必要があって試行錯誤してました。
参考にしたのが、CodeSamplerのやつです。
標準のシェーダーアセンブラを読み込ませて表示していました。

http://www.codesampler.com/oglsrc/oglsrc_9.htm#ogl_shader_simple

これにちょいちょいと手を入れて、Cgのシェーダーを使って表示もやってみました。
行列の列指向、行指向でちょっと転置する必要があったりしますがそのくらいの変更でした。

最後に定数レジスタに直接値をセットする方法も試してみてました。
こちらもおおむねうまくいっているので一安心というところです。
Matrix44 mat;
mat.identity().translate( 0.0f, 0.0f, -4.0f );
mat.rotateX( -g_fSpinY * 3.141592/180.0f);
mat.rotateY( -g_fSpinX * 3.141592/180.0f);
Matrix44 mWVP = matProj * mat;
mWVP.transpose();
cgSetMatrixParameterfc( g_cgParamWVP, (const float*)mWVP.m);

// Cg使わない場合はこんな感じで
for(int i=0;i<4;i++) {
gl::OGLDevice::getDev()->glProgramParameter4fNV(
GL_VERTEX_PROGRAM_NV,
i,
mWVP[4*i+0], mWVP[4*i+1], mWVP[4*i+2], mWVP[4*i+3] );
! 友人より
こんなのを教えてもらいました。

http://labs.i-revo.jp/wiki/?PythonWorkshop2007%2Fsession05

1: slash 『http://xoops.frontwing.jp/product/timeleap/download.html』 (2007/08/08 12:58)

2010/04/27(火) OpenGLのメモ

テクスチャのアドレッシングモードで、
境界色へのクランプってソフトウェア処理と思っていたが、
ちょっと前からそれは違っていたらしい。

発覚したのは GL_CLAMP_TO_BORDER について調べてみたからで、
ある海外サイトによると、GeForce2のころはソフトウェア処理となっていたようだ。

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

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

2010/05/02(日) テクスチャアドレッシングモード

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

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

出来ることの代表的なものとして、
  • 繰り返し貼る(リピート)
  • 反転しながら貼る(ミラー)
  • 繰り返さずに残った部分は引き延ばし
というのがあります。

OpenGL vs DirectX

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

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

どうでもいいこと

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

2010/06/28(月) GLSLスキニング

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

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

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

備考

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

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

ソースコード(VertexProgram)

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

36個にした理由は、tiny.xがこの個数で描けるからです。
#version 120
attribute vec4 in_position;
attribute vec3 in_normal;
attribute vec2 in_texcoord0;
attribute vec4 in_blendindices;
attribute vec4 in_blendweight;

varying vec4 outCol;
varying vec2 outTexcoord0;
uniform vec4 gViewProj[4];
uniform vec4 gMatrixPalette[4 * 36 ];
uniform vec4 gDiffuse;

void main() {
    int  index[4];
    index[0] = int(in_blendindices.x);
    index[1] = int(in_blendindices.y);
    index[2] = int(in_blendindices.z);
    index[3] = int(in_blendindices.w);
    float weight[4] ;
    weight[0] = in_blendweight.x;
    weight[1] = in_blendweight.y;
    weight[2] = in_blendweight.z;
    weight[3] = in_blendweight.w;

    vec4 pos = vec4(0,0,0,1);
    vec3 nrm = vec3(0,0,0);
    for( int i = 0; i < 4; i++ ) {
      int idx = index[i];
      float w = weight[i];
      pos.x += dot( gMatrixPalette[ idx*4 + 0 ], in_position ) * w;
      pos.y += dot( gMatrixPalette[ idx*4 + 1 ], in_position ) * w;
      pos.z += dot( gMatrixPalette[ idx*4 + 2 ], in_position ) * w;
      
      nrm.x += dot( gMatrixPalette[ idx*4 + 0 ].xyz, in_normal.xyz ) * w;
      nrm.y += dot( gMatrixPalette[ idx*4 + 1 ].xyz, in_normal.xyz ) * w;
      nrm.z += dot( gMatrixPalette[ idx*4 + 2 ].xyz, in_normal.xyz ) * w;
    }

    gl_Position.x = dot( gViewProj[0], pos );
    gl_Position.y = dot( gViewProj[1], pos );
    gl_Position.z = dot( gViewProj[2], pos );
    gl_Position.w = dot( gViewProj[3], pos );
    outCol = gDiffuse * max( 0.1, dot( in_normal, vec3( 0.7, 0.7, -0.7) ) );
    outTexcoord0 = in_texcoord0;
}

2010/06/29(火) シェーダー定数(GLSL)

ボーンの行列60個

どこかのブログでボーン用マトリックスパレットが60個くらいまでしか使えなかったと見たので、その理由を書いてみます。
実はその制限は単純なもので、ShaderModel3系までだと、シェーダー定数は256個のレジスタが使えることになっています。
マトリックスだとfloatの16個分なので、float4に換算すると4つ使うことになります。

そして、Matrixが60個の場合 240個の定数レジスタを使ってしまうことになります。
頂点変換用のViewやProjectionのマトリックスも使うことを考えると、
この時点で250個くらいは使っていることになるので、約60個までボーン使えたという結果に合致していると思います。

ずいぶん前の記事だったようで、もうすでに解決しているかもしれません。

GLSLとHLSLとの違いで嵌った

DirectX(HLSL)の行列型は実はfloat4の設定APIを呼んでも設定が可能だったりします。
しかしながらOpenGL(GLSL)の行列型はそのような設定を許さないようです。それぞれで共通のシェーダーを作る場合には、この部分に注意が必要そうです。

2010/07/10(土) Scissorによる挙動違い(DX vs GL)

DirectXとOpenGLとで、シザーの設定時のクリア挙動が異なるようです。

座標系がそれぞれ異なるってのもあるけど、
そこは上下を逆転して対処したとしても、それだけでは互換動作は不可能。


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

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

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

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

2010/07/16(金) 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でやった例ってホント見あたらず。

2010/07/17(土) OpenGLでのストリームアウト その2

GL_NV_transformfeedbackのspecテキスト

こう書いてあった。
Two methods exist to specify which transformed vertex attributes are
streamed to one, or more, buffer objects in transform feedback mode. If
an OpenGL Shading Language vertex and/or geometry shader is active, then
the state set with the TransformFeedbackVaryingsNV() command determines
which attributes to record. If neither a vertex nor geometry shader is
active, the state set with the TransformFeedbackAttribsNV() command
determines which attributes to record.
なるほど、1つ疑問が解けた。
今までTransformFeedbackAttribsNVを実行していたが、
これは固定機能での描画時に使うもののようだ。
(VSもGSも存在しないときと書いてある)。

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

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

その他

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

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

2010/07/18(日) 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なのか、固定機能による処理なのか

2010/07/27(火) OpenGLでのストリームアウト その4

今までのものは GL_transform_feedback_NVのやつでやっていた。
しかし、今回AMDのRadeon 5450環境を手に入れられたのでこちらについても
ちょっと試してみた。

GL_transform_feedback_EXT をサポートしているようなのでこちらを使うことになりそう。

APIの置き換え(その1)

NVIDIAAMD
glBeginTransformFeedbackNVglBeginTransformFeedbackEXT
glEndTransformFeedbackNVglEndTransformFeedbackEXT
こんな感じで単純に置き換えておけば、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のサンプルを作って公開する予定です。