2014年12月26日

画像の極座標変換について その2

今頃気づきましたが、画像の極座標変換のところにコメントをいただいていました。手法など全然説明していないので自分で読んでもどうやっていたのか良くわからないですね。というわけで一応解説とOpenCV使ったサンプルソースコードを作ってみました。

polar_image_001.png

[1]を上の式で変換した結果(polarTest)
polar_image_dst.png

polar_image_002.png


[2]"Photo by DAVID ILIFF. License: CC-BY-SA 3.0"を上の式で変換した結果(polarTest2)
polar_image_dst2.png

ソースコード
opencv_polar.cpp
(2015.10.29追記:atan2(dx, dy)はatan2(dy, dx)の間違いです)

[1] http://www.mvision.co.jp/WebHelpIM/_RESOURCE/Filter_Mvc_Polar.html
[2] Helvellyn Striding Edge 360 Panorama, Lake District
web拍手 by FC2
posted by シンドラー at 17:49 | Comment(0) | TrackBack(0) | Image Processing | このブログの読者になる | 更新情報をチェックする

2014年12月25日

Oculus SDK 0.4.1から0.4.4への修正点メモ(OpenGL用)

0.4.4で速くなったり安定したりというお話を聞いたので、そろそろバージョンアップしてみました。DirectXやUnityのお話の気もするので、OpenGLでその恩恵が受けられるのかどうかわかりませんが。

0.4.1のプログラムをコンパイルしようとしたらエラーがでたので、修正点のメモです。GLFW3を使う場合は、[1]を使えばそのままコンパイル/実行できます。試していないですが、OculusRoomTinyのOpenGLバージョンが[2]にあるので、参考になると思います(Oculus SDK付属のサンプルはDirectXだけになってたみたいなので…)。

変更点1 RTSize -> BackBufferSize
[1]にも書かれていますが、変数名が変わったようなので修正します。
    ovrGLConfig cfg;
    cfg.OGL.Header.RTSize = OVR::Sizei(hmd->Resolution.w, hmd->Resolution.h);
        ↓
    cfg.OGL.Header.BackBufferSize = OVR::Sizei(hmd->Resolution.w, hmd->Resolution.h);

変更点2 ovrHmd_GetEyePose -> ovrHmd_GetEyePoses
0.4.1では片目毎にovrHmd_GetEyePoseをしていたのですが、ovrHmd_GetEyePosesで一度に取得するようになったようです。
    ovrHmd_GetEyePoses(hmd, frameIndex, eyeRenderOffset, eyeRenderPose, NULL);

変更点3 ViewAdjust -> HmdToEyeViewOffset;
変更点2にも関係しますが、0.4.1ではViewAdjustで左右目のIPD差?を取得できていたのですが、HmdToEyeViewOffsetという名前に変わっていました。
    ovrVector3f eyeRenderOffset[2];
    eyeRenderOffset[ovrEye_Left] = eyeRenderDesc[ovrEye_Left].HmdToEyeViewOffset;
    eyeRenderOffset[ovrEye_Right] = eyeRenderDesc[ovrEye_Right].HmdToEyeViewOffset;

後、[1]では大丈夫だったのですが、自前のglutバージョンを0.4.4対応に修正したものでは、health and safety warningをAPIで非表示にした場合に、トラッキングのエラー?が出て画面が真っ暗になってしまったため、[3]を参考に無理やり非表示にしました。

[1] Simple, one page, OpenGL example (0.4.4)
[2] Oculus SDK 0.4.4-beta OpenGL Demo
[3] Oculus Rift SDK 0.4.3bでhealth and safety warningを非表示にする方法
web拍手 by FC2
posted by シンドラー at 08:15 | Comment(0) | TrackBack(0) | Oculus Rift | このブログの読者になる | 更新情報をチェックする

2014年12月09日

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

あぴミクさんモデルでのテストが終わりました。OpenCLを使用しても、1頂点1秒とすると、2万頂点で2万秒(6時間弱)ほどかかりますので、もうちょっと高速化が必要かもしれません。

実行結果

今回は半球ではなく全球で遮蔽情報を計算しましたが、本来は半球で計算するべきかもしれません。後、完全に遮蔽されている頂点があると真っ暗になり、その頂点に隣接する面が必要以上に暗くなってしまっていますので、真っ暗な場合にもある程度0番目の項にだけ値を設定する等の工夫が必要かもしれません。



たまに表示されないみたいなのでその場合はDOWNLOADを押してみてください。

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

2014年12月06日

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

遮蔽情報の計算が怪しかったので修正してみました。

SH_GSL07_001.png

SH_GSL07_002.png

実行結果

床を平面で作ったので、端っこの頂点がほぼ遮蔽されずに明るくなりすぎていますが、何となくそれっぽくできていると思います。計算に時間がかかりますが、あぴミクさんのモデルでの再計算をやりたいと思います。



動的変形に対応した手法までやる気力がないので、あぴミクさんでうまく行ったらとりあえずは大体試せたことになりますかね。
web拍手 by FC2
posted by シンドラー at 00:14 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする

2014年12月03日

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

前回の続きです。

球面調和関数の係数を線形補間すると、滑らかに変化するのかどうか試してみることにしました。

昼・夕方・夜っぽい3枚のパノラマ画像を[1]から使用させていただき、ぞれぞれ3次の球面調和関数近似を行い、係数を線形補間してみました。

実行結果

背景はmix関数で混ぜているのですが、何かおかしいですね。雰囲気的にはうまくいっているような気はしますが、どちらかというとモデルの頂点毎の遮蔽情報の計算が怪しそうです。

背景と遮蔽情報の内積のみ

テクスチャの色と上記の混合


[1] http://www.nicovideo.jp/watch/sm10968092

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

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 | このブログの読者になる | 更新情報をチェックする

2014年10月27日

Normal Matrix についてのメモ

最近少しOpenGL 4.3辺りを試しているのですが、GLSLも結構変わっていますね。gl_ModelViewMatrixとかgl_NormalMatrixとか廃止?非推奨?になってるんですね。そういうわけで、uniform変数として渡す必要があり、glmを使ってModelViewProjection行列などは比較的簡単に作れたのですが、gl_NormalMatrixって何?って感じでした。調べてみると、ModelView行列の左上3x3の逆行列の転置で良いと書いていて、なんでそんな面倒な計算がいるのかなと思ったのですが、[1]などに説明がありました。

接線ベクトルと法線ベクトルの内積は本来0(直交)ですが、Model行列にスケーリングの要素が入っているなど、ModelView行列の3x3成分が直交基底になっていない場合は、内積が0にならなくなります。そのようなわけで、この3x3の行列を法線ベクトルにかけた後も法線ベクトルと接線ベクトルが直交するように導いていくと、最終的に逆行列を計算してから転置するということになるみたいです。

また、LookAt関数で計算したView行列は直交行列で、Model行列も回転と平行移動しかなければ直交行列なので、そういった場合は単純にModelView行列の3x3成分を使ったので構わないということのようです。

実行結果

トーラスに対してX軸方向に2倍するModel行列を使用する場合で試してみました。

ModelView行列の3x3をそのまま使った場合

NormalMatrix_002.png NormalMatrix_004.png

逆行列を計算して転置した場合

NormalMatrix_003.png NormalMatrix_005.png

ちゃんとしたNormal Matrixを使わないと周辺が暗くなってしまっていますね。スケーリングやせん断等はあまり使わないかもしれませんが。まぁこれでgl_NormalMatrixが使えなくても大丈夫ですね。

[1] http://www.lighthouse3d.com/tutorials/glsl-tutorial/the-normal-matrix/

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

2014年10月24日

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

[1]の球面調和関数の説明に、いびつなウニという言葉が使われていていい表現だなと思いました。というわけで、いびつなウニを適当に表示してみることにしました。

入力画像として、[2]を使用させていただいております。[2]は"Photo by DAVID ILIFF. License: CC-BY-SA 3.0"ですので、加工したこのページの結果画像も同じライセンスになります。

実行結果

原画像から点をサンプリングして、明るさ(HSVのV)を中心からの距離にして描画したものです。カラーバッファをクリアせずに毎フレーム40000点ずつGL_POINTSで色はglColor4f(テクスチャのRGB,α=0.2);でやってます。ウニというより爆発っぽいですね。

sh_point_001.png

以下、これを球面調和関数で圧縮して適当な次数で展開したものを同様の方法で描画したものです。係数はRGBでやっていますので、実際には×3になります。

sh_point_002.png
maxL=0, 係数1個。ただの球です。

sh_point_003.png
maxL=1, 係数4個

sh_point_004.png
maxL=2, 係数9個

sh_point_005.png
maxL=3, 係数16個

sh_point_006.png
maxL=4, 係数25個

sh_point_007.png
maxL=5, 係数36個。maxLが3〜5ぐらいで十分と[1]には書かれていますね。

sh_point_008.png
maxL=6, 係数49個

sh_point_009.png
maxL=7, 係数64個

sh_point_010.png
maxL=8, 係数81個

sh_point_L20.png
maxL=20, 係数441個。このぐらいになるととげとげしすぎて遠ざかっている気がしますね…。遮蔽情報との内積を取る分には問題ないのでしょうか…。やっぱり3〜5ぐらいでいいのかもしれません。

[1] マイナビ:3Dグラフィックス・マニアックス 第68回
[2] WikipediaのPanorama画像
web拍手 by FC2
posted by シンドラー at 19:26 | Comment(0) | TrackBack(0) | OpenGL & Metasequoia | このブログの読者になる | 更新情報をチェックする