在開始之前,先看一下最終的動態效果。

視頻封面

00:08水桶里的圓形波紋水面

實現思路

  1. 水面是使用的Unity內置的plane模型,通過內置的Time變數更改它的紋理坐標,從而產生動態的波紋
  2. 計算紋理坐標到中心點的距離,通過clip函數將除了圓形之外的部分裁切掉,就會剩下圓形的水面了

資源準備

一張水面的貼圖

water texture

如果想要更好的效果,可以自行準備一個水桶或者杯子的模型,用來更好的襯托我們的水面。


定義變數

Shader "My Shader/Wave Water"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
_MainColor("Main Coloe (RGBA)", Color) = (1,1,1,1)
_WaveHeight("Wave Height",Range(0,0.1)) = 0.01
_WaveFrequency("Wave Frequency",Range(1,100)) = 50
_WaveSpeed("Wave Speed",Range(0,10)) = 1
}

  1. 定義水面波紋的貼圖
  2. 定義一個顏色變數,其中RGB用於控制水面波紋的顏色,A用於控制材質的透明度
  3. 定義波紋的波動高度
  4. 定義波紋出現的頻率
  5. 定義波紋的波動速度

編譯指令

SubShader
{
Tags{"Queue"="Transparent"}

Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

因為我們想要水面透明顯示,所以把它的渲染序列放在Transparent里,關閉深度寫入,開啟混合模式。這屬於透明shader的標準設置。

定義頂點著色器和片段著色器,然後把Unity的內置文件包含進來。

再次聲明變數

struct v2f
{
float4 vertex:SV_POSITION;
float2 uv:TEXCOORD0;
};

sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _MainColor;

float _WaveHeight;
float _WaveFrequency;
float _WaveSpeed;

  1. 定義v2f結構體,裡邊包含頂點坐標和紋理坐標
  2. 將上述所有的變數在CG里重新定義一遍,多出來的_MainTex_ST變數是水面貼圖的Tiling和Offset,用於計算紋理坐標

定義頂點著色器

v2f vert (appdata_base v)
{
v2f o;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
o.vertex = UnityObjectToClipPos(v.vertex);

return o;
}

在頂點著色器里我們進行了以下操作:

  1. 使用UnityCG.cginc里包含的appdata_base結構體作為頂點著色器的輸入結構體
  2. 在頂點著色器里,使用宏TRANSFORM_TEX計算_MainTex的紋理坐標
  3. 將頂點坐標變換到裁切空間
  4. 最後輸出到v2f結構體

定義片段著色器

fixed4 frag(v2f IN) : SV_Target
{
float2 uvCoord = _MainTex_ST.xy*0.5;

fixed2 uvDir = normalize(IN.uv-uvCoord);
fixed uvDis = distance(IN.uv,uvCoord);

clip(uvCoord-uvDis);

fixed2 uv = IN.uv+sin(uvDis*_WaveFrequency - _Time.y*_WaveSpeed)*_WaveHeight*uvDir;

fixed4 color;
color.rgb = tex2D(_MainTex, uv)*_MainColor;
color.a = _MainColor.a;
return color;
}
ENDCG
}
}
FallBack "Transparent"
}

片段著色器是本shader里最重要的部分,在這裡我們進行了以下操作:

  1. 將v2f結構體輸入到片段著色器
  2. _MainTex_ST是一個四維向量,其中xy是UV的Tiling,乘以0.5表示紋理坐標的中間點,保存到新定義的變數uvCoord里
  3. 定義變數uvDir,等於紋理坐標到中心點的方向。是從中心點朝向四周放射的形狀
  4. 定義變數uvDis,等於紋理坐標到中心點的距離。且從中心點向四周線性遞增,到達邊界的距離為uvCoord,到達四個頂點的距離大於uvCoord
  5. 使用uvCoord減去uvDis,得出一個以中心點為原點,uvCoord為半徑的圓,而圓之外的數值小於零。使用clip函數把結果小於0的像素全部裁切,最後只剩下圓形
  6. uvDis乘以_WaveFrequency變數,用於控制sin函數的頻率,時間變數乘以_WaveSpeed是為了控制sin函數的速度,兩個之所以相減,是為了讓波紋是從中心向四周擴散的。如果用加,會出現波紋從四周向中心彙集的效果。乘以_WaveHeight變數用於控制sin函數的振幅,再乘以方向變數uvDir變為二維向量。結果加在最開始的紋理坐標IN.uv上
  7. 使用新的紋理坐標uv變數對水面貼圖進行採樣,然後乘以顏色變數作為顏色輸出,顏色的A通道作為透明度。最後返回color

材質面板

最後的材質面板以及變數的參數如下:


推薦閱讀:
相关文章