ゲーム中で、旗や水面は静止していることはあまりなく、風にあおられてなびいていることが多いですね。
リアルになびかせようとすると、シミュレーションやボーンアニメーションをする必要があります。この記事ではUnityの頂点シェーダを使ってお手軽に旗や波などを動かす方法を紹介したいと思います。
今回の記事の内容は次のとおりです。
旗や水面をなびかせるアルゴリズム
旗をなびかせるためには、平面オブジェクトの頂点を移動させることで実現します。3Dで考えると難しいので、2Dで考えてみましょう。
平面オブジェクトを横から見ると次のように一直線に頂点が並んでいます。
この頂点を波の形に移動させることで、平面オブジェクトがなびいているように見せかけることができます。
全体的には波打っているように見えますが、それぞれの頂点は単に上下運動を繰り返しているだけです。ただし、隣の頂点とは少しタイミングをずらして上下運動をさせます。
水面uvスクロールで動かす方法はこちらの記事に書いていますので参考にしてみてください。
3Dモデルの配置とシェーダファイルの作成
まずはUnityのシーンビューに平面を配置します。ヒエラルキービューから「Create」→「3D Object」→「Plane」を選択してください。
UnityのPlaneは10x10のメッシュなので、旗のようになびかせると少々ぎこちない動きになってしまいます。もう少し細かいメッシュのものを使いたい方は、Blenderなどで作成して下さい。
いつもと同じようにシェーダファイルとマテリアルを作成します。プロジェクトビューで「Create」→「Shader」→「Standard Surface Shader」を選択し、ファイル名は「Flag」で保存します。
このファイルを選択した状態で、「Create」→「Material」を選択し、Custom_Flagマテリアルを作成してください。作成したマテリアルにFlagシェーダが使われていればOKです。
マテリアルは平面オブジェクトにアタッチして、必要でしたらマテリアルにテクスチャを設定しておきます。
シェーダプログラム
今回作成した旗のシェーダプログラムは次のとおりです。
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シェーダをカスタムで作る必要があります。
頂点シェーダのカスタムについては、頂点カラーの回で詳しく説明しているので合わせて参考にしてください。
#pragmaの中で「vertex:vert」とすることで、カスタムしたバーテックスシェーダ(vert)を使うことを宣言しています。頂点シェーダ(vert)のなかでは、各頂点を上下運動させるシェーダプログラムを書いています。
sin関数を使って時間とともに頂点のy座標を変化させています。隣り合う頂点とは少し周期をずらすために、sin関数の引数に頂点のx座標を足しています。
実行結果
実行結果は次のようになります。このように、頂点シェーダを使うことで簡単にアニメーションを作ることができます。