おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】シェーダで旗や水面をなびかせる

ゲーム中で、旗や水面は静止していることはあまりなく、風にあおられてなびいていることが多いですね。

f:id:nn_hokuson:20170404200530j:plain

リアルになびかせようとすると、シミュレーションやボーンアニメーションをする必要があります。この記事ではUnityの頂点シェーダを使ってお手軽に旗や波などを動かす方法を紹介したいと思います。

今回の記事の内容は次のとおりです。

旗や水面をなびかせるアルゴリズム

旗をなびかせるためには、平面オブジェクトの頂点を移動させることで実現します。3Dで考えると難しいので、2Dで考えてみましょう。

平面オブジェクトを横から見ると次のように一直線に頂点が並んでいます。

f:id:nn_hokuson:20170404194735p:plain:w350

この頂点を波の形に移動させることで、平面オブジェクトがなびいているように見せかけることができます。

f:id:nn_hokuson:20170404194741p:plain:w350

全体的には波打っているように見えますが、それぞれの頂点は単に上下運動を繰り返しているだけです。ただし、隣の頂点とは少しタイミングをずらして上下運動をさせます。

f:id:nn_hokuson:20170404194747p:plain:w350

水面uvスクロールで動かす方法はこちらの記事に書いていますので参考にしてみてください。

nn-hokuson.hatenablog.com

3Dモデルの配置とシェーダファイルの作成

まずはUnityのシーンビューに平面を配置します。ヒエラルキービューから「Create」→「3D Object」→「Plane」を選択してください。

f:id:nn_hokuson:20170404194753p:plain:w300

UnityのPlaneは10x10のメッシュなので、旗のようになびかせると少々ぎこちない動きになってしまいます。もう少し細かいメッシュのものを使いたい方は、Blenderなどで作成して下さい。

f:id:nn_hokuson:20170404195658j:plain

いつもと同じようにシェーダファイルとマテリアルを作成します。プロジェクトビューで「Create」→「Shader」→「Standard Surface Shader」を選択し、ファイル名は「Flag」で保存します。
このファイルを選択した状態で、「Create」→「Material」を選択し、Custom_Flagマテリアルを作成してください。作成したマテリアルにFlagシェーダが使われていればOKです。

f:id:nn_hokuson:20170404194805p:plain:w150

マテリアルは平面オブジェクトにアタッチして、必要でしたらマテリアルにテクスチャを設定しておきます。

f:id:nn_hokuson:20170404194813p:plain

シェーダプログラム

今回作成した旗のシェーダプログラムは次のとおりです。

Shader "Custom/Flag" {
    Properties {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        CGPROGRAM
        #pragma surface surf Lambert vertex:vert
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        void vert(inout appdata_full v, out Input o )
        {
            UNITY_INITIALIZE_OUTPUT(Input, o);
            float amp = 0.5*sin(_Time*100 + v.vertex.x * 100);
            v.vertex.xyz = float3(v.vertex.x, v.vertex.y+amp, v.vertex.z);            
            //v.normal = normalize(float3(v.normal.x+offset_, v.normal.y, v.normal.z));
        }

        void surf (Input IN, inout SurfaceOutput o) {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

頂点の座標データを操作するので、独自のvertexシェーダをカスタムで作る必要があります。

f:id:nn_hokuson:20170401080509p:plain

頂点シェーダのカスタムについては、頂点カラーの回で詳しく説明しているので合わせて参考にしてください。

nn-hokuson.hatenablog.com

#pragmaの中で「vertex:vert」とすることで、カスタムしたバーテックスシェーダ(vert)を使うことを宣言しています。頂点シェーダ(vert)のなかでは、各頂点を上下運動させるシェーダプログラムを書いています。

sin関数を使って時間とともに頂点のy座標を変化させています。隣り合う頂点とは少し周期をずらすために、sin関数の引数に頂点のx座標を足しています。

実行結果

実行結果は次のようになります。このように、頂点シェーダを使うことで簡単にアニメーションを作ることができます。

f:id:nn_hokuson:20170404194843g:plain