【Unity3D】水波エフェクト

1 水波効果の原理

        ウォーター ウェーブ エフェクトは、Unity3D の後処理の特殊効果です。その原理は、レンダリングされたテクスチャに対してローカルの押し出しとリフティング トランスフォームを実行することです。つまり、ローカルの UV 座標で周期的なオフセット移動を実行して波及効果を実現します。

        1) 波形方程式

        水波モデルを単純化するために、水波が機械波 (正弦波または余弦波) として伝播し、時間 0 での水面波形関数が次のようになると仮定します。

\大きなオフセット=A\cdot sin(w_1\cdot r)

        このうち、rは水波の中心からの粒子の半径長さ、w1は波形の角周波数(値が大きいほど波紋が密になる)、Aは粒子の水平振動の振幅です。 、offset はパーティクルの水平オフセットです。

        2) 振動方程式

        時間 t における、半径 r の粒子の水平オフセットは次のとおりです。

\大きなオフセット=A\cdot sin(w_1\cdot r+w_2\cdot t)

         ここで、w2 は粒子の水平振動の角周波数です (値が大きいほど、粒子の振動は速くなります)。

        この記事のコード リソースについては、Unity3D Water Wave Effectを参照してください。

2 コードの実装

        WaterWaveEffect.cs

using UnityEngine;
 
[RequireComponent(typeof(Camera))]  // 屏幕后处理特效一般都需要绑定在像机上
public class WaterWaveEffect : MonoBehaviour {
    public float A = 0.01f; // 水面质点水平波动振幅
    public float w1 = 60; // 水波截面波形角频率(值越大, 波纹越密)
    public float w2 = 30; // 水面质点水平波动角频率(值越大, 水波质点振动越快)
    public float waveWidth = 0.3f; // 水波宽度(水波在扩散时, 后波会消失)
    public float waveSpeed = 0.3f; // 水波传播的速度
    private float waveTime; // 水波传播时间
    private Vector4 waveCenter; // 水波中心
    private Material waveMaterial; // 水波材质
    private bool enabledWave = false; // 水波开关
 
    private void Awake() {
        waveMaterial = new Material(Shader.Find("Custom/WaterWave"));
        waveMaterial.hideFlags = HideFlags.DontSave;
    }

    private void Update() {
        if (Input.GetMouseButton(0)) {
            waveCenter = new Vector2(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height); // 屏幕坐标归一化
            enabledWave = true;
            waveTime = 0;
        }
    }

    void OnRenderImage (RenderTexture source, RenderTexture destination) {
        if (enabledWave) {
            SetWaveMaterialParams();
            Graphics.Blit (source, destination, waveMaterial);
            waveTime += Time.deltaTime;
            if (waveTime > 2 / waveSpeed) { // 水波传播到屏幕外面, 结束水波特效
                enabledWave = false;
            }
        } else {
            Graphics.Blit (source, destination);
        }
	}

    private void SetWaveMaterialParams() { // 设置水波材质参数
        waveMaterial.SetFloat("_A", A); // 水面质点水平波动振幅
        waveMaterial.SetFloat("_w1", w1); // 水波截面波形角频率(值越大, 波纹越密)
        waveMaterial.SetFloat("_w2", w2); // 水面质点水平波动角频率(值越大, 水波质点振动越快)
        waveMaterial.SetFloat("_t", waveTime); // 水波传播时间
        waveMaterial.SetVector("_o", waveCenter); // 水波中心
        waveMaterial.SetFloat("_waveDist", waveTime * waveSpeed); // 水波传播距离
        waveMaterial.SetFloat("_waveWidth", waveWidth); // 水波宽度(水波在传播时, 后波会消失)
    }
}

        注: WaterWaveEffect スクリプト コンポーネントは、カメラの下に吊るす必要があります。

        WaveShader.shader

Shader "Custom/WaterWave" 
{
	Properties 
	{
		_MainTex ("mainTex", 2D) = "white" {}
	}
 
	SubShader 
	{
		Pass
		{
			ZTest Always
			Cull Off
			ZWrite Off
			Fog { Mode off }
 
			CGPROGRAM

			#pragma vertex vert_img // UnityCG.cginc中定义了vert_img方法, 对vertex和texcoord进行了处理, 输出v2f_img中的pos和uv
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float _A; // 水面质点水平波动振幅
            float _w1; // 水波截面波形角频率(值越大, 波纹越密)
            float _w2; // 水面质点水平波动角频率(值越大, 水波质点振动越快)
            float _t; // 水波传播时间
            float2 _o; // 水波中心坐标
            float _waveDist; // 水波传播距离
            float _waveWidth; // 水波宽度(水波在传播时, 后波会消失)

            fixed4 frag(v2f_img i) : SV_Target // 水波uv坐标的计算不能在顶点着色器中进行, 因为屏后处理的顶点只有屏幕的4个角顶点
            {
                float2 vec = i.uv - _o.xy;
                vec.x *= _ScreenParams.x / _ScreenParams.y; // 按照屏幕长宽比进行缩放
                float radius = length(vec); // 距离波中心的半径长度
                float leng = abs(radius - _waveDist);
                float offset = 0;
                if (leng < _waveWidth)
                {
                    offset = _A * sin(_w1 * radius - _w2 * _t) * (1 - leng / _waveWidth);
                }
                return tex2D(_MainTex, i.uv + offset * 0.707); // offset是一维的, uv是二维的, 需要除以根号2, 即乘以0.707
            }

			ENDCG
		}
	}

	Fallback off
}

3 ランニング効果

         画面上の任意の場所をクリックすると、水の波が次のように表示されます。地面と空の接合部の直線に注意してください。正弦波がはっきりと見えます。

4 推奨読書

おすすめ

転載: blog.csdn.net/m0_37602827/article/details/127992378