【Unity】【シェーダテクニック】プロシージャルになんとなくおしゃれな感じのグラデーションを作る

プロシージャルになんとなくおしゃれな感じのグラデーションを作る方法です。

Unity2019.1.10

やりたいこと

下記のサイトで、プロシージャルなグラフィックスを作るときにいい感じのカラーパレット作る方法が紹介されていました。

www.iquilezles.org

これによると、以下の式でカラーパレットが作れるようです。

 { \displaystyle
color(t) = a + b * cos(2 pi (c * t + d))
}

ここでtは0~1の値で、これによりカラーパレットのどこから色を取るかが決まります。

a,b,c,dはそれぞれ三次元の値です。
cはRGBそれぞれの振動、dは位相のずれを表します。
つまりRGBのそれぞれの値について振動数の違うコサインカーブを作って、それらをちょっとずつずらして合成することで色を作ります。
また、グラデーションをループさせたい場合はcの値に整数を入れる必要があります。

aとbは最終的に明るさやコントラストを調整するだけの値なので、
今回は両方0.5の固定値で計算することにします。

ソースコード

それではこれでどんな感じのグラデーションが作れるのか試してみるためのソースコードを書いてみます。

using UnityEngine;

public class Example : MonoBehaviour
{
    [System.Serializable]
    public class OscilateTimes
    {
        public bool looping = true;
        [Range(0.0f, 10.0f)]
        public float r = 1.0f;
        [Range(0.0f, 10.0f)]
        public float g = 1.0f;
        [Range(0.0f, 10.0f)]
        public float b = 1.0f;
    }

    [System.Serializable]
    public class Phases
    {
        [Range(0.0f, 1.0f)]
        public float r;
        [Range(0.0f, 1.0f)]
        public float g;
        [Range(0.0f, 1.0f)]
        public float b;
    }

    [SerializeField]
    private OscilateTimes _oscilateTimes = new OscilateTimes();
    [SerializeField]
    private Phases _phases = new Phases();

    private Texture2D _texture;

    private void Awake()
    {
        _texture = new Texture2D(100, 1);
    }

    private void OnRenderImage(RenderTexture source, RenderTexture dest){
        Graphics.Blit(_texture, dest);
    }

    private void Update()
    {
        // ループ設定の場合は振動数を整数にする
        if (_oscilateTimes.looping) {
            _oscilateTimes.r = Mathf.Round(_oscilateTimes.r);
            _oscilateTimes.g = Mathf.Round(_oscilateTimes.g);
            _oscilateTimes.b = Mathf.Round(_oscilateTimes.b);
        }
        // テクスチャを更新する
        for (int i = 0; i < 100; i++) {
            var rate = (float)i / 100;
            _texture.SetPixel(i, 0, GetColor(rate, _oscilateTimes, _phases));
        }
        _texture.Apply();
    }

    private Color GetColor(float rate, OscilateTimes oscilateTimes, Phases phases)
    {
        var r = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (oscilateTimes.r * rate + phases.r));
        var g = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (oscilateTimes.g * rate + phases.g));
        var b = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (oscilateTimes.b * rate + phases.b));
        return new Color(r, g, b);
    }
}

内容としては前節の計算で求めた色をテクスチャに焼き込み、
画面に対して描画命令を走らせているだけです。

色々と適当ですがまあ軽く試す分には十分でしょう。

結果

Inspectorからcとdの値を編集してなんとなくいい感じのグラデーションが作れるようになりました。

f:id:halya_11:20190721181509g:plain

シェーダで使えば表現の幅が広がりそうです。

参考

www.iquilezles.org