この記事は 本篇 のつづきです(ページが重くなりすぎたので分割しました)。
【もくじ】
はじめに
今回の出展作品は、一見、立方体をくるくる回すだけの比較的簡素なスケッチに見えます。
しかしながら、制作は Processing.js のバグとの闘いの連続であり、コードにはあらゆる苦悩の蹟が凝縮されています。
2年ぶりくらいにProcessing触っているけど、JavaScriptモードの制限がかなりきつい(・ω・ lll)
かつて(Javaの頃)に僕が得意としていたエフェクトとかがことごとく使えなくなってる(´・ω・`)
— たーせる (@tercel_s) 2014, 11月 5
この問題に直面したのがおよそ1年前。2014年のAdvent Calendarでは技術不足のため、3Dの質感表現のほぼすべてを犠牲にした失敗作を投稿してしまいました。
今回はいろいろ改善できたので、ひとまず記録としてここに残しておこうと思います。
でこぼこ感のつくり方
概要と実装手順
今回のスケッチでは、見る角度によってテクスチャを動的に変化させることで「でこぼこ感」を表現しています。このテクニックはバンプマッピングと呼ばれており、手法としては比較的古典の部類に入ります。
以下に、効果がわかりやすいサンプルを置いておきます。激しく重いと思いますが。
バンプマッピングの実装手順は、一般的に以下の通りです。
- 高さマップを作る
- 高さマップを法線マップに変換する
- 法線マップからピクセルごとの陰影情報を計算する
- ピクセルごとの陰影情報を、面のテクスチャと合成する
以下に処理の詳細を示します*1。
高さマップを作る
高さマップとは、表面の擬似的な高さ(でこぼこ)情報が記録された特殊なテクスチャのことです。下図のように、高さが高いほど白く、低いほど黒くなります。
今回用意した高さマップはこんな感じです(わかりやすいようにグリッドを追加)。
高さマップを法線マップに変換する
法線マップとは、テクスチャ画像の全ピクセルの法線ベクタを格納した2次元配列のことで、先ほどの高さマップから導出できます。
はじめに、テクスチャ座標 における高さマップの値を、 と書くこととしましょう。ちなみに実装上の話ですが、の値域は0
〜0xff
にしています(真っ黒なときは0
、真っ白なときは0xff
を取ります)。
における軸方向の変化は、左右の高さの差の平均をとって以下のように求めます。
また軸方向の変化も同様に計算できます。
上式より、あるテクスチャ座標 における 、各軸の傾きベクタを求めます。
軸方向の傾きベクタを、軸方向の傾きベクタをとすると、それぞれ以下のように計算できます。
法線は、上記の傾きベクタに直交します。
具体的には、以下のように外積を計算することでを得ます。
全ピクセルに対して法線を計算し、その結果を2次元配列に格納すれば法線マップのできあがりです。
法線マップからピクセルごとの陰影情報を計算する
ピクセルごとの法線がわかれば、あとは平行光源の方向と法線ベクタの内積を計算することで、陰影の濃淡値を決定できます。
このへんは(より基礎的な)平行光源の計算の議論なので、詳しい解説は割愛します。
ピクセルごとの陰影情報を、面のテクスチャと合成する
あとは、テクスチャ画像に対して濃淡値を合成することで、でこぼこ感のある外観を作ることができます。
……と、いかにも簡単に説明しましたが、実は一筋縄ではいかないのが Processing.js のつらいところ。
バンプマッピングを実装する際に泣かされた Processing.js のバグとその回避策を次のセクションで紹介します。
Processing.jsのバグと回避策
今回は以下2点のバグが制作上の障壁となりました。
- ライティング(シェーディング)のバグ
- テクスチャの書き換えができないバグ
それぞれサンプルつきでくわしく見ていきましょう。
ライティング(シェーディング)がレンダリングに反映されないバグ
Processing.js の3Dモードには、平行光源を設置した環境で、テクスチャの陰影が正しくレンダリングされないバグがあります*2。
再現コードは以下の通りです。
立方体にチェックパターンのテクスチャを貼り、正面から平行光源を当てています。が、実行すると全く陰影がついておらず、のっぺりした見た目になってしまっています。
上記バグを、自力で陰影計算することにより回避したのがコチラ。
仕掛けは簡単で、毎フレームtint()
を使ってテクスチャの明暗を設定しているだけです。
今回は実装も簡単ですし、処理自体もそこまで重くはないと思います。バグフィックスされるまではこの回避策で乗り切れるのではないでしょうか。
その他がんばったこと
あとがき
というわけで、3歩進んで2歩下がるような開発でしたが、とりあえずなんとか形になってよかったです。わはー。つかれた。
謝辞
今回のキーワード「あたたかみ」「やわらかさ」「でこぼこ感」は、かべみさん(@sn2562)の活動からのインスパイアです。いつもありがとうございます。