思い返せばGPUでスキニングなんてまともにやったことがない事実。
LightwaveのCPUスキニングくらいしか記憶にない。
分業化の弊害というかやる気がなかっただけというか。
初心に帰ってやってみることにした。
左:行列パレット使用
中:行列パレット使用(途中の過程はSQT)
右:SQT
どれもこれも結果は同じのベーシックな手法。
結局、頂点ブレンドしてる限り潰れることには変わりなし。
サンプルはGitHubのSimpleSkinningSample。
一応、最近の流行というか主流な手法にも目を通してみた。
・spherical blend skinning
・skinning with dual quaternions
前者が主流で後者が割りと最近の手法とのこと。
変形結果を見る限りでは前者が自然な気がする。
計算コスト的には後者が優れている(対数空間で乗算を加算にするとか)。
2012年3月27日火曜日
2012年3月26日月曜日
GLSLあれこれ
HLSLの場合はDirectXがコンパイル。
GLSLの場合はグラフィックカードのドライバでコンパイル。
という認識なので、誤認識でなければドライバが悪さしているということになる。
GLSLに限らずシェーダ言語はベクトル演算が得意なのは百も承知なんだ。
それでも最適化を意識しない段階ではスカラー演算で済ませてしまうこともある。
とある実装で内積演算をスカラー演算で済ませている箇所で問題が発生した。
ベクトル演算に直すと意図した結果になった・・・めでたしめでたし。
では済まない。
C++でのアルゴリズムから演算部分、シェーダの記述を全て見直して、
該当箇所をなんとはなしに変更して見ると、実はベクトル演算でなかった結果、
問題が発生していたのだ。
仮にデバッガがあったとしても、気付き難いレベルだぞっと・・・。
一応ドライバ(nVidia Geforce7800用)は最新なんだけどなぁ。
あとは以前発生していたリンクエラーの問題。
vertex/fragment共にエラーはないのにリンク時に失敗するケース。
失敗時は通常エラーログを取得できるのだができない。
つまり何が起きているのかさっぱり分からない。
glGetShaderiv(program, GL_INFO_LOG_LENGTH, &bufSize);
で返ってくるバッファサイズが負になっていたんだが、無理やり適当なサイズに変更した。
するとエラーログが取得できた。
GLSLのおかげでやりたいことが一向に進まないジレンマ。
GLSLの場合はグラフィックカードのドライバでコンパイル。
という認識なので、誤認識でなければドライバが悪さしているということになる。
GLSLに限らずシェーダ言語はベクトル演算が得意なのは百も承知なんだ。
それでも最適化を意識しない段階ではスカラー演算で済ませてしまうこともある。
とある実装で内積演算をスカラー演算で済ませている箇所で問題が発生した。
ベクトル演算に直すと意図した結果になった・・・めでたしめでたし。
では済まない。
C++でのアルゴリズムから演算部分、シェーダの記述を全て見直して、
該当箇所をなんとはなしに変更して見ると、実はベクトル演算でなかった結果、
問題が発生していたのだ。
仮にデバッガがあったとしても、気付き難いレベルだぞっと・・・。
一応ドライバ(nVidia Geforce7800用)は最新なんだけどなぁ。
あとは以前発生していたリンクエラーの問題。
vertex/fragment共にエラーはないのにリンク時に失敗するケース。
失敗時は通常エラーログを取得できるのだができない。
つまり何が起きているのかさっぱり分からない。
glGetShaderiv(program, GL_INFO_LOG_LENGTH, &bufSize);
で返ってくるバッファサイズが負になっていたんだが、無理やり適当なサイズに変更した。
するとエラーログが取得できた。
おいこらnVidiaの担当者ちょっと出て来い。
GLSLのおかげでやりたいことが一向に進まないジレンマ。
2012年3月21日水曜日
glslDevil
フリーのGLSL用デバッガglslDevilを触ってみた。
シェーダに関わらずgl系列の命令に対するデバッグも可能。
で、肝心のシェーダデバッグではあるが・・・nVidiaのG80ベース(8000系)以上でないと
デバッグができないと記載されている。
GT-7800ユーザとしては・・・。
純粋なデバッグツールとしてはこれ以外は話にならなさそうなんだけどなぁ。
どうもシェーダの動作が安定しないというか挙動不審な時が多々ある。
いわゆるバグではなくGLSLの最適化の都合によるものいう節が多々。
似たようなものをHLSLで動かしても問題ないのになぁ。
[追記]
挙動不審な理由が判明した。
シチュエーションは入力に位置、法線、色を送っている場合を仮定。
シェーダ内部で漏れなく位置、法線、色を利用しなくてはいけない。
多分、最終結果に影響させないとお茶を濁すだけでもダメそうな予感。
デバッグ用に例えば色をシェーダ内部で定数値に置き換えた場合(入力を利用しない)、
シェーダ全体の動作が狂う。
あとは、繰り返し文の内部での分岐とか配列アクセスとかエラーではなくリンクエラーが
返ってきたり・・・イカれた風変わりなシェーダですね。
シェーダに関わらずgl系列の命令に対するデバッグも可能。
で、肝心のシェーダデバッグではあるが・・・nVidiaのG80ベース(8000系)以上でないと
デバッグができないと記載されている。
GT-7800ユーザとしては・・・。
純粋なデバッグツールとしてはこれ以外は話にならなさそうなんだけどなぁ。
どうもシェーダの動作が安定しないというか挙動不審な時が多々ある。
いわゆるバグではなくGLSLの最適化の都合によるものいう節が多々。
似たようなものをHLSLで動かしても問題ないのになぁ。
[追記]
挙動不審な理由が判明した。
シチュエーションは入力に位置、法線、色を送っている場合を仮定。
シェーダ内部で漏れなく位置、法線、色を利用しなくてはいけない。
多分、最終結果に影響させないとお茶を濁すだけでもダメそうな予感。
デバッグ用に例えば色をシェーダ内部で定数値に置き換えた場合(入力を利用しない)、
シェーダ全体の動作が狂う。
あとは、繰り返し文の内部での分岐とか配列アクセスとかエラーではなくリンクエラーが
返ってきたり・・・
2012年3月20日火曜日
GLSLのレジスタ最大数
どこで見るんだろう・・・追々調べることにしよう。
間接的な話題となるスキニングについて。
とりあえず色々必要とはなるが、細かいことは忘れて行列パレットのみ着目。
(1) 古典的な行列パレットによるスキニングその1
真面目に4x4の行列を渡す
→ mat4の最大数=ボーン最大数
(2) 古典的な行列パレットによるスキニングその2
回転(含むスケール)と平行移動以外は不要なので
→ vec4の最大数/3=ボーン最大数
(3) クォータニオンによるスキニング
均等スケールなら平行移動のw辺りに配置して
→ vec4の最大数/2=ボーン最大数
(3)はクォータニオンを圧縮すれば回転は半分で済みそう。
平行移動も稼動範囲を意識すれば半分で済みそう。
予め1つの頂点に対するボーンの最大影響数が判明しているなら許容範囲でならなんでもいい。
といいたいところだけど、行列変換による加重平均は潰れる箇所とか出てくるんだよね。
頂点の場合は形状に法線の場合は光源計算に影響が出るから、いづれも見た目がおかしくなる。
ボーン数増やして対処はできるが本末転倒な気がする。
容量的にも品質的にも(3)がデフォルトか。
最近の事情は良く分からないけど100本級のメッシュとか普通なんだろうかね?
間接的な話題となるスキニングについて。
とりあえず色々必要とはなるが、細かいことは忘れて行列パレットのみ着目。
(1) 古典的な行列パレットによるスキニングその1
真面目に4x4の行列を渡す
→ mat4の最大数=ボーン最大数
(2) 古典的な行列パレットによるスキニングその2
回転(含むスケール)と平行移動以外は不要なので
→ vec4の最大数/3=ボーン最大数
(3) クォータニオンによるスキニング
均等スケールなら平行移動のw辺りに配置して
→ vec4の最大数/2=ボーン最大数
(3)はクォータニオンを圧縮すれば回転は半分で済みそう。
平行移動も稼動範囲を意識すれば半分で済みそう。
予め1つの頂点に対するボーンの最大影響数が判明しているなら許容範囲でならなんでもいい。
といいたいところだけど、行列変換による加重平均は潰れる箇所とか出てくるんだよね。
頂点の場合は形状に法線の場合は光源計算に影響が出るから、いづれも見た目がおかしくなる。
ボーン数増やして対処はできるが本末転倒な気がする。
容量的にも品質的にも(3)がデフォルトか。
最近の事情は良く分からないけど100本級のメッシュとか普通なんだろうかね?
2012年3月19日月曜日
進捗 その2
アニメーションやスキニングをする予定はなかったのだが、一応どんなものか目を通した。
どちらも比較的単純で理解自体は直ぐではあった。
が、やはりデータ構造がしんどいなぁ。
スキン関連だと行列パレット、頂点ウェイトの個数なんかが圧縮されているから
すべて展開しないといけない。
最大10個程度のボーンの影響しかないのに展開前だと85とか総数が記載されてるから。
アニメーションの指定についても
<channel source="#group1_translate-anim-samplerY" target="group1/translate.Y"/>
ターゲットの指定がこれだしなぁ・・・。
colladaを直接扱ってる限りmapの呪縛からは逃れられないってことか。
あとはデータ構造全般として、参照形式で持たせておいたほうが良さそうだ。
同じものを描画する際、<node>だけクローンさせれば無駄がなくなるし。
どちらも比較的単純で理解自体は直ぐではあった。
が、やはりデータ構造がしんどいなぁ。
スキン関連だと行列パレット、頂点ウェイトの個数なんかが圧縮されているから
すべて展開しないといけない。
最大10個程度のボーンの影響しかないのに展開前だと85とか総数が記載されてるから。
アニメーションの指定についても
<channel source="#group1_translate-anim-samplerY" target="group1/translate.Y"/>
ターゲットの指定がこれだしなぁ・・・。
colladaを直接扱ってる限りmapの呪縛からは逃れられないってことか。
あとはデータ構造全般として、参照形式で持たせておいたほうが良さそうだ。
同じものを描画する際、<node>だけクローンさせれば無駄がなくなるし。
2012年3月14日水曜日
進捗
問題点ばかりだったので進んでいなかったテクスチャ周辺を改修。
各サンプラにつき2Dテクスチャ1枚という限定はあるが自動読み込み完了。
自動読み込みってなんだって感じだが、今まで非常に残念なことをしていたのだ・・・。
結局デフォルトシェーダも対応しなければいけない方向になってきたがどうしたものか。
あとは、上軸の定義をどうするか。
今の環境ではデフォルトでZ_UPばかり出力されるから、面を反転して描画時に回転を掛けている。
真面目に対応するとあらゆる要素を変換しなければいけないというのが憂鬱。
少し問題点を整理しよう。
[追記]2012/03/15
軸の問題が面倒なので気休めに簡単なトラックボールとズーム機能を追加。
手を抜いていらんだろうとたかをくくっていたが、いざ実装してみると便利なものである。
ただ、数学関連のライブラリが大昔に作ったものを引っ張り出してきたため
行指向・左手座標系とかそういう類のものであったため部分的にOpenGLで利用できるよう
改修中。
列指向・右手座標系はこの世から消えてくれ・・・。
GLSL特化にすれば問題ないといえばそうではあるが・・・一考してみるか。
ズーム機能といえばfreeglutなるもので利用できることを知った。
厳密に言えばホイールイベントの検知ではあるが。
GLUT自体の更新が止まっているためfreeglutなるものが開発されているらしい。
VS2005ユーザとしては悲しいが公式のは利用できなかった。
が、こちらでバイナリを配布しているようで、早速利用させて頂いた。
[追記]2012/03/17
階層構造を実装。
<node>の構築自体は終わっていたが行列関連の整備が進んでいなかったため変換行列周り
に手を付けられていない状態だった。
今回もテスト用モデルを物色しこちらから拝借。
というのもこれまで利用していたモデルは変換行列が不要なものばかりだったので。
右腕が変換を含んでいるみたい。
各サンプラにつき2Dテクスチャ1枚という限定はあるが自動読み込み完了。
自動読み込みってなんだって感じだが、今まで非常に残念なことをしていたのだ・・・。
結局デフォルトシェーダも対応しなければいけない方向になってきたがどうしたものか。
あとは、上軸の定義をどうするか。
今の環境ではデフォルトでZ_UPばかり出力されるから、面を反転して描画時に回転を掛けている。
真面目に対応するとあらゆる要素を変換しなければいけないというのが憂鬱。
少し問題点を整理しよう。
[追記]2012/03/15
軸の問題が面倒なので気休めに簡単なトラックボールとズーム機能を追加。
手を抜いていらんだろうとたかをくくっていたが、いざ実装してみると便利なものである。
ただ、数学関連のライブラリが大昔に作ったものを引っ張り出してきたため
行指向・左手座標系とかそういう類のものであったため部分的にOpenGLで利用できるよう
改修中。
列指向・右手座標系はこの世から消えてくれ・・・。
GLSL特化にすれば問題ないといえばそうではあるが・・・一考してみるか。
ズーム機能といえばfreeglutなるもので利用できることを知った。
厳密に言えばホイールイベントの検知ではあるが。
GLUT自体の更新が止まっているためfreeglutなるものが開発されているらしい。
VS2005ユーザとしては悲しいが公式のは利用できなかった。
が、こちらでバイナリを配布しているようで、早速利用させて頂いた。
[追記]2012/03/17
階層構造を実装。
<node>の構築自体は終わっていたが行列関連の整備が進んでいなかったため変換行列周り
に手を付けられていない状態だった。
今回もテスト用モデルを物色しこちらから拝借。
というのもこれまで利用していたモデルは変換行列が不要なものばかりだったので。
右腕が変換を含んでいるみたい。
2012年3月13日火曜日
Metasequoia~Blender~Colladaの罠
ケース1
Metasequoiaで作成した*mqoをBlenderにインポート
*blendで出力
*blendを読み込む
*.mqoでエクスポート
Metasequoiaで読み込む
→ざっくり見た感じ問題ない
ケース2
Metasequoiaで作成した*mqoをBlenderにインポート
*.daeでエクスポート
*.daeをインポート
*.mqoでエクスポート
Metasequoiaで読み込む
→色々アウト。
可逆する必要性はまったくないのでこれ自体は問題ない。
気づいた点が1つ。
Metasequoiaで作成した*mqoをBlenderにインポートし、*daeでエクスポート。
ざっくり見た感じ形状などには問題はない。
が、自己照明(放射光)の値がおかしい。
とある*.daeを読み込んだらやたらと白とびしていたため気がついた。
emissionが(1.0, 1.0, 1.0, 1.0)とかなってるわけ。
単純なレンダリング方程式として見ても、(1.0, 1.0, 1.0, 1.0)とかなってるとトーンマップでも
しない限りemissionを扱っただけで真っ白になるじゃないか!
とりあえず原因を探ってみた。
Metasequoiaのパラメータの扱いが若干特殊なのかも知れない。
というのも自己照明は%表現。
材質パネルの出力イメージで確認するとMetasequoia的には基本色*自己照明となっている。
対してBlenderの*.daeエクスポートを通すと、(自己照明、自己照明、自己照明、1.0)
のようになっている。
Metasequoia側で基本色RGB(255,0,0)として自己照明1.0の出力を行うと
*.daeのマテリアルのemissionが(1.0, 1.0, 1.0, 1.0)となったからだ。
拡散光については想定どおりなんだが。
フリーなので文句は言えないか・・・。
で、渦中の対象モデルは今回こちらから拝借させて頂いた。
中見ると半透明とか使用しているので見た目は結構変わるかも知れない。
emissionについてはどうにもならんので手作業で改変。
フラグメントシェーダはMetasequoia風にアレンジ。
Colladaさん柔軟であるが故に、元が何からエクスポートされたか把握しておかねば
問題点を絞るのが大変だ。
Metasequoiaで作成した*mqoをBlenderにインポート
*blendで出力
*blendを読み込む
*.mqoでエクスポート
Metasequoiaで読み込む
→ざっくり見た感じ問題ない
ケース2
Metasequoiaで作成した*mqoをBlenderにインポート
*.daeでエクスポート
*.daeをインポート
*.mqoでエクスポート
Metasequoiaで読み込む
→色々アウト。
可逆する必要性はまったくないのでこれ自体は問題ない。
気づいた点が1つ。
Metasequoiaで作成した*mqoをBlenderにインポートし、*daeでエクスポート。
ざっくり見た感じ形状などには問題はない。
が、自己照明(放射光)の値がおかしい。
とある*.daeを読み込んだらやたらと白とびしていたため気がついた。
emissionが(1.0, 1.0, 1.0, 1.0)とかなってるわけ。
単純なレンダリング方程式として見ても、(1.0, 1.0, 1.0, 1.0)とかなってるとトーンマップでも
しない限りemissionを扱っただけで真っ白になるじゃないか!
とりあえず原因を探ってみた。
Metasequoiaのパラメータの扱いが若干特殊なのかも知れない。
というのも自己照明は%表現。
材質パネルの出力イメージで確認するとMetasequoia的には基本色*自己照明となっている。
対してBlenderの*.daeエクスポートを通すと、(自己照明、自己照明、自己照明、1.0)
のようになっている。
Metasequoia側で基本色RGB(255,0,0)として自己照明1.0の出力を行うと
*.daeのマテリアルのemissionが(1.0, 1.0, 1.0, 1.0)となったからだ。
拡散光については想定どおりなんだが。
フリーなので文句は言えないか・・・。
で、渦中の対象モデルは今回こちらから拝借させて頂いた。
中見ると半透明とか使用しているので見た目は結構変わるかも知れない。
emissionについてはどうにもならんので手作業で改変。
フラグメントシェーダはMetasequoia風にアレンジ。
Colladaさん柔軟であるが故に、元が何からエクスポートされたか把握しておかねば
問題点を絞るのが大変だ。
2012年3月11日日曜日
COLLADA (7)プリミティブ
再びジオメトリ周辺。
<p>(インデクス配列)には直前の<input>要素の数だけインデクスが入っている。
<input semantic="VERTEX" source="#vertices" offset="0"/>
<input semantic="NORMAL" source="#normals" offset="1"/>
<input semantic="TEXCOORD" source="#texcoords" offset="2" set="0"/>
<p>0 0 1 1 2 2</p>
位置、法線、座標、位置、法線、座標
なんて具合にインデクスが混在している。
上記は非常に単純な例だが、仕様書には様々なイカレタ例が示されている。
また実際に利用される実数は<p>に依存する。
とあるサンプルファイルの実数配列部は
位置:4122 / 3 = 1374
法線:4122 / 3 = 1374
座標:12904 / 2 = 6452
<p>に基づき展開すると
位置:6318 / 3 = 2106
法線:6318 / 3 = 2106
座標:4212 / 2 = 2106
しかしこれではインデクス化の旨みが0。
OpenGLなら要素毎にプッシュできるので百歩譲って問題ないが・・・。
頂点配列を利用するなら再インデクス化が必要。
この部分だけ見ると強烈にダルいフォーマットだなぁ。
<p>(インデクス配列)には直前の<input>要素の数だけインデクスが入っている。
<input semantic="VERTEX" source="#vertices" offset="0"/>
<input semantic="NORMAL" source="#normals" offset="1"/>
<input semantic="TEXCOORD" source="#texcoords" offset="2" set="0"/>
<p>0 0 1 1 2 2</p>
位置、法線、座標、位置、法線、座標
なんて具合にインデクスが混在している。
上記は非常に単純な例だが、仕様書には様々な
また実際に利用される実数は<p>に依存する。
とあるサンプルファイルの実数配列部は
位置:4122 / 3 = 1374
法線:4122 / 3 = 1374
座標:12904 / 2 = 6452
<p>に基づき展開すると
位置:6318 / 3 = 2106
法線:6318 / 3 = 2106
座標:4212 / 2 = 2106
しかしこれではインデクス化の旨みが0。
OpenGLなら要素毎にプッシュできるので百歩譲って問題ないが・・・。
頂点配列を利用するなら再インデクス化が必要。
この部分だけ見ると強烈にダルいフォーマットだなぁ。
2012年3月9日金曜日
マルチテクスチャ
glinterleavedarraysではマルチテクスチャを扱えなさそうなので。
頂点配列による描画とVBOを利用した描画を考察。
固定機能でマルチテクスチャなんかやってられんな・・・というのが1点。
指定が回りくどいにも程があるのとAPIの呼び出し順序がカオス過ぎる。
いづれにしても可変頂点フォーマットを実現するには、頂点要素は分離しておく
必要性がありそうだ。
頂点配列による描画とVBOを利用した描画を考察。
固定機能でマルチテクスチャなんかやってられんな・・・というのが1点。
指定が回りくどいにも程があるのとAPIの呼び出し順序がカオス過ぎる。
いづれにしても可変頂点フォーマットを実現するには、頂点要素は分離しておく
必要性がありそうだ。
glInterleavedArrays
Direct3Dならテクスチャ8ステージまで指定できるんだけど。
glInterleavedArraysを見る限りは1ステージまでしか指定できなさそうだな。
可変頂点フォーマットを許す場合、vboは分割しておく必要性があるってことか。
glInterleavedArraysを見る限りは1ステージまでしか指定できなさそうだな。
可変頂点フォーマットを許す場合、vboは分割しておく必要性があるってことか。
2012年3月7日水曜日
COLLADA (6)マテリアル~エフェクト
これは制限を付けないと収拾が付かない。
今回は下記の制限を付けた。
■<profile_***>
<profile_COMMON>を1つのみ。
仕様書によると固定機能だそうだ。
今時固定機能なんて・・・と思いたいが、シンプルイズベストだ。
将来、いやむしろ今(GLES2.0とか)既にシェーダが基準となっている。
<profile_COMMON>が提供するモデルは、<constant>、<lambert>、<phong>、<blinn>
の4つしかない。
実際これらはシェーダで書いた方が手っ取り早い。
シェーダを準備するのとシェーダ用の窓口を作るのが面倒なだけの単なる怠惰だ。
逆にシェーダ標準で固定機能を切り捨てる設計なら話は早い。
いづれにせよ制限は必要だ。
1つのみとしたことにも理由がある。
仕様書によると<profile_COMMON>以外も0以上で混載できるとある。
何度も引っかかったが、COLLADAはあくまで各種3Dツールの中間フォーマット。
例えばデザイナが試行錯誤しながらモデルを作成している際に、様々なマテリアルを作り
最終的にコレだ!というものを適用する。
適用しなかったものは?
おそらく3Dツールとしては有用な資産として、そうでない場合はゴミとして残る。
デジタルアセットの管理という面では、COLLADAで一元管理(様々なプラットフォーム
データを含む)を行い、そこから必要なものだけ抜き出す感じになるんだろう。
■<Sampler***>
<Sampler2D>のみ。
各種要素のテクスチャは1枚のみ。
キューブマップ(6枚指定)とか考えたくない、、、
<Sampler1D>は面白いことができるのでこれはありかもしれない。
この辺は固定機能では面倒となるので、シェーダ標準とするならすべてサポート
という方向でいいかも。
あと気になったことが1点。
現状はv1.4を対象としているが、仕様書が結構手抜きなのでv1.5も併読している。
今回採り上げた周辺の仕様には地味に差があり、一部互換性がないように見える。
今回は下記の制限を付けた。
■<profile_***>
<profile_COMMON>を1つのみ。
仕様書によると固定機能だそうだ。
今時固定機能なんて・・・と思いたいが、シンプルイズベストだ。
将来、いやむしろ今(GLES2.0とか)既にシェーダが基準となっている。
<profile_COMMON>が提供するモデルは、<constant>、<lambert>、<phong>、<blinn>
の4つしかない。
実際これらはシェーダで書いた方が手っ取り早い。
シェーダを準備するのとシェーダ用の窓口を作るのが面倒なだけの単なる怠惰だ。
逆にシェーダ標準で固定機能を切り捨てる設計なら話は早い。
いづれにせよ制限は必要だ。
1つのみとしたことにも理由がある。
仕様書によると<profile_COMMON>以外も0以上で混載できるとある。
何度も引っかかったが、COLLADAはあくまで各種3Dツールの中間フォーマット。
例えばデザイナが試行錯誤しながらモデルを作成している際に、様々なマテリアルを作り
最終的にコレだ!というものを適用する。
適用しなかったものは?
おそらく3Dツールとしては有用な資産として、そうでない場合はゴミとして残る。
デジタルアセットの管理という面では、COLLADAで一元管理(様々なプラットフォーム
データを含む)を行い、そこから必要なものだけ抜き出す感じになるんだろう。
■<Sampler***>
<Sampler2D>のみ。
各種要素のテクスチャは1枚のみ。
キューブマップ(6枚指定)とか考えたくない、、、
<Sampler1D>は面白いことができるのでこれはありかもしれない。
この辺は固定機能では面倒となるので、シェーダ標準とするならすべてサポート
という方向でいいかも。
あと気になったことが1点。
現状はv1.4を対象としているが、仕様書が結構手抜きなのでv1.5も併読している。
今回採り上げた周辺の仕様には地味に差があり、一部互換性がないように見える。
2012年3月6日火曜日
COLLADA (5)
頭の片隅に常にあった懸案。
・<scene>内の<instance_visual_scene>の出現回数は0または1
・<library_visual_scenes>内の<visual_scene>の出現回数は1以上
・<instance_node>は<library_nodes>を参照する新たなノード
・<instance_material>と<library_materials>
・<instance_effect>と<library_effects>
他
・<instance_geometry>と<library_geometries>
原点回帰とでもいうべきか。
インスタンス化と外部参照
注:COLLADA では、インスタンス間のデータ共有の方法を規定していません。データ共有ポリシーはランタイムアプリケーションに任されています。
とある。
様々な凡例やサンプルを調査すると、よほど単純なものでない限りは共有は意識されていない
ように感じる。
マテリアルを例に出すと、Aという基本になるものに差分変更を加えたB、またはCという具合に
実質3種類のマテリアルがあたかも存在することになる。
ご丁寧に<newparam>や<setparam>などで上手い具合にぼかしてある。
メモリー効率面では断然共有化ではあるが、元データの退避や上書きなど処理が煩雑になる。
おまけに差分要素はぴんからきりである。
実行時に毎回セットアップなんてしてられんなぁということで、<instance_***>系列はそのとおり
インスタンス化する方針に変更。
敢えて他の後に記述した<instance_geometry>。
極端な話をしない限りは<instance_geometry>以外はすべてインスタンス化しても大した量には
ならない。
途中経過の自問自答
<instance_geometry>をインスタンス化しなければならないケースは?
なんらかの頂点に対する操作の結果を必要とする場合。
ソフトウェアでスキンニングとかそういった類か。
vertex_shaderを前提とするなら大抵は回避はできるはず。
地形や背景を1つの*.daeで表現なんて絶対しないししてはいけないだろうが
仮にした場合は共通パターンで影響が出る。
これはそもそもがダメなので問題外。
おっと、モーフィングがあったか。
顔の表現時にボーンじゃ上手くいかん!とか言われて顔だけモーフィングしたことあるな・・・。
とりあえず<instance_geometry>以外をインスタンス化することで妥協する方針で。
・<scene>内の<instance_visual_scene>の出現回数は0または1
・<library_visual_scenes>内の<visual_scene>の出現回数は1以上
・<instance_node>は<library_nodes>を参照する新たなノード
・<instance_material>と<library_materials>
・<instance_effect>と<library_effects>
他
・<instance_geometry>と<library_geometries>
原点回帰とでもいうべきか。
インスタンス化と外部参照
注:COLLADA では、インスタンス間のデータ共有の方法を規定していません。データ共有ポリシーはランタイムアプリケーションに任されています。
とある。
様々な凡例やサンプルを調査すると、よほど単純なものでない限りは共有は意識されていない
ように感じる。
マテリアルを例に出すと、Aという基本になるものに差分変更を加えたB、またはCという具合に
実質3種類のマテリアルがあたかも存在することになる。
ご丁寧に<newparam>や<setparam>などで上手い具合にぼかしてある。
メモリー効率面では断然共有化ではあるが、元データの退避や上書きなど処理が煩雑になる。
おまけに差分要素はぴんからきりである。
実行時に毎回セットアップなんてしてられんなぁということで、<instance_***>系列はそのとおり
インスタンス化する方針に変更。
敢えて他の後に記述した<instance_geometry>。
極端な話をしない限りは<instance_geometry>以外はすべてインスタンス化しても大した量には
ならない。
途中経過の自問自答
<instance_geometry>をインスタンス化しなければならないケースは?
なんらかの頂点に対する操作の結果を必要とする場合。
ソフトウェアでスキンニングとかそういった類か。
vertex_shaderを前提とするなら大抵は回避はできるはず。
地形や背景を1つの*.daeで表現なんて絶対しないししてはいけないだろうが
仮にした場合は共通パターンで影響が出る。
これはそもそもがダメなので問題外。
おっと、モーフィングがあったか。
顔の表現時にボーンじゃ上手くいかん!とか言われて顔だけモーフィングしたことあるな・・・。
とりあえず<instance_geometry>以外をインスタンス化することで妥協する方針で。
COLLADA (4)シーングラフ4
ジオメトリを抜き出すのが最終目的なので、 <node>以下の<instance_geometry>は
軽く抜き出すことに止めて置いた。
というのも設計部分で悩んでいる。
<node>におけるもう1つ重要な要素がある。
transformation_elements
変換要素、つまり移動、回転、縮尺など。
これがまたフォーマット観点から見ると非常に素晴らしい表現である。
各子変換要素が出現順で合成されるコンテキストを表します。
COLLADAさん相変わらず柔軟ですね!
本当に壁を殴ってやりたい・・・。
変換要素は
<Lookat>、<matrix>、<rotate>、<scale>、<skew>、<translate>
これらの出現回数は各々0以上。
ジオメトリ特化かつせん断を考慮しなければ
<matrix>、<rotate>、<scale>、<translate>
※<matrix>が微妙な気がするが
つまり、回転→移動→縮尺→移動→回転なんて記述されていれば
すべて順番どおりにジオメトリに適用しないといけないわけだ。
アニメーションを考慮しないなら行列にしてしまえば済む話ではあるが・・・。
見るだけ見てみるか。
軽く抜き出すことに止めて置いた。
というのも設計部分で悩んでいる。
<node>におけるもう1つ重要な要素がある。
transformation_elements
変換要素、つまり移動、回転、縮尺など。
これがまたフォーマット観点から見ると非常に素晴らしい表現である。
各子変換要素が出現順で合成されるコンテキストを表します。
COLLADAさん相変わらず柔軟ですね!
本当に壁を殴ってやりたい・・・。
変換要素は
<Lookat>、<matrix>、<rotate>、<scale>、<skew>、<translate>
これらの出現回数は各々0以上。
ジオメトリ特化かつせん断を考慮しなければ
<matrix>、<rotate>、<scale>、<translate>
※<matrix>が微妙な気がするが
つまり、回転→移動→縮尺→移動→回転なんて記述されていれば
すべて順番どおりにジオメトリに適用しないといけないわけだ。
アニメーションを考慮しないなら行列にしてしまえば済む話ではあるが・・・。
見るだけ見てみるか。
2012年3月5日月曜日
COLLADA (4)シーングラフ3
今回は思考中な部分をそのまま記述したので長文となってしまった。
ということで要点だけ。
<library_nodes>には<instance_node>となる<node>が格納されている(はず)。
<visual_scene>内の<node>と同じく、<node>の詳細も記述されている (はず)。
node id は一意になるため、getElement で最初に取得できる要素は必ず指定した<node>
になる(はず)。
<instance_node>とすべきかどうかはアプリケーション依存ではあるが、シーングラフ上で
複数回出現するノードはもれなく<instance_node>となり、<library_nodes>に格納される(はず)。
またその子、孫・・・ももれなく<library_nodes>に格納される(はず)。
とりあえずこれで様子を見よう。
ということで要点だけ。
<library_nodes>には<instance_node>となる<node>が格納されている(はず)。
<visual_scene>内の<node>と同じく、<node>の詳細も記述されている (はず)。
node id は一意になるため、getElement で最初に取得できる要素は必ず指定した<node>
になる(はず)。
<instance_node>とすべきかどうかはアプリケーション依存ではあるが、シーングラフ上で
複数回出現するノードはもれなく<instance_node>となり、<library_nodes>に格納される(はず)。
またその子、孫・・・ももれなく<library_nodes>に格納される(はず)。
とりあえずこれで様子を見よう。
2012年3月4日日曜日
COLLADA (4)シーングラフ2
<node>周辺。
<instance_node>が出現する際に循環参照が生成されることはあるんだろうか。
COLLADA DOMへ独自形式を登録しインポート、エクスポートを行っているなら
責務はCOLLADA DOMとなるが、独自にエクスポートしてる場合はなきにしろあらずか。
コンセプトとして各種デジタルアセットを取り扱う基点となるのが目的だから
文句を言っても仕方ないが<instance_node>の存在が少し厄介。
単純な階層構造の場合、<node>はメッシュそのものになるわけだから、
各toWorldは計算済みとなる。
描画フェーズで階層構造をトラバースしながらtoWorldを利用してプリミティブを描画するだけで
いいこととなる。
仕様書の例を少し改造して
仕様書によると、node1はnode2を少し移動するということだ。
class Nodeの例で<instance_node>への参照を持つと、計算フェーズでtoWorldが
上書きされて残念なことになる。
要素は、COLLADA ノードリソースのインスタンス化を宣言するためのものです。
説明に従ってインスタンス化するのが無難か。
とすると、
node0
node1
node2
node3
node2
node3
見かけ上のノード数4が実際には6ということになる。
COLLADA DOMのデータベースを介してノードを展開できると後で楽をできそうだがはてさて。
[追記]
ノードが展開できるかはさておき、daeDatabaseの検索が良くできてるな。
ただ、ここではgetElementの第二引数が0なので<instance_node>の<node>が引っかかる。
常識的に考えると<instance_node>に同じ<node>が存在するはずもないし
それらはただ間接参照するためだけに存在するはずだからid属性しか持っていないはずだ。
また、<library_visual_scenes>内の各<node>のid属性はユニークなはずなので
最大でも2回のクエリで取得できるはずだ。
余談ではあるが、仕様書の<node>の項をよく見ると面白いことが記載されている。
<instance_camera>
<instance_controller>
<instance_geometry>
<instance_light>
<instance_node>
出現回数は0以上。
ということは良し悪しはともかく
・カメラにジオメトリをくっつける
・カメラにライトをくっつける
・ライトにジオメトリをくっつける
なんてことも記載できるわけだ!
改めてこのフォーマットの柔軟性を感じた、今回はいい意味で。
<instance_node>が出現する際に循環参照が生成されることはあるんだろうか。
COLLADA DOMへ独自形式を登録しインポート、エクスポートを行っているなら
責務はCOLLADA DOMとなるが、独自にエクスポートしてる場合はなきにしろあらずか。
コンセプトとして各種デジタルアセットを取り扱う基点となるのが目的だから
文句を言っても仕方ないが<instance_node>の存在が少し厄介。
単純な階層構造の場合、<node>はメッシュそのものになるわけだから、
class Node{ Node* sibling; Node* children; Matrix toLocal; Matrix toWorld; Primitive* prim; }みたいな感じとすると、<node>だけで構成される場合は、階層構造を1度トラバースすれば
各toWorldは計算済みとなる。
描画フェーズで階層構造をトラバースしながらtoWorldを利用してプリミティブを描画するだけで
いいこととなる。
仕様書の例を少し改造して
<library_nodes> <node id="node2"/> </library_nodes> <node id="node0"> <node id="node1"> <translate>11.0 12.0 13.0</translate> <instance_node url="#node2"/> </node> </node> <node id="node2"> <node id="node3"> </node> </node>node1が該当部分となる。
仕様書によると、node1はnode2を少し移動するということだ。
class Nodeの例で<instance_node>への参照を持つと、計算フェーズでtoWorldが
上書きされて残念なことになる。
説明に従ってインスタンス化するのが無難か。
とすると、
node0
node1
node2
node3
node2
node3
見かけ上のノード数4が実際には6ということになる。
COLLADA DOMのデータベースを介してノードを展開できると後で楽をできそうだがはてさて。
[追記]
ノードが展開できるかはさておき、daeDatabaseの検索が良くできてるな。
domNode* dom_node; if(dae_db->getElement((daeElement**)&dom_node, 0, "node2", "node") != DAE_OK) return NULL;先の例でこんな感じにすればdomNodeを引っ張ってこれる。
ただ、ここではgetElementの第二引数が0なので<instance_node>の<node>が引っかかる。
常識的に考えると<instance_node>に同じ<node>が存在するはずもないし
それらはただ間接参照するためだけに存在するはずだからid属性しか持っていないはずだ。
また、<library_visual_scenes>内の各<node>のid属性はユニークなはずなので
最大でも2回のクエリで取得できるはずだ。
余談ではあるが、仕様書の<node>の項をよく見ると面白いことが記載されている。
<instance_camera>
<instance_controller>
<instance_geometry>
<instance_light>
<instance_node>
出現回数は0以上。
ということは良し悪しはともかく
・カメラにジオメトリをくっつける
・カメラにライトをくっつける
・ライトにジオメトリをくっつける
なんてことも記載できるわけだ!
改めてこのフォーマットの柔軟性を感じた、今回はいい意味で。
2012年3月3日土曜日
なんと・・・
物持ちだけはいいらしい。
本棚を整理していたら、結構な数ある3D関連の書籍群から
DirectX2API本や通称3z本を発掘した。
ここ数年はDirectXもすっかり疎遠になっている。
最後に触ったのはPCではなく360だったかな。
懐かしいなぁとパラパラめくりつつ、なんとなく昔のブックマークから
shi3zさんのところを見に行ったりしてみた。
相変わらずご活躍されているようでなにより。
裏CEDECやXFC東京で数回拝見した程度なんだけど記憶に残っている。
XFCといえばnekoさんやMasaさんkanoさんを筆頭に、とんでもない面子が
集結した会合だった。
余談はさておき、記事を読む進めていると衝撃の内容が・・・。
川西裕幸さんがお亡くなりになったそうだ。
私はただのDirectXを利用する1ユーザだったに過ぎないわけだけど
当事はBio100%の掲示板やBBXとか、いわゆる狭いコミュニティ界隈で
ユーザ同士が情報を共有する程度と極めて情報が不足していた。
GDCやGamasutraのスライドにSIGGRAPHの論文などもあるにはあったが。
DirectX6-7あたりからかな、この方が公式でDirect3Dまたは3Dに関連する記事を
精力的に更新していた記憶がある。
SDKも当事は英語ヘルプしかないか僅かな部分だけ翻訳されている程度だったのが
この頃あたりから日本語ヘルプがほぼリリースと同時に出ていたと思う。
shi3zさんのところにも書いているが、その後も著名な洋書の翻訳監修として名前は必ず見かけた。
所有している書籍を見渡しただけでも簡単に目に留まる。
(そういえばnVidiaの人をCEDECに引っ張ってきたのはこの方なのかな)
Microsoft社にはエバンジェリストという役職がある。
(wikiを見るまでいわゆる肩書きかと思っていた)
本当にそのとおりの伝道師といえるんじゃないだろうか。
謹んでお悔やみを申し上げますとともに、心からご冥福をお祈りいたします。
本棚を整理していたら、結構な数ある3D関連の書籍群から
DirectX2API本や通称3z本を発掘した。
ここ数年はDirectXもすっかり疎遠になっている。
最後に触ったのはPCではなく360だったかな。
懐かしいなぁとパラパラめくりつつ、なんとなく昔のブックマークから
shi3zさんのところを見に行ったりしてみた。
相変わらずご活躍されているようでなにより。
裏CEDECやXFC東京で数回拝見した程度なんだけど記憶に残っている。
XFCといえばnekoさんやMasaさんkanoさんを筆頭に、とんでもない面子が
集結した会合だった。
余談はさておき、記事を読む進めていると衝撃の内容が・・・。
川西裕幸さんがお亡くなりになったそうだ。
私はただのDirectXを利用する1ユーザだったに過ぎないわけだけど
当事はBio100%の掲示板やBBXとか、いわゆる狭いコミュニティ界隈で
ユーザ同士が情報を共有する程度と極めて情報が不足していた。
GDCやGamasutraのスライドにSIGGRAPHの論文などもあるにはあったが。
DirectX6-7あたりからかな、この方が公式でDirect3Dまたは3Dに関連する記事を
精力的に更新していた記憶がある。
SDKも当事は英語ヘルプしかないか僅かな部分だけ翻訳されている程度だったのが
この頃あたりから日本語ヘルプがほぼリリースと同時に出ていたと思う。
shi3zさんのところにも書いているが、その後も著名な洋書の翻訳監修として名前は必ず見かけた。
所有している書籍を見渡しただけでも簡単に目に留まる。
(そういえばnVidiaの人をCEDECに引っ張ってきたのはこの方なのかな)
Microsoft社にはエバンジェリストという役職がある。
(wikiを見るまでいわゆる肩書きかと思っていた)
本当にそのとおりの伝道師といえるんじゃないだろうか。
謹んでお悔やみを申し上げますとともに、心からご冥福をお祈りいたします。
2012年3月2日金曜日
デバッグ表示
息抜き。
streamもいいけどAndroidのアレも結構好きなんだよなぁということで。
本来は第一引数がタグ指定だけど__FUNCTION__を使ってみたかっただけ。
使い方は下記のような感じ。
コンソールへの出力イメージ。
main関数内の該当行から呼び出しただけなので有り難味が・・・。
ソースはこちら。
streamもいいけどAndroidのアレも結構好きなんだよなぁということで。
本来は第一引数がタグ指定だけど__FUNCTION__を使ってみたかっただけ。
// *.h #if defined(LOG_ENABLE) && defined(LOG_E_ENABLE) #define Log_e(fmt, ...) \ log_fprint(stderr, "E/" ## __FUNCTION__, __FILE__, __LINE__, fmt, ## __VA_ARGS__) #else #define Log_e(fmt, ...) (void)0 #endif // defined(LOG_ENABLE) && defined(LOG_E_ENABLE) // *.cpp #include <stdio.h> #include <stdlib.h> #include <stdarg.h> static char _buff[512]; static char _filename[256]; static char _ext[5]; void log_fprint(FILE* file, const char* func, const char* filename, int line, const char* format, ...){ // Windowsの__FILE__はフルパスらしい _splitpath_s(filename, NULL, 0, NULL, 0, _filename, sizeof(_filename), _ext, sizeof(_ext)); va_list args; va_start(args, format); sprintf_s(_buff, sizeof(_buff), "%s %s%s(%6d): %s", func, _filename, _ext, line, format); vfprintf_s(file, _buff, args); va_end(args); }
使い方は下記のような感じ。
Log_e("hogehoge\n"); Log_e("hoge %s bar = %d\n", "foo", 10);
コンソールへの出力イメージ。
main関数内の該当行から呼び出しただけなので有り難味が・・・。
ソースはこちら。
2012年3月1日木曜日
COLLADA (4)シーングラフ
<scene> <instance_physics_scene> <instance_visual_scene> <instance_kinematics_scene> <extra> <instance_visual_scene> sid(optional) name(optional) url <extra> <library_visual_scenes> id(optional) name(optional) <asset> <visual_scenes> <extra> <visual_scene> id(optional) name(optional) <asset> <node> <evaluate_scene> <extra> <node> id(optinal) name(optinal) sid(optinal) type(optinal) layer <asset> transformation_elements <Lookat> <matrix> <rotate> <scale> <skew> <translate> <instance_camera> <instance_controller> <instance_geometry> <instance_light> <instance_node> <node> <extra> <library_nodes> id(optinal) name(optinal) <asset> <node> <extra>
<extra>は実質アプリケーション次第なので無視。
<asset>はこれといって重要なケースが今のところ見つからないので無視。
(optinal)も一部を除いて実質無視。
(1) <scene>→<instance_visual_scene>::url
(2) <visual_scene>
(3) <node>
階層構造
root:<visual_scene>
他は<node>を入れ子とした親子関係
<node>自体は特に問題ないが<instance_node>に注意。
多分1以上存在していれば<library_nodes>が出現するはず。
エイリアスとなるので生成、破棄はNG。
レイヤー構造
<node>::layer
ケース1:"" ... 空(無所属)
ケース2:"hoge" ... 1グループ(hoge所属)
ケース3:"hoge foo" ... 複数グループ(hogeとfoo所属)
モデラなら必須だが。
デフォルトは空="NODE"
それ以外は"JOINT"
まだ見てないがスキン関連か?
COLLADA (3)テクスチャマッピング
次に取り掛かるのはテクスチャ周り。
<library_effects>
<library_images>
<library_materials>
このあたり。
その前に避けて通れない画像の読み出しがある。
COLLADAのコンセプトとして多種多様な画像を想定しているわけなので
個々で対応していられない。
ここはオープンソースの享受を受けようというわけでOpenCV。
これもいつの間にか色々進化を遂げていて、Win、Linux、Mac、Android!まである。
単体で遊んでも面白そう。
・・・遊びそうになったので我慢してCOLLADAに戻る。
バイナリ配布も行っているようだが、VCに関しては2008(VC9)と2010(VC10)のみ。
当方は2005(VC8)ユーザなのでビルドするしかない。
今時2005なんて使ってる人いるんかと気が引けるが、素敵な情報があった!
ちゃちゃっと環境が整った。
[追記]
collada周りは無視でOpenCVを利用したテクスチャマッピングが正しくできるかのテスト。
モデルを作ろうとしたが、私にとってのBlenderはオーパーツそのものだった。
というわけでメタセコイア→Blender→Colladaのコンボ。
どうせならいい感じのモデルを表示してみたいと物色したら・・・
Paletteというサイトの方のをお借りすることにした。
特に問題なく表示はできているようだ。
OpenCVとOpenGLの相性はかなりいい。
画像ロード~テクスチャバインドまで秒殺できる勢い。
[追記その2]
<library_geometries>から直接辿れる限界がきたようだ。
<library_images>は独立してるからいいとして、
メッシュのプリミティブが参照しているマテリアルを辿るには基本的に
<library_visual_scenes>からでないと無理そう。
<library_visual_scenes>→<node>→<instance_geometry>→<bind_material>
ここから
<library_materials>→<library_effects>
ただ、モデルによっては必ずしも<bind_material>の中身があるわけでもないらしい。
サンプル数が少ないが、上記で辿れない場合は直接
<library_materials>→<library_effects>
か?
また、静的なモデルの最低限の情報は
<library_effects>
<library_images>
<library_materials>
<library_geometries>
<library_visual_scenes>
<scene>
というところか。
作戦の練り直しだな。
<library_effects>
<library_images>
<library_materials>
このあたり。
その前に避けて通れない画像の読み出しがある。
COLLADAのコンセプトとして多種多様な画像を想定しているわけなので
個々で対応していられない。
ここはオープンソースの享受を受けようというわけでOpenCV。
これもいつの間にか色々進化を遂げていて、Win、Linux、Mac、Android!まである。
単体で遊んでも面白そう。
・・・遊びそうになったので我慢してCOLLADAに戻る。
バイナリ配布も行っているようだが、VCに関しては2008(VC9)と2010(VC10)のみ。
当方は2005(VC8)ユーザなのでビルドするしかない。
今時2005なんて使ってる人いるんかと気が引けるが、素敵な情報があった!
ちゃちゃっと環境が整った。
[追記]
collada周りは無視でOpenCVを利用したテクスチャマッピングが正しくできるかのテスト。
モデルを作ろうとしたが、私にとってのBlenderはオーパーツそのものだった。
というわけでメタセコイア→Blender→Colladaのコンボ。
どうせならいい感じのモデルを表示してみたいと物色したら・・・
Paletteというサイトの方のをお借りすることにした。
特に問題なく表示はできているようだ。
OpenCVとOpenGLの相性はかなりいい。
画像ロード~テクスチャバインドまで秒殺できる勢い。
[追記その2]
<library_geometries>から直接辿れる限界がきたようだ。
<library_images>は独立してるからいいとして、
メッシュのプリミティブが参照しているマテリアルを辿るには基本的に
<library_visual_scenes>からでないと無理そう。
<library_visual_scenes>→<node>→<instance_geometry>→<bind_material>
ここから
<library_materials>→<library_effects>
ただ、モデルによっては必ずしも<bind_material>の中身があるわけでもないらしい。
サンプル数が少ないが、上記で辿れない場合は直接
<library_materials>→<library_effects>
か?
また、静的なモデルの最低限の情報は
<library_effects>
<library_images>
<library_materials>
<library_geometries>
<library_visual_scenes>
<scene>
というところか。
作戦の練り直しだな。
登録:
投稿
(
Atom
)