知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】UVスクロールで水面を作る #12

前回の成果

soramamenatan.hatenablog.com

ステンドグラスのシェーダーができました。

今回やること

nn-hokuson.hatenablog.com

今回はuvスクロールを使用して、水面のようなものを制作していきます。

前準備

SceneにPlaneを置き、今回制作したMaterialのinspectorに水面の画像をアタッチします。

f:id:soramamenatan:20190712153032p:plain

画像を頂戴したサイト様はこちらです。

www.pixiv.net

ソースコード

Shader "Custom/waterSurface" {
    Properties {
        _MainTex("Texture", 2D) = "white" {}
    }

    SubShader {
        Tags { "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed2 uv = IN.uv_MainTex;
            fixed speed = 1.0f;
            uv.x += speed * _Time.x;
            uv.y += speed * _Time.x;
            o.Albedo = tex2D (_MainTex, uv);
        }
        ENDCG
    }
    FallBack "Diffuse"
}

inputからもらってきたUV座標をtimeでズラしているように見えます。

uv.x += speed * _Time.x

前フレームのUV値を保持しておいて、そこから加算していけばよいのでは?と思う方もいると思います。
しかし、Shader上の変数に値を入れても、Shaderはフレーム間で状態を保持しないので不可能なのです。
これはSurfaceShaderに限った話ではありません。

なので、uv座標にスクロールする速度×時間を足すことによって実現させます。

_Time

これはUnityの変数にデフォルトで用意されている変数です。
Timeはステージの読み込みからの時間を表していて、Shaderの中で主にアニメーションを使用する際に用いられます。

名称 用途
_Time.x time/20
_Time.y time
_Time.z time*2
_Time.w time*3

※ timeはステージを読み込んだ時からの時間

実行すると・・・?

f:id:soramamenatan:20190718152507p:plain

このまま実行すると、textureはズレているのですが、うまくいっていません。
原因は元のtextureの設定にあります。

textureのinspectorのWarp ModeがClampになっているので、uvスクロールがうまくいっていません。

f:id:soramamenatan:20190719114957p:plain

これをClampからRepeatに変更します。

f:id:soramamenatan:20190719115057p:plain

すると、しっかりとuvスクロールしてくれるようになりました!

f:id:soramamenatan:20190719114453g:plain

他のWarp Mode

わかりやすいように、textureに絵を1つのみにして、Tilingを3に変更しています。

f:id:soramamenatan:20190719154041p:plain

Clamp

画像を左下に移動させて足りない部分は無理やり補っています。

f:id:soramamenatan:20190719145702p:plain

Repeat

同じtextureを描画させています。

f:id:soramamenatan:20190719145740p:plain

Mirror

textureを上下左右に反転させています。

f:id:soramamenatan:20190719145928p:plain

Mirror Once

textureを一度ミラーリングしてから、エッジピクセルに固定しています。
見た目はClampと変わりません。

f:id:soramamenatan:20190719150608p:plain

Per-axis

x軸とy軸で項目を選んで、描画させることができます。
画像ではx軸をMirrorに、y軸をClampにしています。
f:id:soramamenatan:20190719150642p:plain

f:id:soramamenatan:20190719150654p:plain

ソースコードにコメントを付与

Shader "Custom/waterSurface" {
    // プロパティ
    Properties {
        // テクスチャのデータ
        _MainTex("Texture", 2D) = "white" {}
    }
    // Shaderの中身の記述
    SubShader {
        // 一般的なShaderを使用
        Tags { "RenderType" = "Opaque" }
        // しきい値
        LOD 200

        // cg言語記述
        CGPROGRAM
        // フォワードレンダリング
        #pragma surface surf Standard fullforwardshadows
        // Shader Model
        #pragma target 3.0

        // Input構造体
        struct Input {
            // テクスチャのuv座標
            float2 uv_MainTex;
        };

        // テクスチャのデータ
        sampler2D _MainTex;

        // surf関数
        void surf (Input IN, inout SurfaceOutputStandard o) {
            // uv値の取得
            fixed2 uv = IN.uv_MainTex;
            // uvスクロールの速度
            fixed speed = 1.0f;
            // x軸の移動
            uv.x += speed * _Time.x;
            // y軸の移動
            uv.y += speed * _Time.x;
            // ズレを適応させる
            o.Albedo = tex2D (_MainTex, uv);
        }
        // Shaderの記述終了
        ENDCG
    }
    // SubShaderが失敗した時に呼ばれる
    FallBack "Diffuse"
}

以上になります! 次回も引き続きShaderの勉強をしていきます!