【Unity】旗がはためくシェーダー


はじめに

ShaderLabで、はためく旗をつくります。
テクスチャの表示の解説は省いていますがご了承ください。

環境

  • Unity 2021.2.11f1
  • Build-in Rendering Pipline

コード全文

FlagAnimation.shader

https://gist.github.com/went5/28bd105169fe62c31ef82c79b4ce81e9

Planeを両面表示する

Planeが片面しか表示されないと不都合があるため、CullOffキーワードを入れます。
このキーワードをいれるだけで、両面表示してくれます。

SubShader
{
    Pass
    {
        Cull Off

        Tags
        {
            "RenderType"="Opaque"
        }
        // ...省略
    }
}

Sinを使って波のような形を作る

sin anim

頂点を動かすため、頂点シェーダーを作っていきます。
sinを使って波のような形を取るには、以下の式を使います。
ffは周波数(Frequency)です。 y=sin(xf)y = sin(x \cdot f)

yyv.vertex.yxxv.vertex.xff_WaveFreq
とおくと以下のようなコードになります。

v2f vert(appdata v)
{
    v2f o;
    v.vertex.y = sin(v.vertex.x *_WaveFreq);
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    return o;
}

Planeにシェーダーを貼ると上記の画像を再現できます。
カクカクしているのは、Planeの頂点数が少ないのかつ、周波数が大きいためです。

Time変数を使って動かす

sin wave

Unityのビルトインのシェーダー変数_Time を使ってアニメーションをさせていきます。
sin(x)sin(x)xxを増やしていくと、波を進められるので、ttを使って進めます。
y=sin(xf+t)y =sin(x \cdot f + t)

v2f vert(appdata v)
{
    v2f o;
    v.vertex.y = sin(v.vertex.x*_WaveFreq + _Time.y * _TimeSpeed);
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    return o;
}

上記のアニメーションは _TimeSpeed が1の場合のものです。

旗の動きに近づける

flag anim1

_WaveFreq_TimeSpeed を調整して、旗の動きに近づけていきましょう。
筆者は以下の値にしました。

  • _WaveFreq : 0.27
  • _TimeSpeed : 3.29

さらに旗の動きに近づける

このままだと、ポールに近い布の動きとポールに遠い布の動きが同じなため、ポールから布がずれてしまっています。
そのため、uv座標を使ってポールに近くところは揺れないように調整します。

fixed4 frag(v2f i): SV_Target
{
    fixed4 col = fixed4(0.0, i.uv.x, 0.0, 1.0);
    return col;
}


カメラの初期位置を変えていなければ、画面から見て左側のuv座標(x)の値が0に近づくことが分かります。
これを考慮したコードが以下のものになります。

v2f vert(appdata v) {
    v2f o;
    v.vertex.y = sin(v.vertex.x * _WaveFreq + _Time.y * _TimeSpeed) * v.uv.x;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    return o;
}

以上で冒頭の旗を再現できます。

参考

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

Table of contents


©️ 2026 went5. blog icon by

icons8