スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

全方位シャドウマップ

全方位シャドウマップ!
5日ほど前からの怒涛の流れはこの記事を書くためのものだったりします。

そしてもってこの機能を実装したのは「前からずーーっと言っているあるプロジェクト」のためのものだったりします。まだひっぱっています。(まだ出来ていないんじゃ?って香りを嗅ぎ分けたあなた!スルーですよ)

ってことでサックリ実装したかったのですが、なかなか大変でした。
機能としては「キューブマップを利用したシャドウマップ」です。
点光源が使えますね。なんなく出来るとおもったのですが詰まりました。

というのもまずこれ
cube8.jpg
以前紹介したこの記事の絵にレンズを加えます。

このレンズってのはただのイメージで所謂「プロジェクション行列」です。
キューブマップは色をもらうときにベクトルが必要というのは昨日話した内容です。
このベクトルってのはシャドウマップならば光からAの位置を指しますね。
ところがこのベクトルと実際書かれたキューブマップの間にプロジェクション行列を挟んでいます。

どういう関係になっているのかわかっていないと実装できないですよね・・・
しかーも!これまた資料が皆無。
ため息ついて実験したわけです。

結論:視野角90度なら歪みが0です。

そりゃ予想はできますよ?でもあとからこのズレの知識がないのに実装していて影響が別のところにでないとも限りません。
試す作業が大変だったのです。

まず
目の前にシャドウキューブマップ(の1面)を置きベクトルを作ることから始めました。
任意の6面のうち一つを選ぶにはこれまたキューブマップを使いました。
6方向に0,127(128),255で色分けしたキューブマップをエフェクトに読み込ませておきます。
そんでもって「書き込み点のワールドpos-LightPosition」をtexCUBEに渡してやりどの面のキューブマップを使っているか?とUPの方向などを持ってきます。

これでEyeとAtとUpが分かるので昔書いたように現在の書いている点が使用したであろうView行列がわかります

float4 uv = mul(mul(mul(pos,World),LightView),LightProjection);
float4 LightCubeVec = float4(uv.x/uv.w , uv.y/uv.w ,-1,1);


これで目の前に-1~1にぴったりのキューブマップの一面が展開された状態で、その点がXとYのどこにあるかを示してくれています。
Z座標はとりあえず-1として原点からキューブに伸びたベクトルを作ります。

これだけでは目の前にある面がキューブの真上のものかもしれないので、とりあえずその面がどの面をむいているのか調べてベクトルに回転を加えます。

ここで少し詰まりました。
というのも上記で調べたUpベクトル(どこが上か?を指すベクトル)などからCosとSinを作って回転させようと思ったのですが、Cos(0)=1、90や-90は0、180は-1などの計算をさせるとところどころ近似値になって出てきます。さすがにこういう節目っぽい角度はぴったり来るだろうとたかをくくっていたのが失敗でした。
floatに対する小数点の制限?などが絡んでこのようになるのでしょうが(全く調べてないので別問題かもしれません)とりあえずこれを解決しなければなりません。

ただの調査であり、常に使用するならもっといい方法を考えようと思い、こうしました。
以下は使用しないほうがいいです。上下の面の生成の仕方がキューブマップの理解が乏しかったためにこのようなことが起きています。
本来そのまま上を向くべきなのですが、すべての面が左右逆になってほしい(他の実験も兼ねていた)ので少し仕様が理解しにくいかも。

VecCubeはキューブ面の向いているベクトル
Upはその上方向を表すベクトル

float c = -VecCube.z + (-Up.z * Up.z);
float s = VecCube.x * Up.y;
float4x4 RotateY = float4x4(c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1);
c = Up.y;
s = -Up.z;
float4x4 RotateX = float4x4(1, 0, 0, 0,
0, c, -s, 0,
0, s, c, 0,
0, 0, 0, 1);
LightCubeVec =mul(mul(LightCubeVec,RotateY),RotateX);

これで一応必要な実験ベクトルがでましたね。

あとはこのベクトルをtexCUBEに渡して得られた色描写点の位置-光源を渡して得られる色の相違を調べるだけです。

結果
cube2.jpg
取得した色を比べて違うところだけ黒になるようにしました。
プロジェクションは
Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(90), 1, 0.1f, 1000.0f);
で試しています。
MathHelper.PiOver2としてあっても同じ90度を指します。

っは!ここまで撮ったのに比較の45度とかの絵を撮影するの忘れてた!
立ち上げるの面倒なので察してください。
6面の正面に当たるところは綺麗ですが、角度が広がると一定角度から真っ黒になります。

90度でもよーくみると少し取得位置がずれているところが見受けられます。
理由は。。。。。。
なにかしら問題があったのでしょう。(遠い目)



さて。キューブマップに対してそのままベクトルを入れてやってもOKと分かればこっちのものです。
といってもパースティクティブキューブシャドウにするなら↑を参考に作り変えてください。

シャドウマップの鍵である深度の受け渡しがもうできそう!ってとこで、昨日の記事にもあったように面の方向がネックになってきます。
ライトからみた方向をその方向のキューブ面に張った場合
・ポジティブネイティブのXとZ面は左右が逆になる
・Y面はどちらも上下反転になる

結構問題があります。

解決策は色々あると思います。当初、
上下だけUp方向をいじってやり、どの方向も左右逆にはってやり取り出すときに反転させる。
という方法を使っていましたが。
キューブ面を生成するときに渡すView行列を変えてやり、すべての面が上下左右逆に撮影したうえで、張る面を逆(上面と下面の入れ替え)にしてやる→取り出すベクトルVを-Vで取り出す。
としました


POS-ライトのベクトルからキューブマップの方向を取り出す時、昨日の記事にもかぶるのですがもう一個のキューブマップを使いました。
round(2.0f*texCUBE(VecCubeSmp,-V)-1.0f)
などとしてやっているのですが、roundが気になりますよね。
色が
0=0
255=1
127か128=0に近いけど違う

という結果になります。
欲しいのは-1~1には変わりないのですが、0でないと困るので仕方なしのroundです。
もっといい方法があると思うのですが思いつくまではこれで我慢っと。


や、やばい。無駄に長い記事が今日もできてる・・・・

ねよっと

コメントの投稿

非公開コメント

プロフィール

あしゅ

Author:あしゅ
ぷぃぷぃ日常。
いつのまにか雑記ブログに。

カテゴリ
最新記事
検索フォーム
最新コメント
リンク
このブログをリンクに追加する
ブロとも申請フォーム

この人とブロともになる

カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。