正弦函數/正弦波 是最基礎的波形
在游戲中通常使用 正弦函數/正弦波 來逼近真實世界中的漣漪效果
漣漪效果
有了波形並不意味着就能產生漣漪的效果
往往還需要在畫面中添加折射、反射、扭曲等效果
看圖中的漣漪效果
之所以人眼看起來像漣漪
是因為在漣漪處的空間發生了輕微的扭曲,而 “空間扭曲”,也就是貼圖偏移
Shader
Shader "Effect/ripple" { Properties { _MainTex("Texture", 2D) = "white" {} _Ctor("Ctor", float) = 84 _timeCtor("timector",float) = 60 _max_dis("maxdis",Range(0,1)) = 0.5 } SubShader { Tags { "RenderType" = "Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog #pragma target 4.0 #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _ArrayParams[10]; float _Ctor; float _timeCtor; float _max_dis; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag(v2f i) : SV_Target { float2 uv = float2(0,0); [unroll] for (int j = 0; j < 10; j++) { float2 dv = float2(_ArrayParams[j].x,_ArrayParams[j].y) - i.uv; float dis = sqrt(dv.x * dv.x + dv.y * dv.y); float sinFactor = sin(dis * _Ctor + _Time.y * _timeCtor); float2 dv1 = normalize(dv); float2 offset = dv1 * sinFactor * max(0,_max_dis - dis) * step(dis,_ArrayParams[j].z) * step(_ArrayParams[j].w,dis); uv += offset; } uv = i.uv + uv / 10; return tex2D(_MainTex, uv); } ENDCG } } }
Shader 代碼里面使用了 for,上面打上 [unroll] 標簽,編譯的時候會把 for 展開成靜態代碼
通過在 C# 代碼中傳入不同水波漣漪的初始點
然后在 Shader 的算法中對每一個uv點做插值來實現多個的漣漪效果
using UnityEngine; /// <summary> /// 根據位置信息,在指定位置生成水波 /// </summary> public class CreatNodes : MonoBehaviour { // 水波參數 public float _speed = 3; public float forward_speed = 0.006f; public float back_speed = 0.003f; public float width = 0.1f; // shader最多的水波數量是10(同時) public const int max_click_count = 10; public Vector4[] uis = new Vector4[max_click_count]; // 最大距離 private float max_dis = 1; // 當前材質球 private Material currentMaterial; private Ray ray; private RaycastHit hit; private bool can_add; private Vector3 vector3; private void Awake() { currentMaterial = transform.GetComponent<Renderer>().sharedMaterial; currentMaterial.SetVectorArray("_ArrayParams", uis); } private void FixedUpdate() { for (int i = 0; i < uis.Length; i++) { if (uis[i].z > max_dis) uis[i].Set(0, 0, 0, 0); if (uis[i].x == 0 && uis[i].y == 0) { if (can_add) { // 將物體坐標轉換成uv坐標 uis[i].x = vector3.x + 0.5f; uis[i].y = vector3.y + 0.5f; // 頭與尾巴的寬度 uis[i].z = width; // 尾巴的開始點 uis[i].w = 0; can_add = false; } } else { uis[i].z += forward_speed * _speed; uis[i].w += back_speed * _speed; } } currentMaterial.SetVectorArray("_ArrayParams", uis); } private void Update() { if (Input.GetMouseButtonDown(0)) { // 主相機屏幕點轉換為射線 ray = Camera.main.ScreenPointToRay(Input.mousePosition); // 射線碰撞檢測 if (Physics.Raycast(ray, out hit)) { if (hit.transform == transform) { vector3 = transform.InverseTransformPoint(hit.point); can_add = true; } } } } }
通過修改 C# 腳本上的參數也能改變生成的漣漪效果
水波漣漪效果
👉 | 以上內容僅為學習參考、學習筆記使用 | 👈