kumaryu日記
2009-09-04 基本的なところを間違える
_ [Riko] COLLADA読み込み
なんかまたCOLLADA読み込みを始めました。
年に3回はCOLLADAを読んでる気がしますが。
今回はカメラ。まあそんなに難しくないだろうと思ったんですが、これが意外と苦労した。難しくは無かったんだけど。
カメラの各パラメータがアニメーションできるようになってるんで、アニメーションを適用してみるまで確定しない。まあアニメーション対応は一応仕組みとして作ってあるから、注意してやればそんなにめんどいわけじゃないけどね。
とりあえず出来たかと思ったら、想定よりものすごい小さく表示されちゃった。Blenderからはちゃんとした値が出てるみたいなんだけど。
しらべてたらなんかカメラの近平面クリップの値によって表示の大きさが変わる。んん?
おおっと、俺の透視変換行列が間違ってんぞ!なぜかXYのところに近平面までの距離を掛けてる。何計算してんだよこれ!
そこを直したらちゃんと出た。まさかそんな根本的なところが間違ってるとは思わなかったから時間かかっちまったぜ。
今までもおかしかったのに良く気づかなかったなぁ、と思ったんだが、近平面までの距離はいつも1.0にしていたのでした、うへへ。
これで出来たと思ったら、一部のメッシュしか表示されなくなってしまった。はて。
データを見たら、シーン中でカメラのインスタンス化より前にメッシュのインスタンス化をしている。たしかに今はカメラの描画メソッドでカメラパラメータを設定してるし、シーングラフを上からたどって順番に描画してるのでこうなるのは分かる。
でもこれじゃきっと困るよなぁ。でもカメラの後の物だけが影響を受けるというのも分からなくはない。
たとえばカメラが複数インスタンス化されてて、このノードはカメラ1で描画されてほしいけど、こっちのノードはカメラ2で描画されてほしいってことがあるよね?
って書いてて自分で思ったがどんな状況だよそれ!明らかに一つのシーンに描ける物じゃないよ!!
しかしカメラが複数インスタンス化されてたらどうすればいいんだ?仕様とか見たけど禁止されてるわけでもなくとくに何も書いてない。うーん、まあべつにいいか。一番最初に見つけたカメラで描画すれば。
最終的にはインスタンス化されてるカメラをリストアップしておくだけにして、プログラム側がその中で適当な奴を選んで使ってねということに。まあこれが普通だわな。
あとはアニメーションを適用して…お、絶対間違ってると思ったのに普通に動いちゃった。やったー。
次はライトの設定を読み込みたいんだけど、これはシェーダも対応させないといけないから後回しにしてきちゃったんだよね。こまったわ。
_ シェーダ難しい
ライトとシェーダの関係が難しいというお話。
何が難しいって、ライトは当然シェーダに設定してあげないといけない物なんですが、ライトの種類と数に応じてシェーダをコンパイルしなおさないといけない。というかライトの種類と数の変化に対応できるシェーダを書かなくてはいけなくて、むむむ…。
数も種類も動的に変えられるようなシェーダも書けるんだが、GPUでの動的分岐はやばい。らしい。
いくつか方法は考えられるんだけどどれがいいんだろう。
- ライト数と各ライトの種類毎にシェーダを作る
前もって全パターンのシェーダをコンパイルしておいて、どんなパターンのライトが来てるかによって切り替える方法。 ライト種類の最大ライト数乗個のシェーダが出来るんだよね。 最大ライト8本で平行高原と点光源のみでも256種類。メモリとコンパイル時間が大変なことになりそう。
- 種類と数は決め打ち
平行光源4本、点光源4つと決めうち。必要ない光源もカラー0とかにして計算してしまう。 いくつ決め打ちにするか難しいかも。シェーダパラメータの最大数を見て変えられるかな? ライトが少ないときに処理が無駄になっちゃうね。
- 全部動的に決定
書くのは一見楽だけど、遅いはず。注意深く書けばそんなに遅くは無いと思うけど、注意深く書くって事自体が大変だ。
どれがいいかとなると、種類と数を決め打ちするのが管理も書くのも楽だしよさげかなぁ。負荷の心配もあんまりしなくていい。
ただ動的にライトが増減するようなものだと、シーン中にいくつライトが来るかを前もって予想するのは難しいし、十分大きな数を指定するのももったいない。
なので足りなくなったら増やすか、一部のライトは見なかったことにするとかしないといけないね。増やすよりは減らす方が楽だな。うまい具合に減らすのが難しそうだけど。
話は変わるけど、カメラとかライトみたいなシーン全体に設定しないといけないパラメータのシェーダへの設定が難しい。
シェーダのuniform変数ってプログラム単位に保持される物だから、全てのシェーダに一括設定ってのができなくて…。
OpenGLのアセンブリシェーダにはenviromentレジスタがあって、これはプログラムごとじゃなくてグローバルに設定できるレジスタなんだけど、GLSLではなんで無くなっちゃったんだろうなぁ。
いやまあ、ある名前の変数が何番のレジスタに割り付けられるかってのを、てんでばらばらにコンパイルされるシェーダ間で統一しろってのは無理なのは分かるんですけどね。でもなんとかできなくもなさそうな気がするんだけど…。
uniform buffer objectとか使えば同じようなことは出来るけど、これはつい最近の機能だからOpenGL2世代では使えない。というか期待できない。
そうすると一個一個Uniform変数を設定しないといけなくて大変だよ。というか遅いよ。
でもそれしかないし、なんとかUniform Buffer Objectをラップするような物作るしかないんかね。
あ、Uniform Buffer Objectの嫌なところはシェーダも書き換えないといけないところだよな。有り無しでかき分けるのめんどい><