先上效果图,一步一步拆解开:
(1)焦散
(2)水的颜色深浅的插值
(3)随着视角和相机的远近,会有一个圆圈的红色(这是自己设置的菲涅尔颜色,请留意一下)
(4)反射水中的倒影和倒影的扰动
(5)岸边的处理
(6)泡沫的处理:由弱变强 变弱
(7)在焦散中用到 还原scene的世界坐标:
详细介绍在这还原世界坐标
(8)泡沫波浪的感觉:
(9)水面的高度起伏变化:
(10) 总体的效果:
用到的知识点,之前的文章中都介绍过,如果不能理解代码的意图,请翻看前面的文章。
```csharp
Shader "Unlit/Water_Code"
{
Properties
{
_ReflectionTex("_ReflectionTex",2D) = "white"{}
_WaterNormal ("_WaterNormal", 2D) = "white" {}
_NormalTilling("_NormalTilling",float) = 2.5
_NoiseIntensity("_NoiseIntensity",float) = 3
_WaterSpeed("_WaterSpeed",vector) = (-4,0,0,0)
_WaterNoise("_WaterNoise",float) = 1
_DeepthColor("_DeepthColor",color) = (1,1,1,1)
_ShallowColor("_ShallowColor",color) = (1,1,1,1)
_DeepRange("_DeepRange",float) = 1
_FresnelColor("_FresnelColor",color) = (0,0,0,0)
_FresnalPower("_FresnalPower",range(0,10)) = 5
_ReflectDistort("_ReflectDistort",float) = 1
_ReflectIntensity("_ReflectIntensity",range(0,2)) = 0.8
_ReflectPower("_ReflectPower",range(0,10)) = 5
/// 水下折射扰动强度
_UnderWaterDistort("_UnderWaterDistort",range(0,2))= 1
焦散
_CausticsTex("_CausticsTex",2D) = "white"{}
_CausticsScale("_CausticsScale",float) = 8
_CausticsSpeed("_CausticsSpeed",vector) = (-8,1,0,0)
_CausticsIntensity("_CausticsIntensity",range(0,10)) = 3
_CausticsRange("_CausticsRange",range(0,2)) = 1
岸边
_ShoreColor("_ShoreColor",color) = (1.0,1.0,1.0,1.0)
_ShoreRange("_ShoreRange",range(0,5)) = 1
_ShoreEdgeWidth("_ShoreEdgeWidth",range(0,1.0)) = 0.2
_ShoreEdgeIntensity("_ShoreEdgeIntensity",float) = 0.2
泡沫
_FoamColor("_FoamColor",color) = (1,1,1,1)
_FoamRange("_FoamRange",float) = 1
_FoamBlend("_FoamBlend",range(0,1.0)) = 0
_FoamWidth("_FoamWidth",range(0,1)) = 0.15
_FoamFrequency("_FoamFrequency",float) = 15
_FoamSpeed("_FoamSpeed",float) = -1
_FoamNoise("_FoamNoise",vector) = (10,40,0,0)
_FoamDissolve("_FoamDissolve",range(0,1.5)) = 1.6
海浪的波形运动 (speedX,speedX,steepness,waveLength)
_WaveA("_WaveA",vector) = (1,-1,1.6,50)
_WaveB("_WaveB",vector) = (-0.5,-0.5,1.6,30)
_WaveC("_WaveC",vector) = (1,0.5,1.6,20)
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Grabpass{}
Pass
{
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityStandardUtils.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float3 worldPos : TEXCOORD1;
float3 worldTangent : TEXCOORD2;
float3 worldBinormal : TEXCOORD3;
float3 worldNormal : TEXCOORD4;
float4 screenPos : TEXCOORD5;
float4 GrabPos : TEXCOORD6;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _DeepthColor,_ShallowColor;
float _DeepRange;
float4 _NormalSpeed;
sampler2D_float _CameraDepthTexture;
sampler2D _NormalMap,_ReflectionTex;
float _NormalScale,_NormalNoise;
float4 _FresnelColor;
float _FresnalPower;
float _ReflectDistort;
float _ReflectPower,_ReflectIntensity;
sampler2D _CausticsTex;
float _CausticsScale,_CausticsRange;
float4 _CausticsSpeed;
float _CausticsIntensity;
float _ShoreRange,_ShoreEdgeWidth,_ShoreEdgeIntensity;
float4 _ShoreColor ,_FoamColor;
sampler2D _GrabTexture;
float _UnderWaterDistort;
sampler2D _WaterNormal;
float4 _WaterSpeed;
float _WaterNoise,_NoiseIntensity,_NormalTilling;
float _FoamRange,_FoamBlend,_FoamWidth,_FoamFrequency,_FoamSpeed,_FoamDissolve;
float4 _FoamNoise;
float4 _WaveA,_WaveB,_WaveC;
float2 GradientNoiseDir( float2 x )
{
const float2 k = float2( 0.3183099, 0.3678794 );
x = x * k + k.yx;
return -1.0 + 2.0 * frac( 16.0 * k * frac( x.x * x.y * ( x.x + x.y ) ) );
}
float GradientNoise( float2 UV, float Scale )
{
float2 p = UV * Scale;
float2 i = floor( p );
float2 f = frac( p );
float2 u = f * f * ( 3.0 - 2.0 * f );
return lerp( lerp( dot( GradientNoiseDir( i + float2( 0.0, 0.0 ) ), f - float2( 0.0, 0.0 ) ),
dot( GradientNoiseDir( i + float2( 1.0, 0.0 ) ), f - float2( 1.0, 0.0 ) ), u.x ),
lerp( dot( GradientNoiseDir( i + float2( 0.0, 1.0 ) ), f - float2( 0.0, 1.0 ) ),
dot( GradientNoiseDir( i + float2( 1.0, 1.0 ) ), f - float2( 1.0, 1.0 ) ), u.x ), u.y );
}
///
float3 GenerateWaveOffset(float3 worldPos,inout float3 tangent,inout float3 binormal,float4 wave)
{
float steepness = wave.z * 0.01;
float waveLength = wave.w ;
float k = 2 * UNITY_PI / waveLength;
float c = sqrt(9.8 / k);
float2 d = normalize(wave.xy);
float f = k * (dot(d,worldPos.xz) - c * _Time.y );
float a = steepness / k;
tangent += float3(-d.x * d.x * (steepness * sin(f)), d.x * (steepness * cos(f)),-d.x * d.y * (steepness * sin(f)));
binormal += float3(-d.x * d.y * (steepness * sin(f)), d.y * (steepness * cos(f)),-d.y * d.y * (steepness * sin(f)));
return float3(d.x * ( a * cos(f) ),a * sin(f),d.y * (a * cos(f)));
}
v2f vert (appdata v)
{
v2f o;
波形的顶点动画:
float3 worldPos = mul(unity_ObjectToWorld,v.vertex);
float3 tangent = float3(1,0,0);
float3 binormal = float3(0,1,0);
float3 offset1 = GenerateWaveOffset(worldPos,tangent,binormal,_WaveA);
float3 offset2 = GenerateWaveOffset(worldPos,tangent,binormal,_WaveB);
float3 offset3 = GenerateWaveOffset(worldPos,tangent,binormal,_WaveC);
float3 endWorldPos = worldPos + (offset1 + offset2 + offset3);
float3 objPos = mul( unity_WorldToObject,float4(endWorldPos,1));
v.vertex = float4(objPos.xyz,1.0);
float3 endNormal = normalize(cross(tangent,binormal));
endNormal = mul( unity_WorldToObject,float4(endNormal,0)).xyz;
v.normal = endNormal;
/
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
o.worldTangent = normalize(UnityObjectToWorldNormal(v.tangent));
o.worldBinormal =normalize(cross(o.worldTangent,o.worldNormal) * v.tangent.w);
o.screenPos = ComputeScreenPos(o.pos);
o.screenPos = ComputeGrabScreenPos(o.pos);
o.uv = v.uv;
COMPUTE_EYEDEPTH(o.screenPos.z);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
/// 还原世界坐标
float depth = tex2D(_CameraDepthTexture, i.screenPos.xy / i.screenPos.w).r;
float secneZ = LinearEyeDepth(depth);
float4 screenPos1 = float4(i.screenPos.xy /i.screenPos.w * 2.0 -1.0,0,-1);
float3 viewVector = mul(unity_CameraInvProjection,screenPos1);
float3 viewDir = normalize(mul(unity_CameraToWorld,viewVector));
float3 rebuildWorldPos = _WorldSpaceCameraPos + viewDir * secneZ;
//return float4(rebuildWorldPos,1.0);
float3 worldPos = i.worldPos;
float2 uv = worldPos.xz / _NormalTilling + (_Time.y * 0.1f * _WaterSpeed);
float2 uv3 = worldPos.xz / _NormalTilling * 2.0f + (_Time.y * 0.1f * _WaterSpeed * -0.5);
//float3 worldNormal = UnpackScaleNormal( tex2D(_WaterNormal,uv),_NoiseIntensity);
float3 worldNormal = UnpackNormal( tex2D(_WaterNormal,uv));
worldNormal.xy *= _NoiseIntensity;
worldNormal.z = sqrt(1.0 - dot(worldNormal.xy,worldNormal.xy));
float3 worldNormal1 = UnpackNormal( tex2D(_WaterNormal,uv3));
worldNormal1 *= _NoiseIntensity;
worldNormal1.z = sqrt(1.0 - dot(worldNormal1.xy,worldNormal1.xy));
worldNormal += worldNormal1;
worldNormal *= 0.5;
worldNormal.z = sqrt(1.0 - dot(worldNormal.xy,worldNormal.xy));
float3 tangentNormal = worldNormal;
worldNormal = normalize(mul(float3x3(i.worldTangent,i.worldBinormal,i.worldNormal),worldNormal));
//return float4(worldNormal.rgb,1.0);
/// 求出深度差
float sceneZ = LinearEyeDepth(tex2Dproj(_CameraDepthTexture,UNITY_PROJ_COORD(i.screenPos)).r);
float objZ = i.screenPos.z;
float diff = abs(sceneZ - objZ);
//return float4(diff.xxx,1.0);
float3 worldView = normalize(UnityWorldSpaceViewDir(worldPos));
/// 求出水的颜色 : 深水和浅水的 颜色插值 ; 水的颜色 和 水的折射的插值
float lerpFactor = saturate(exp(-diff / 5.0));
float4 waterColor = lerp(_DeepthColor,_ShallowColor,lerpFactor);
float fresnel = 0 + (1-0) * pow(max(dot(worldNormal,worldView),0.0001),_FresnalPower);
waterColor = lerp(waterColor,_FresnelColor,fresnel);
float waterOpacity = 1 - waterColor.a;
//return float4(waterColor.rgb,1.0f);
// 用菲涅尔 控制反射和折射的比率
// 反射颜色 reflectColor 用切线空间下的法线扰动,是因为该空间下的法线可以反映顶点局部空间下的法线方向 是基于UV坐标轴的
float2 screenPos = i.screenPos.xy / i.screenPos.w;
float2 uv_Reflect = tangentNormal.xy * (_ReflectDistort * 0.01) + screenPos;
float4 reflectColor = tex2D(_ReflectionTex,uv_Reflect);
float fresnel_Reflect = 0.0 + _ReflectIntensity * pow(max(dot(worldNormal,worldView),0.0001),_ReflectPower);
reflectColor = reflectColor * fresnel_Reflect;
//return float4(reflectColor.xyz,1.0);
float2 UV_grab = worldNormal.xz / (i.pos.w+1) * _UnderWaterDistort;
float4 sceneColor = tex2D(_GrabTexture,i.GrabPos.xy / i.GrabPos.w + UV_grab);
//return float4(sceneColor.rgb,1.0);
//焦散 : 用还原的世界坐标中的 xz 值 采样焦散图
float2 positionFromDepth = rebuildWorldPos.xz;
float2 uv1 = (positionFromDepth / _CausticsScale) + (_Time.y * _CausticsSpeed.xy * 0.01);
float2 uv2 = -(positionFromDepth / _CausticsScale) + (_Time.y * _CausticsSpeed.xy * 0.01);
float4 causticsColor1 = tex2D(_CausticsTex,uv1);
float4 causticsColor2 = tex2D(_CausticsTex,uv2);
float4 causticsColor = min(causticsColor1,causticsColor2) * _CausticsIntensity;
float causticsMask = saturate(exp(-diff / _CausticsRange));
causticsColor = causticsColor * causticsMask;
float4 underWaterColor = causticsColor + sceneColor;
//return float4(underWaterColor.rgb,1.0);
water shore 岸边的处理
float waterShore = saturate(exp(-diff / _ShoreRange));
float shoreEdge = smoothstep(1 - _ShoreEdgeWidth,1, waterShore) * _ShoreEdgeIntensity;
float3 shoreColor = (_ShoreColor * sceneColor).rgb;
//return float4(shoreColor.rgb,1.0);
Foam noise扰动
float foamNoise = GradientNoise(i.uv,_FoamNoise.xy);
Foam 泡沫的处理
float foamSorce = saturate(diff / _FoamRange);
float foamMask = 1 - smoothstep(_FoamBlend,1.0,foamSorce + 0.1);
float width = 1 - foamSorce - _FoamWidth;
float sinResult = sin(((1- foamSorce) * _FoamFrequency) + (_Time.y * _FoamSpeed));
//float4 foamColor = step(width,sinResult + foamNoise + - _FoamDissolve) * foamMask * _FoamColor;
float4 foamColor = step(width,sinResult + foamNoise +(1 - foamSorce) - _FoamDissolve) * foamMask * _FoamColor;
//return float4(foamColor.rgb,1.0);
/// 最后的结果
float4 waterFaceCOlor = lerp(reflectColor + waterColor, causticsColor, waterOpacity);
float3 faceColor = lerp(waterFaceCOlor.rgb,shoreColor,waterShore);
//return float4(faceColor,1.0);
float3 FaceColorWithFoam = lerp(faceColor,faceColor + foamColor.rgb,foamColor.a);
//return float4(FaceColorWithFoam,1.0);
float3 endColor = saturate(FaceColorWithFoam + shoreEdge);
return float4(endColor.rgb,1.0);
}
ENDCG
}
}
}
之前的水:水效果