頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


OpenGLのシャドウマッピング

OpenGLで影を付けてみようってお話。


↑とりあえずこんな感じになった。一番最初は光源と同じ角度で見てて、その後ジェスチャー(パン)で視点を動かしてる。デバイスはiPhone 5s、iOS 7.1.2
テクスチャのサイズは1024x1024でやってる。
それにしても、、、汚いね。
実際に自分でやってみるとキレイで自然な影っていろいろと難しいんだなとわかったよ。おかげで最近は3DのCGでキレイな影を見るとおおお〜!美しい〜!と見入ってしまうことがあるんだ。

影を付ける手法はデプスバッファシャドウとか言うそうな(いろいろあるみたい)。
wgld.org | WebGL: シャドウマッピング |
↑原理的にはこのサイトがとても参考になったよ。

処理の流れは
光源から見てレンダリングして深度情報をテクスチャに書き出す(もちろん表示しない=オフスクリーンレンダリング)。
カメラから見たシーンを描画、この時先ほどの深度情報と比較して影になるか否かを判断する。
とまあどこでも書いてるような記述だけど、いざ自分で実装しようとするとえらく苦労したよ。

はまったところをいくつか書いておこうっと、、、はまった、というか今でもよくわからなかったりするんだけどさ。

そもそも深度情報をどうやって得るの?って話なんだけど、glTexImage2Dでテクスチャに出力するのはいいとして、何を出力するのかよくわかんない。
GL_UNSIGNED_BYTEでGL_DEPTH_COMPONENTを出力する!って記述をよく見るんだけど、何がよくないのか俺コードではフレームバッファのチェックでエラーがでちゃう。
いや、そもそもGL_DEPTH_COMPONENTで深度が書き込まれるというならシェーダで何するのよ?

結局、テクスチャへの出力は
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  outputLength, outputLength, 0, GL_RGBA,GL_UNSIGNED_BYTE, NULL);
こんな感じでGL_RGBAの値(4バイトも要らないんだけど)を書き込めるようにしといて、シェーダで深度情報(0から1)を計算して出力するようにした。なんか違うような気がするんだけどねえ。


表示するピクセルの座標の変換は最初は難しそうだな、と思っていたけどやってみるとどうということでもなくて、ただ面倒なだけ。頂点シェーダからもらった座標に対してmodel view matrixとprojection matrixの逆行列でローカル座標に戻して、さらに光源から見た場合のmodel view matrixとprojection matrixをかけてやればいい、というだけ。
逆行列はGLKitのを使ってこんな感じで。
{
    bool invertible;
    GLKMatrix4 invModelViewMatrix = GLKMatrix4Invert(modelViewMatrix , &invertible);
    if(!invertible) {
       NSLog(@"modelViewMatrix is not invertible”);
    }
}
以外に難しいのが表示するピクセルが一番光源に近いのか?って判定をどうするか?って問題。
シェーダ内で光源から見た場合の深度値を計算して、テクスチャに記録されてる一番小さい深度値と比較するんだけど、highp float の比較なので丸められる分を考慮する必要もあり(うまい方法もありそうだけど)、それが適切でないとすごく不自然になったり汚くなってしまう。深度値が8バイト(256階調)ってのが問題なんだろうな。

いろいろと修正する余地がありまくりなんだけど、今回はこの辺で。



<< 色じゃない値をフラグメントシェーダで出力したい  TopPage  その手は桑名の蒸しはまぐり >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/914-c5c9f1b6




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad