今回やってみたのはこれ。
SF系ゲームでは割とよくあるスキャンエフェクトです。
球状の浮遊ロボットが不審な人間をスキャンして個人識別する、ってのはデストピアな未来ではよくあること。
今回はそんな状況で使用できそうなマテリアルを作ってみました。
作成したマテリアルは2つ。
1つは人型キャラに使われているもので、スキャンラインの移動に合わせてライン部分に色がつくもの。
もう1つが球体から放出されているスキャンラインのマテリアル。
普通ならテクスチャを貼った三角形の板で済む部分なのですが、今回はわざと面倒なマテリアルを作成しました。
実装方法は続きから
まず最初に人間のラインを表示しているマテリアルからです。
これは比較的簡単なもので、スキャンラインの平面を平面方程式に変換、その方程式を利用して平面からワールド座標の距離を計算、一定距離内にあるワールド座標にエミッシブを追加しているだけです。
平面方程式は以下の方程式です。
ax + by + cz + d = Length
x, y, zが平面からの距離を求める座標、a, b, c, dが平面方程式のパラメータ、Lengthが指定座標の平面からの最小距離です。
平面方程式のパラメータのうち、a, b, cは平面の法線を割り当てます。正規化されている必要があります。
dは平面上の点Pにおいて Length = 0 となるように計算します。
つまり、平面のパラメータは平面の法線と平面上の点があれば求めることが出来ます。
これをマテリアルファンクションにしたものがこちら。
MF_Calc_Plane
法線は正規化されているものとみなしています。
ここで4要素ベクトルとして出力しているのは、DotProductだけで簡単に計算できるからです。
で、実装しているスキャンラインのマテリアルファンクションはこちら。
MF_Plane_Line
Planeが平面方程式のパラメータ、つまり前述のマテリアルファンクションで求めた値で、LineWidthがスキャンラインの太さです。
平面からの距離を2乗し、1 - t で平面上が1、そこから距離が増すと0に向かうように計算しています。
この値とスキャンラインのカラーを積算し、エミッシブに加えてやればOKです。
実装例はこんなかんじ。
M_Scan_Destination
他の部分は定数を入れているだけなので放置。
今回はプレイヤーが球体の前に来たらスキャンされるようにしたため、Lineというパラメータでラインの有無を設定できるようにしています。
他のパラメータは解説しなくても大丈夫ですね?
ではもう1つの方。
こちらは前述したとおり、本来であれば三角形の板にテクスチャ貼ればいいだけなのですが、プロシージャルテクスチャっぽいことをしたかったために無理やり計算で模様をつけました。
結果はこんな感じになります。
プレビューメッシュのアイコンからわかると思いますが、ただの四角い板です。
単純ではありますが、テクスチャを利用せずにこのような簡単な模様をつけています。
ある程度の規則性を持っていて、計算によって求められる模様くらいであればテクスチャを使わなくても表示できたりします。
このようなプロシージャル技術は最近の大規模開発ではなくてはならない技術になっています。
木や草を自動生成するのはもちろん、最近では街全体を自動生成してしまったり。
プロシージャルテクスチャはテクスチャを生成するものですが、リアルタイム処理することでいくつかの利点を得られます。
1.パラメータの変更による映像の変化をリアルタイムにチェックできる
2.解像度の影響を受けない
例えば今回のこのスキャンラインは、三角形の角度、長さ、途中のラインの間隔と幅を指定することが出来ます。
もちろん、これらをマテリアルインスタンスで変更すれば簡単に変化の度合いをチェックできます。
解像度の影響は特に画面に対してアップになった場合にテクスチャ特有の低解像度によるしょぼさを見せなくてすみます。
低解像度らしい部分は映像の説得力を失わせる要因の1つです。
実装はどうなっているのでしょうか?
単純な形状ではありますが、その割にちょっと複雑です。
MF_Scan_Plane
パラメータも多いですね。
ScanFrontはスキャンラインが伸びていく方向です。
つまり、三角形の頂点から底辺に垂線をおろした場合の方向を示します。
ScanLengthがこの頂点から垂線までの距離、三角形の長さを示します。
LineFrequencyはラインが出現する周期を長さで指定します。
LineWidthはラインの幅ですね。こちらはMF_Plane_LineのLineWidthと同じ意味合いです。
ScanAngleがあ三角形の角度です。あまり広げすぎるとモデルの範囲内に収まらなくなったりするので注意。
BaseColor,LineColorがそれぞれ板部分とライン部分の色、BaseOpacityは最も不透明度が高い位置(三角形の頂点)の不透明度です。
使い方はまあ、パラメータを突っ込んでUnlitの半透明マテリアルのエミッシブにつなげればOKです。
あとはBlueprintでスキャンラインを動かしたり、球体の前にプレイヤーが立ったらスキャンラインを生成したりしてやれば最初の画像のようなシーンが作れます。
というわけで、これらのマテリアルや関数はいつもどおりにGitHubにコミットしてあります。
興味がある方はご確認ください。