环境
下面代码的运行环境
- Unity : 2022.3.3f1
- Pipeline : URP
美术思路:获取屏幕中得一张RT图,传给Shader生成高度图,至于水的效果就按照正常流程去写,顶点起伏+水面反射(海水的话得加湍流)+ 泡沫 + 水边缘处理;目前水Shader还没写完后面有空再接着写;
代码如下,有注释(参考了很多文章,后面再优化效果和代码):
Shader "Ripples/Add" {
Properties {
}
SubShader {
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline" }
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
ENDHLSL
Pass {
Name "Add"
Tags { "LightMode"="UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_InteractiveTex);
SAMPLER(sampler_InteractiveTex);
TEXTURE2D(_CurrentRT);
SAMPLER(sampler_CurrentRT);
float _isRenderMousePointer;
float4 _PositionPoint;
v2f vert(a2v v) {
v2f o;
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
o.uv = v.uv;
return o;
}
half4 frag(v2f i) : SV_Target {
float c = SAMPLE_TEXTURE2D(_InteractiveTex, sampler_InteractiveTex, i.uv).r + //交互相机RT
SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT,i.uv).r + //上一帧RT
max(_PositionPoint.z - length(i.uv - _PositionPoint.xy)/_PositionPoint.z,0) * _isRenderMousePointer; //鼠标交互
//float c = SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT,i.uv).r + //上一帧RT
// max(_PositionPoint.z - length(i.uv - _PositionPoint.xy)/_PositionPoint.z,0) * _isRenderMousePointer; //鼠标交互
return c;
//return length(i.uv - _PositionPoint.xy);
//return max(_PositionPoint.z - length(i.uv - _PositionPoint.xy),0);
//return max(_PositionPoint.z - length(i.uv - _PositionPoint.xy)/_PositionPoint.z,0);
//return SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT,i.uv).r + max(_PositionPoint.z - length(i.uv - _PositionPoint.xy)/_PositionPoint.z,0);
}
ENDHLSL
}
}
}
Shader "Ripples/RippleShader"
{
Properties {
_Attenuation("Attenuation" , Range(0,1)) = 0.99
}
SubShader {
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline" }
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// CBUFFER_START(UnityPerMaterial)
//float _Attenuation;
// CBUFFER_END
ENDHLSL
Pass {
Name "Ripple"
Tags { "LightMode"="UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_PrevRT);
SAMPLER(sampler_PrevRT);
TEXTURE2D(_CurrentRT);
SAMPLER(sampler_CurrentRT);
float4 _CurrentRT_TexelSize;
float _Attenuation;
v2f vert(a2v v) {
v2f o;
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
o.uv = v.uv;
return o;
}
half4 frag(v2f i) : SV_Target {
//最小偏移单位
float3 e = float3(_CurrentRT_TexelSize.xy,0);
float2 uv =i.uv;
//获取上下左右四个值
float p10 = SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT, uv - e.zy).x;//下
float p01 = SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT, uv - e.xz).x;//左
float p21 = SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT, uv + e.xz).x;//右
float p12 = SAMPLE_TEXTURE2D(_CurrentRT, sampler_CurrentRT, uv + e.zy).x;//上
//中心值
float p11 = SAMPLE_TEXTURE2D(_PrevRT, sampler_PrevRT, uv).x;
//计算结果
float d = (p10 + p01 + p21 + p12) / 2 - p11;
//衰减
d *= _Attenuation;
return d;
}
ENDHLSL
}
}
}
Shader "water0829"
{
Properties
{
_SourceTexture("涟漪高度图", 2D) = "white" {}
_sampleDelta("高度偏移",range(0,1)) = 0.5
_FresnelPower("水面菲涅尔", Range(0.1,50)) = 5
_Amount("折射强度",float)=100
[Header(Turbulence)]
[Normal]_NormalMap("水面法线扰动",2D) = "bump"{}
_NormalIntensity("扰动强度",Range(0,5)) = 1
_NormalScale("扰动纹理缩放",Range(0,5)) = 1
_Offset("扰动纹理偏移",Range(-1,1)) = 0
_WaveXSpeed("扰动速度(X轴)",Range(0,1)) = 0.5
_WaveYSpeed("扰动速度(Y轴)",Range(0,1)) = 0.5
_NormalRefract("扰动折射",Range(0,1)) = 0.5
[NoScaleOffset]_CubeMap ("环境", CUBE) = "white" {}
[Header(WaterCol)]
[KeywordEnum(Col,RampTex)] DepthCol("水颜色模式(2选1)",Float) = 1
_DepthMaxDistance("水深度", Float) = 1
[Header(DepthCol)]
_DepthGradientShallow("浅水颜色", Color) = (0.325, 0.807, 0.971, 0.725)
_DepthGradientDeep("深水颜色", Color) = (0.086, 0.407, 1, 0.749)
[Header(DepthRampTex)]
_rampTex("水着色图",2D) = "white" {}
[Header(WavShape)]
_WavSpeed("波浪速率",Range(0,1))=1
_WavwA("波浪 A: directionX, directionZ, _Steepness, _Wavelength", Vector) = (1, 1, 0.8, 3.0)
_WavwB("波浪 B: directionX, directionZ, _Steepness, _Wavelength", Vector) = (1, 1, 0.8, 3.0)
_WavwC("波浪 C: directionX, directionZ, _Steepness, _Wavelength", Vector) = (1, 1, 0.8, 3.0)
_ShadowMainColor("阴影颜色", color) = (0,0,0,1)
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Pass
{ Tags{ "LightMode"="UniversalForward" }
Name "Unlit"
HLSLPROGRAM
// Required to compile gles 2.0 with standard srp library
#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
//自定义
#pragma multi_compile DEPTHCOL_COL DEPTHCOL_RAMPTEX
// URP 软阴影
#pragma multi_compile_fragment _ _SHADOWS_SOFT
// URP 主光阴影、联机阴影、屏幕空间阴影//
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTexture.hlsl"
#include "WaterMath.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float4 tangentOS : TANGENT;
float3 normalOS : NORMAL;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
float fogCoord : TEXCOORD1;
float4 screenPosition : TEXCOORD2;
float3 positionWS : TEXCOORD3;
float3 normalWS : TEXCOORD4;
float4 tangentWS : TANGENT;
};
CBUFFER_START(UnityPerMaterial)
float4 _SourceTexture_TexelSize; float _sampleDelta;
float _WavSpeed,_NormalIntensity,_NormalScale,_Offset,_WaveXSpeed,_WaveYSpeed,_NormalRefract;
float4 _WavwA,_WavwB,_WavwC;
float4 _DepthGradientShallow,_DepthGradientDeep,_ShadowMainColor; float _DepthMaxDistance,_FresnelPower,_CubemapMip;
float _Amount;
CBUFFER_END
TEXTURE2D (_rampTex); SAMPLER(sampler_rampTex);
TEXTURE2D (_SourceTexture); SAMPLER(sampler_SourceTexture);
TEXTURECUBE(_CubeMap); SAMPLER(sampler_CubeMap);
TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap);
SAMPLER(_CameraColorTexture); float4 _CameraColorTexture_TexelSize; //该向量是非本shader独有,不能放在常量缓冲区
Varyings vert(Attributes v)
{
Varyings o = (Varyings)0;
//多波叠加
float3 tangent = float3(0.0, 0.0, 0.0);
float3 bitangent = float3(0.0, 0.0, 0.0);
v.positionOS.xyz += gerstner(_WavwA, v.positionOS, tangent, bitangent, _WavSpeed); //_WavwB,_WavwC
v.positionOS.xyz += gerstner(_WavwB, v.positionOS, tangent, bitangent, _WavSpeed);
v.positionOS.xyz += gerstner(_WavwC, v.positionOS, tangent, bitangent, _WavSpeed);
o.normalWS = normalize(cross(bitangent, tangent));
VertexPositionInputs positionInputs = GetVertexPositionInputs(v.positionOS.xyz);
o.positionWS = positionInputs.positionWS;
o.positionHCS = positionInputs.positionCS;
o.screenPosition = ComputeScreenPos(o.positionHCS);
VertexNormalInputs normalInputs = GetVertexNormalInputs(v.normalOS, v.tangentOS); //计算世界空间中的法线和切线
o.tangentWS = half4(normalInputs.tangentWS, v.tangentOS.w * GetOddNegativeScale()); //世界空间的切线
o.uv = v.uv;
o.fogCoord = ComputeFogFactor(o.positionHCS.z);
return o;
}
half4 frag(Varyings i) : SV_Target
{
//阴影
float4 SHADOW_COORDS = TransformWorldToShadowCoord(i.positionWS.xyz);
Light lightDirectional = GetMainLight(SHADOW_COORDS);
half shadow = lightDirectional.shadowAttenuation;
//高度图
float2 Hdelta = float2(_SourceTexture_TexelSize.x*0.5, 0);
float u1 = SAMPLE_TEXTURE2D(_SourceTexture, sampler_SourceTexture, i.uv - Hdelta).r;
float u2 = SAMPLE_TEXTURE2D(_SourceTexture, sampler_SourceTexture, i.uv + Hdelta).r;
float3 du = float3(_sampleDelta, (u2 - u1), 0);
float2 Vdelta = float2(0, _SourceTexture_TexelSize.y * 0.5);
float v1 = SAMPLE_TEXTURE2D(_SourceTexture, sampler_SourceTexture, i.uv - Vdelta).r;
float v2 = SAMPLE_TEXTURE2D(_SourceTexture, sampler_SourceTexture, i.uv + Vdelta).r;
float3 dv = float3(0, (v2 - v1), _sampleDelta);
float3 waterNormal = cross(dv, du);
//向量准备
half3 L = normalize(lightDirectional.direction);
half3 V = normalize(_WorldSpaceCameraPos.xyz - i.positionWS.xyz);
half3 N01 = waterNormal;
half3 N02 = i.normalWS;
half3 blendedNormal = lerp(N01, N02, 0.5);
//---------//uv偏移
float4 offsetColor = (SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap, i.uv
+ float2(_WaveXSpeed * _Time.x, 0))
+ SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap, float2(i.uv.y, i.uv.x)
+ float2(_WaveYSpeed * _Time.x, 0))) / 2;
half2 offset = UnpackNormal(offsetColor).xy * _NormalRefract; //法线偏移程度可控之后offset被用于这里
//切线转世界
half3 normalTS1 = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap,i.uv*_NormalScale+offset)); //对法线纹理采样(切线)
half3 normalTS2 = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap,i.uv*_NormalScale-offset)); //对法线纹理采样(切线)
half3 normalTS3 = normalize(normalTS1+normalTS2);
normalTS3.xy *= _NormalIntensity;
normalTS3.z = sqrt(1 - saturate(dot(normalTS3.xy, normalTS3.xy)));
half3 binormalWS = cross(blendedNormal, normalTS3.xyz) * i.tangentWS.w; //世界空间下的副切线
half3 NormalWS = normalize(mul(normalTS3,half3x3(i.tangentWS.xyz,binormalWS,blendedNormal))); //将切线空间中的法线转换到世界空间中
//blendedNormal = lerp(blendedNormal, NormalWS, 0.5);
half3 vrDirWS = reflect(-V, NormalWS); // 反射
//折射
float2 SS_texcoord = i.positionHCS.xy/_ScreenParams.xy;//获取屏幕UV
float2 SS_bias=normalTS3.xy*_Amount*_CameraColorTexture_TexelSize;//如果取的是切线空间的法线则执行它计算偏移,但是切线空间的法线不随着模型的旋转而变换;
half3 refract = tex2D(_CameraColorTexture, SS_texcoord+SS_bias).rgb;
//计算结果
half NdotL = max(dot(blendedNormal, L),1e-5);
half3 SampleCubeMap = SAMPLE_TEXTURECUBE_LOD(_CubeMap, sampler_CubeMap, vrDirWS,_CubemapMip).rgb;
half fresnel = pow((1- (dot(blendedNormal,V))),_FresnelPower);
half3 ref = lerp(refract,SampleCubeMap, fresnel)+pow(fresnel,100);
//水的颜色
float2 screenPos= i.screenPosition.xy / i.screenPosition .w;
float depth = LinearEyeDepth(SampleSceneDepth(screenPos), _ZBufferParams);
float depthDifference = depth - i.screenPosition.w;
depthDifference = saturate(depthDifference / _DepthMaxDistance);
//两个方法
#if DEPTHCOL_COL
float4 waterColor = lerp(_DepthGradientShallow, _DepthGradientDeep, depthDifference);
//waterColor.a*= depthDifference;
#elif DEPTHCOL_RAMPTEX
depthDifference = clamp(0,0.99,depthDifference);
float3 DepthColor = SAMPLE_TEXTURE2D(_rampTex,sampler_rampTex,(depthDifference + 0.2)*4/5);
float alpha = (0,1,depthDifference);
float4 waterColor = float4(DepthColor,alpha);
waterColor = float4(waterColor.rgb,alpha);
#endif
shadow = shadow*depthDifference; //阴影矫正边缘过硬
waterColor.rgb = MixFog(waterColor.rgb, i.fogCoord);
waterColor.rgb = lerp(_ShadowMainColor.rgb * waterColor.rgb, waterColor.rgb, shadow);
waterColor.rgb += ref;
half4 Debug = float4(vrDirWS,1);
return waterColor;
}
ENDHLSL
}
}
}
水还没写完,后面有空再写,后面有空再写~