おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】スパイクノイズを作る

スパイクノイズは、ブランドロゴのイントロとかでよく使われる感じのエフェクトです。といっても伝わりにくいので↓のような感じのものを作ります。

f:id:nn_hokuson:20170609224404g:plain

スパイクノイズという言葉はもともとは電子回路の言葉で、スイッチをオン・オフしたときに生じるパルスノイズです。チャタリングのようなものですね〜。余談でした(笑)

www.marutsu.co.jp

スパイクノイズのエフェクトを作る

画像を横方向に歪めるエフェクトは非常に簡単で、参照するテクスチャのX座標値をY軸の値をもとにずらすだけです。ずらす量は基本的にはsin関数で良いと思います。

f:id:nn_hokuson:20170609222354j:plain:w450

今回は場所によってもう少しランダムなノイズにしたかったので、sin(10*x)*(-(x-1)^2+1)という関数の0〜3の範囲を使います。
この関数はsin関数と二次曲線の値を掛けただけのものですが、これにより山形のノイズが生成できます。

f:id:nn_hokuson:20170609221144p:plain:w400

MacではGrapherというアプリ(デフォルトで入っている)を使うと、簡単にグラフが書けるので、「こういう波形が作りたい」というときに重宝しています。

パルスノイズのシェーダを作る

まずはシェーダファイルとマテリアルを作ります。プロジェクトビューで右クリックし、「Create/Shader/Unlit Shader」を選択してください。「PulseNoise.shader」という名前で保存します。このシェーダを設定した「PulseNoiseマテリアル」も作成します。

f:id:nn_hokuson:20170609222617p:plain:w150

PulseNoise.shaderに次のプログラムを入力してください。

Shader "UI/PulseNoise"
{
    Properties
    {
        _MainTex ("Sprite Texture", 2D) = "white" {}
        _Amount ("Distort", Float) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag  
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float  _Amount;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                float2 uv = i.uv;
                float x = 2*uv.y;
                uv.x += _Amount*sin(10*x)*(-(x-1)*(x-1)+1);
                fixed4 col = tex2D(_MainTex, uv);
                return col;
            }
            ENDCG
        }
    }
}

フラグメントシェーダで、テクスチャを横方向にずらす処理をしています。テクスチャのy座標の値をもとにx方向にずらす量を計算しています。計算式は上で書いたとおりです。

また、ノイズの強さ自体をインスペクタから操作するため、propertiesブロックに_Amount変数を用意しています。この値を上で計算した値に掛けることで、ノイズ全体の大きさを制御します。

シェーダが書けたら、ノイズをかけたいuGUIのImageのインスペクタのMaterial欄に作成したPulseNoiseマテリアルをドラッグ&ドロップしてください。

f:id:nn_hokuson:20170609222945p:plain:w400

PulseNoiseマテリアルのインスペクタからAmount値を操作するとノイズがかかることが確認できます。

f:id:nn_hokuson:20170609223344g:plain

パルスノイズを発生させるスクリプト

いちいち手作業でノイズを発生させるわけにもいかないので、スクリプトからノイズを発生させましょう。

ノイズを一瞬だけ発生させるため、C#スクリプトから_Amount変数の値を操作します。NoiseControllerを作って次のプログラムを入力してください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class NoiseController : MonoBehaviour {

    IEnumerator GeneratePulseNoise()
    {
        for (int i = 0; i <= 180; i += 30)
        {
            GetComponent<Image> ().material.SetFloat ("_Amount", 0.2f * Mathf.Sin (i * Mathf.Deg2Rad));
            yield return null;
        }
    }

    void Update () {
        if (Input.GetMouseButtonDown (0))
        {    
            StartCoroutine (GeneratePulseNoise ());
        }
    }
}

ここではノイズの大きさをsin波で変化させているだけです。もちろん、Animatorから_Amountの値を操作してもOKです。最終的な実行結果は次のようになります。

f:id:nn_hokuson:20170609224404g:plain