Unityshaderglsl着色器特效之模拟海面海浪效果
- 电脑硬件
- 2025-08-23 09:48:01

一个简单的海浪效果,通过波的叠加实现水面起伏的动效,根据波峰斜率来为浪花着色,再根据法线贴图和水花贴图来和调整uv的平滑移动来增强海浪移动的细节。如果需要更逼真的效果可以考虑在满足浪花触发的地方添加粒子系统
前置效果图 因为是很久以前写的文章,贴图已经找不到了,随便PS了两张看看效果 inspector的可调项目
原理介绍水波部分使用4个不同参数的Gerstner波叠加,不同波长(10m/5m/3m/7m)不同传播方向(0°/45°/90°/135°),动态计算顶点偏移量:
offset += GerstnerWave(10.0, 0.3, 1.2, 0.0, worldPos, tangent, binormal);通过交叉计算切线/副切线生成基础法线,叠加噪声贴图增加细节:
float3 noiseNormal = UnpackNormal(tex2D(_NoiseTex, IN.uv_NoiseTex)); o.Normal = normalize(noiseNormal + o.Normal);水花效果实现,基于表面坡度检测生成水花:
float slope = 1 - o.Normal.y; float foam = saturate(slope * 5 - 0.7) * foamTex.r;光源反馈采用菲涅尔反射效果:
float fresnel = pow(1.0 - saturate(dot(o.Normal, IN.viewDir)), 4);动态镜面反射:
o.Smoothness = _Gloss * (1 - foam); 完整代码 Shader "Custom/OceanWave" { Properties { _MainColor ("Main Color", Color) = (0.1, 0.3, 0.6, 1) _FoamColor ("Foam Color", Color) = (1,1,1,1) _WaveScale ("Wave Scale", Range(0,2)) = 0.5 _WaveSpeed ("Wave Speed", Range(0,5)) = 1.2 _NoiseTex ("Noise Texture", 2D) = "white" {} _FoamTex ("Foam Texture", 2D) = "white" {} _Gloss ("Gloss", Range(0,1)) = 0.8 _NoiseUVSpeed ("Noise UV Speed", Vector) = (0.1, 0.1, 0, 0) // 添加噪声纹理UV移动速度 _FoamUVSpeed ("Foam UV Speed", Vector) = (0.1, 0.1, 0, 0) // 添加水花纹理UV移动速度 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard vertex:vert addshadow #pragma target 3.0 #include "UnityCG.cginc" struct Input { float3 worldPos; float3 viewDir; float2 uv_NoiseTex; float2 uv_FoamTex; }; // 属性声明 fixed4 _MainColor; fixed4 _FoamColor; sampler2D _NoiseTex; sampler2D _FoamTex; float _WaveScale; float _WaveSpeed; float _Gloss; float4 _NoiseUVSpeed; float4 _FoamUVSpeed; // Gerstner波函数 float3 GerstnerWave( float wavelength, float amplitude, float speed, float direction, float3 position, inout float3 tangent, inout float3 binormal) { float k = 2 * UNITY_PI / wavelength; float c = sqrt(9.8 / k); float2 d = float2(sin(direction), cos(direction)); float f = k * (dot(d, position.xz) - c * speed * _Time.y); float a = amplitude / k; tangent += float3( -d.x * d.x * (amplitude * sin(f)), d.x * (amplitude * cos(f)), -d.x * d.y * (amplitude * sin(f)) ); binormal += float3( -d.x * d.y * (amplitude * sin(f)), d.y * (amplitude * cos(f)), -d.y * d.y * (amplitude * sin(f)) ); return float3( d.x * (a * cos(f)), a * sin(f), d.y * (a * cos(f)) ); } // 顶点着色器 void vert(inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; float3 tangent = float3(1,0,0); float3 binormal = float3(0,0,1); float3 offset = 0; // 叠加四个不同参数的波浪 offset += GerstnerWave(10.0, 0.3, 1.2, 0.0, worldPos, tangent, binormal); offset += GerstnerWave(5.0, 0.2, 1.5, 0.785, worldPos, tangent, binormal); offset += GerstnerWave(3.0, 0.1, 2.0, 1.570, worldPos, tangent, binormal); offset += GerstnerWave(7.0, 0.15, 1.0, 2.356, worldPos, tangent, binormal); // 计算法线 float3 normal = normalize(cross(binormal, tangent)); v.normal = mul((float3x3)unity_WorldToObject, normal); worldPos += offset; v.vertex.xyz = mul(unity_WorldToObject, float4(worldPos, 1)).xyz; } // 表面着色器 void surf (Input IN, inout SurfaceOutputStandard o) { // 计算UV偏移 float2 noiseUVOffset = _NoiseUVSpeed.xy * _Time.y; float2 foamUVOffset = _FoamUVSpeed.xy * _Time.y; // 应用UV偏移 float2 noisyUV = IN.uv_NoiseTex + noiseUVOffset; float2 foamUV = IN.uv_FoamTex + foamUVOffset; // 基础颜色 fixed4 mainColor = _MainColor; // 法线计算 float3 noiseNormal = UnpackNormal(tex2D(_NoiseTex, noisyUV)); o.Normal = normalize(noiseNormal + o.Normal); // 水花效果 float slope = 1 - o.Normal.y; fixed4 foamTex = tex2D(_FoamTex, foamUV); float foam = saturate(slope * 5 - 0.7) * foamTex.r; // 菲涅尔反射 float fresnel = pow(1.0 - saturate(dot(o.Normal, IN.viewDir)), 4); // 最终颜色合成 o.Albedo = lerp(mainColor.rgb, _FoamColor.rgb, foam); o.Metallic = 0.0; o.Smoothness = _Gloss * (1 - foam); o.Alpha = mainColor.a; } ENDCG } FallBack "Diffuse" }Unityshaderglsl着色器特效之模拟海面海浪效果由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Unityshaderglsl着色器特效之模拟海面海浪效果”