この記事は WebGL Advent Calendar 2018 25日目の記事です。
Tokyo Demo Fest2018の作品を作るに当たり目指したこと出来なかったことを書こうと思います。
概要
まずは TDF2018に応募した作品です。
https://www.shadertoy.com/view/MlyBRd
※非常に重いです
要素はたった2つ
- 雲
- 戦闘機
これだけです。
雲については以前書いた レイマーチングで潜れる雲を作る を見てください。
ここでは戦闘機についてあれこれ書きます。
戦闘機
作品ではいくつか戦闘機が通過するだけでしたが、本来はこれらのドッグファイトを表現したいと思ってました。
しかし、一般的なレイマーチングでは難しい表現があります。
それが物量と地平線です。
レイマーチングというと同じものを大量に表示するのが得意なイメージがありますが、
大量に表示出来るのはmod関数で量産出来る幾何学的な模様だけです。
戦闘機は(本来の目標では)空間を等間隔に並んで飛ぶわけではなく、敵機の後ろに張り付いたり逃げ回ったりするわけですからその分だけ戦闘機の距離関数の実行回数は増えていきます。
これは戦闘機の形状が複雑であれば複雑であるほど計算量が倍増していきます。
そこでざざーっと考えたのが戦闘機全体をすっぽり覆うだけの球体を定義し、その球体にレイがヒットしたら球体の半径分レイを戻し、そこからレイマーチングを開始するというものです。
当たったらdepth color normalを返して他の色と合成します。
まぁifやらなんやら使いまくるので実際のところどっちが軽量かどうかは測定しないとわからないですが
メリットがいくつかあります。
メリット
レイがオブジェクト周辺を横切っても霞まない
レイマーチングの特徴として描画するしないにかかわらずオブジェクト付近を通過するとレイのマーチ幅が減ります。
レイが戦闘機に届かなければ当然戦闘機は画面に表示されません。
これは冒頭のような手前から奥に見せたいシチュエーションを再現する際に非常には不利です。
mod関数を使える場合は一回の距離関数で判定出来ますが、戦闘機が十何機出て機銃やらミサイルやら表現しようと思ったらタダじゃすまないでしょう(多分)
Farを無視出来る
レイマーチングは上記の理由からそもそも遠景の描画には向いてません。
多くのレイマーチング作品でもカメラから一定距離離れると被写界深度Fogで誤魔化しているのがわかると思います。
しかし、この方法であればどんなに遠方であってもしっかり描画します。
オブジェクトの整理がしやすい
コードの書き方の問題になりますが、いくつもの距離関数の中に放り込んだレイが誰のかわからない距離やら法線やらを拾って帰ってくるのは稀に書いてる本人ですらそれがなにか忘れます。
遠景を表現したい
こちらは非常に簡単です。
TDF用の作品を作ったときの過程で生まれた作品です。
https://www.shadertoy.com/view/MtyfRc
考え方は上記と同じで、レイが付近のオブジェクトに引っ張られるなら当たるところまで無視ればいいじゃないというものです。
シェーダー芸を生業としている人にとっては言うまでもないテクニックだと思いますが簡単に図解を作りました。
他
来年はsin波を使った無限に続くterrainで遠景を作ろうと思います