-
Notifications
You must be signed in to change notification settings - Fork 389
Visualizer
この項目では、ステージの床 (オブジェクト名: Visualizer) の処理について解説します。
おおまかには、床はテクスチャ素材は使わず、ピクセルシェーダでパターンを生成しています。
反射の映り込みは Y 軸を反転したカメラでレンダリングした結果を用いて実現しています。
ピクセルシェーダで図形を描くのに distance function という手法を用いています。
これはその名の通り、現在のピクセルの位置と図形との距離を算出する関数です。
例えば円であれば以下のような式になります。
float circle(float2 pos, float radius)
{
return length(pos) - radius;
}
pos が円の内側であれば負に、外側であれば正になります。
画面左下が -1.0,-1.0、右上が 1.0,1.0 の領域に半径 0.5 で上の関数を実行し、円の内側だけを白くすると以下のようになります。
WebGL で実行
円の内側をフェードアウトさせてみます。
外円を 0.5、内円を 0.4 とし、その間を距離に応じて 白->黒 とグラデーションさせます。
アニメーションさせてみます。
デフォルトのシェーダのパラメータの中には時間が含まれています(_Time.y)。これに応じて中心からの距離を広げることでアニメーションを実現できます。
また、それだけだと一つの輪が広がるだけになってしまうので、距離を mod() で区切ることで繰り返す処理も入れます。
六角形も考え方は円と同じで、図形との距離を算出して可視化していきます。
六角形の式は以下のようになります。
float hex(float2 pos, float2 size)
{
float2 apos = abs(pos);
return max(apos.x-size.y, max(apos.x+apos.y*0.57735, apos.y*1.1547)-size.x);
}
円のアニメーションで少し触れましたが、mod() 関数を使うことで図形を繰り返すことができます。
例えば pos = mod(pos, 0.2) とすると pos は -0.2~0.2 の範囲を繰り返すことになるため、これと図形との距離を計算することで、結果として図形も繰り返されることになります。
このようにして六角形を並べてハニカム模様にします。
WebGL で実行
そして、広がる輪とハニカム模様の隙間との and を取ることで、光の溝を実現できます。
WebGL で実行
ステージ中央を中心にぐるぐる回っているリング群、これは円の変則パターンです。
中心からの距離を mod() で区切ることで年輪模様ができます。
WebGL で実行
リングの幅にフェードアウトを入れます。
abs(中心からの距離 - 太さ/2) で、各リングの幅の中心からの距離を得られます。これに応じてフェードアウトさせます。
WebGL で実行
角度に応じたフェードアウトを入れます。
atan(pos.y, pos.x) でそのピクセルの中心からの方向が取れるので、その角度に応じてフェードアウトさせます。
ついでにフェードアウトの角度を時間で変えることで回転するアニメーションも入れます
各リングの回転を (擬似) 乱数でずらします。
この乱数は各リング内においては同じ結果になる必要があります。このため、floor(中心からの距離 / リングの幅) (== n 番目のリング) を適当に hash した値を乱数として使いました。
そして最後に、BGM のボリュームに応じてリングの幅や色を変える処理を入れます。
これは reaktion のスペクトラム分析の結果をシェーダのパラメータに入れて、それをリングの幅や色の値に使うだけです。
六角模様とリングを組み合わせることで以下のような結果になります。(BGM との連動はこの例では入っていません)
WebGL で実行
大体ステージの床の模様と同じになっているのが見て取れると思います。
実際にステージに使われているものは最終的にブルームで光らせるため、かなり色を強くしています。
RGB: 2.0,2.0,3.0 のようにすることで、模様本体は白く、フェードアウト部分や周囲のブルームの光はほのかに青い、という結果が得られます。
冒頭で触れたように、映り込みは Y 軸を反転させたカメラのレンダリング結果を用いています。このへんは Standard Asset の水面の処理を流用しています。
Y 反転カメラの結果をステージに重ねると以下のようになります。
悪くないですが、鏡のようでやや安っぽく見えます。これをもうちょっとリッチな絵に見えるように工夫します。
まず、深度に応じてぼかしてフェードアウトさせる処理を入れます。
反射画像をレンダリングする際に camera.depthTextureMode = DepthTextureMode.Depth; で深度テクスチャを生成し、それを使います。
そこそこいい感じに馴染んだんじゃないかと思います。
(実際のところこのあたりはすごくアドホックな実装になっており、輪郭付近に不自然なところが目立ちます…)
最後に六角形の縁の部分を歪ませる処理を入れます。
前述のように、distance function で各ピクセルと図形との距離を取れるため、近隣ピクセルの図形との距離を見ることで、図形の外側に向かう方向を推測することができます。六角形の縁の部分だけ、反射画像をサンプリングする位置をこの方向にずらして反射を歪ませます。
実際のところこれは 2D 処理のフェイクであるため、よく見ると反射として全然正しくはないのですが、動いてるのを見るとぱっと見「おっ」と思える効果があるんじゃないかと思います。
以上が床の描画処理の解説になります。
今回ピクセルシェーダで生成したパターンは 2D でしたが、3D も可能で、今回のハニカム模様と光の溝を 3D で可視化することで以下のような絵を出すこともできます
WebGL で実行
この類のテクニックは demoscene の世界で広く使われており、興味がある方は調べてみるといいでしょう。シェーダはそれだけでアートたりえる、というのが見て取れるんじゃないかと思います。