C#
Unity
Shader

【UNITY】007っぽいスポットライト演出作ってみた【Shader】【PostProcess】

初投稿です。

作ったもの

まずはこちらをご覧ください。

Shader とPostProcess でスポットライト風エフェクト作ってみた(モバイルでも動くよ) pic.twitter.com/L0grnsx0a2

— 人生\(^o^)/ (@8bitdots) 2018年3月20日

実装について

PostProcess による、現在カメラ写している絵を取得&加工 することで実装しました。
手順としては
1. カメラコンポーネントにアタッチしているC# スクリプトでOnRenderImage でカメラで写している絵をTexture として取得
2. そのTexture を事前に専用Shader を設定したMaterial に適応
3. Shader 内で表示/非表示を判定

C# コードについて

こちらにある通り、OnRenderImage 関数無いでBilt しているだけです。
コピペでいけますね

Shader について

基本的にはピクセルシェーダー(フラグメントシェーダー)で行います。
※ポイント
- if文は並列演算を行うGPUにとって処理が重いので
条件分岐はif文ではなく Clamp やlerp を用いて表現
- 2乗は関数ではなくそのまま A x A みたいに書いてしまう
- 平方根を計算するのが重いので2乗した値で比較する

実際のコードは以下の通りです。

fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed4 black = float4(0.0, 0.0, 0.0, 1.0);

    // Elipse equation
    // ((x-p)/a)^2 + ((y-q)/b)^2 = 1
    //
    float r = (i.uv.x - _Param.x)*(i.uv.x - _Param.x)/_Param.z/_Param.z+
    (i.uv.y - _Param.y)*(i.uv.y - _Param.y)/_Param.w/_Param.w;

    // r^2 < 1 ? Original : Black
    return lerp(col, black, floor(r) );
}

以下解説
- L1:ピクセルシェーダーの関数定義
- L3: 受け取った画像(OnRenderImage で得た画像)のあるピクセルの色情報を取得
- L4: 非表示用の黒色
- L9~10: 楕円の方程式を計算しています。
- L13: 楕円の方程式の計算結果が1以上なら黒, 1未満ならオリジナルの画像を描画

楕円の方程式について

高校数学の復習ですね。
中心座標(p,q) でx軸の長さをa, y軸の長さをb とすると下記のような方程式になりますね。
スクリーンショット 2018-03-20 17.17.03.png

左辺が1以下なら楕円内に存在することがわかるので、各ピクセルに対して上記楕円の方程式を解いて楕円内にいるか判定しています。

動作確認

動作確認のため、Unity ちゃんを置いてみます。
Unity ちゃんのDL 先はこちら
利用規約的にも大丈夫そうですね。

あ、ライセンス、ライセンス
Light_Frame.png
これで大丈夫かな。

最終的に

冒頭の動画の通り、Shader のパラメータをいじることで指定位置に指定サイズ,形状の円領域のみ表示することができました。
あとは、モーションを右から歩かせてそれに合わせてスポット位置を調整すればいけそうですね。

[ 再掲 ]

Shader とPostProcess でスポットライト風エフェクト作ってみた(モバイルでも動くよ) pic.twitter.com/L0grnsx0a2

— 人生\(^o^)/ (@8bitdots) 2018年3月20日

GitHub

今回作ったShaderとかのコードはGitHub で公開しています。
https://github.com/Cova8bitdots/SpotLightShader

参考

【Unityシェーダ入門】Unityのポストエフェクトでモノクロ画面を作る
http://nn-hokuson.hatenablog.com/entry/2016/11/17/204831

Unityちゃん利用ガイドライン
http://unity-chan.com/contents/guideline/

手書き数式認識
https://webdemo.myscript.com/views/math.html#