2014年11月27日

GSLを用いた球面調和関数の計算 その5

前回の続きです。

とりあえず単純なオブジェクトということで、球を使ったテストをしてみました。遮蔽情報が必要で、本来であればレイを飛ばして遮蔽するかどうか確認、といったことをしないといけないのですが、手抜きで上(法線方向)だけ遮蔽されておらず、そこからだんだん暗くなる下記のものをベースに、法線ベクトルに応じて前回の係数回転をさせることにしました。

          原画像                 3次(係数16個)で圧縮/展開した画像
SH_GSL05_003.png      SH_GSL05_004.png

環境マップには、わかりやすいように下記のような画像を作成しました。

          原画像                 3次(係数16個)で圧縮/展開した画像
SH_GSL05_001.png      SH_GSL05_002.png

実行結果

反射なのでわかりにくいですが、正しく動作していそうです。

前回からZ軸を上方向にしたせいか、Y軸とZ軸が入れ代わってしまっているので、↑はカメラを寝させているような状態になってしまっています。その辺は修正しないと駄目ですが、とりあえず回転含め球面調和関数が使えるようになったかなと思います。
web拍手 by FC2
posted by シンドラー at 03:23 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2014年11月22日

GSLを用いた球面調和関数の計算 その4

球面調和関数の続きです。以前まで極座標でθはY軸方向を基準にしていましたが、参考文献などではZ軸方向が基準になっているものが多かったため、それに合わせることにしました。

sh_rot_004.png

で、今回は回転のお話です。自分は遮蔽情報をオブジェクト座標系で計算して頂点毎に持たせていますので、回転等のモデリング変換を行った場合には、遮蔽情報の係数を回転させてあげる必要があります。

参考文献[1]では、回転行列RからZYZオイラー角を取得し、SH回転行列を作成して回転を行っています。とりあえず[1]を参考に実装していくことにします。ただ、自分で実装しなくても[2]にソースコード付きのライブラリがあります。こちらにはSHEXP技法の計算なども含まれているようですが、今回はSH Rotationを参考にさせていただきます。

まずは回転行列からZYZオイラー角の取得です。

sh_rot_005.png

sh_rot_006.png

sh_rot_007.png

上にも書いてますが、[1]と結果が違うのでどうなのでしょうね。続いて回転です。オイラー角が取得できたら、それを使って[1]に載っている式で回転させます。順番は違いますが行列自体は[1]のものでうまくいったのでこれも謎ですね。ちゃんと行列を自分で導出すればわかるのかもしれませんが。

sh_rot_008.png

実行結果

適当に回転行列を作って、球面調和関数の係数を回転させてみました。一応色々な角度を試してみましたが、ちゃんとZ軸方向を向いてくれています。

sh_rot_001.png

sh_rot_002.png

sh_rot_003.png

次は実際のモデル等で試してみますかね。

[1] http://www.cs.columbia.edu/~cs4162/slides/spherical-harmonic-lighting.pdf
[2] http://www.pyramid-inc.net/technical


web拍手 by FC2
posted by シンドラー at 01:45 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2014年11月14日

OpenGL 4.xのテッセレーションのテスト

いつの間にか11月も半分終わっているとか…。困ったものです。前回に引き続き、OpenGL 4.x系のテストです。最近?の機能といえば、テッセレーションだと思いますが、単純にメッシュを細かくしただけでは滑らかになるだけなので、やはりDisplacement Mappingとかやらないと恩恵が分かりにくいのかなと思いました。

まずはPer-vertex displacement mapping+bump mappingのテストです。頂点シェーダでディスプレイスメントマッピングをする場合、単純に頂点座標を法線ベクトル方向に高さ分だけ移動させるだけで行けると思います。

 vec4 tex = texture(NormalMapTex, VertexTexCoord);
 float height = SCALE * tex.a + OFFSET;
 vec4 pos = ModelViewMatrix * vec4(VertexPosition+height*VertexNormal, 1.0);

NormalMapTexは、rgbに法線ベクトル、aに高さ情報を格納したテクスチャです。法線マップがあるので、移動方向も法線マップの方向にした方がいいのかなと思って、法線マップをオブジェクト座標系に変換してみましたが、変なことになってしまったので普通の頂点法線方向がいいみたいでした。

これだと、頂点だけ移動して、法線ベクトルが正しくなくなるので、バンプマッピングで法線ベクトルはフラグメントシェーダ側でテクスチャから取得することにしました。

バンプマッピングについては[1]などを参考にさせていただきました。

実行結果
[1]の高さマップを反転して法線マップを計算したものを使用させていただいております。

約8万ポリゴン
displacement_001.png

111ポリゴン
displacement_003.png

十分ハイポリならちゃんと凹凸しますが、頂点ベースのディスプレイスメントマッピングでは、頂点しか移動できませんので、ローポリだと全然出っ張りません。そこで、視差遮蔽マッピングなど、ピクセルベースでのディスプレイスメントマッピングが色々提案されているようです。資料としては[2]が充実していました。

で、時代はテッセレーション+ディスプレイスメントマッピングということのようなので、[3]のソースコードを色々変更してTessellation + Displacement mapping + Bump mappingを試してみました。分割した頂点の法線ベクトルをどう計算すればいいのかがよく分からなかったので、もうバンプマッピングでやってしまえばいいか、ということにしています。

基本的には、テクスチャで法線マップと高さマップ、VAOで法線だけでなく接線ベクトルも渡すようにして、TES内で高さマップから頂点を移動させたりバンプマッピング用に視線ベクトルや光原ベクトルを回転させたりして、フラグメントシェーダ内で法線マップから法線ベクトルを取得して色出力をしました。

また、TCSの中のforループで値代入しているだけなのに全部0になっていて、forループ使わずに代入したらちゃんと動いたり、良くわからないことも色々ありました。

その他参考文献として[4][5]などがあります。ジオメトリシェーダで法線ベクトルを計算すればいけるかなと思ったのですが、3頂点からだと面の法線ベクトルしか計算できないようでしたので、とりあえず諦めました。ジオメトリシェーダで頂点法線を求める方法もあったはずだとは思います。

実行結果

111ポリゴンのものを分割しています。流石に少なすぎますが、1000ポリゴンぐらいあれば今回の対象では問題ないレベルになると思います。対象や法線マップと高さマップの解像度などにもよると思いますが。

レベル1
displacement_005.png
displacement_006.png

レベル8
displacement_007.png
displacement_008.png

レベル32
displacement_009.png
displacement_010.png

レベル64
displacement_011.png
displacement_012.png

このPCでは64が最大レベルみたいでした。ここまで分割すると元が荒いポリゴンでもワイヤフレーム表示でほぼ隙間がなくなるほどですね。あと面倒だったので光原計算はかなり適当でちゃんとしたバンプマッピングになっていないと思います。

[1] http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20051014
[2] Displacement Mapping on the GPU - State of the Art
[3] Tutorial 31 - PN Triangles Tessellation
[4] GLSL Tessellation Displacement Mapping
[5] OpenGL でテセレーションのシェーダー(TCS,TES)を使う
web拍手 by FC2
posted by シンドラー at 15:08 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする