当前位置: 首页 > news >正文

URP - 水效果Shader

一、水面颜色

利用屏幕深度纹理和水体面片的深度差来设置水面颜色,形成水面的颜色渐变

float4 frag(Varyings i):SV_Target
{//根据深度差设置水面颜色float2 ScreenUV = i.positionCS.xy/_ScreenParams.xy; //屏幕UVfloat depthTex =     SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,ScreenUV); //采样深度图depthTex = LinearEyeDepth(depthTex,_ZBufferParams); //将深度纹理的深度值转换到视图空间//(此时水体面片不渲染到深度图中)用深度图中的深度值与水体面片的在视图空间的深度值做差值,两者交接处颜色为0float depthDifference = depthTex+i.positionVS.z; //i.positionVS.z为负值,做差值时需两者相加//_depthIntensity用于调节深度差变化depthDifference *= _depthIntensity; //归一化depthDifference = saturate(depthDifference);//水面颜色float4 WaterColor_M = lerp(_EdgeColor,_CenterColor,depthDifference);return WaterColor_M;
}


 二、水面流动

采样两次流动的法线纹理并进行混合作为水面的流动效果

  • 在材质面板和Pass中分别声明法线纹理

        _NormalTex("NormalTex",2D)="white"{}

        //法线纹理
        TEXTURE2D(_NormalTex);
        SAMPLER(sampler_NormalTex);

  • 定义采样法线纹理所需要的UV,并使该纹理的重复和平铺有效同时使该纹理随时间而流动
o.normalUV.xy = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(1,1);
//*float2(-1.15,0.8)是使U方向朝负方向流动V方向正常,正常来说是*float2(-1,1),而数值改变是为了让纹理的重复感消失
o.normalUV.zw = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(-1.15,0.8);
  • 利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果
//水面法线
//利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果
float4 NormalTex01 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.xy);
float4 NormalTex02 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.zw);
float4 normalTex = NormalTex01*NormalTex02;

Shader"unity/Water02"
{Properties {[Header(Depth)][Space()]_depthIntensity("Depth Intensity",Range(0,0.2))=0.05[Header(WaterColor)][Space()]_CenterColor("Center Color",Color)=(1,1,1,1)_EdgeColor("Edge Color",Color)=(1,1,1,1)[Header(WaterFlowSpeed)][Space()]_FlowSpeed("Water FlowSpeed",float)=1[Header(Normal)][Space()]_NormalTex("NormalTex",2D)="white"{}}SubShader{Tags{"RenderPipeline" = "UniversalPipeline" "Queue"="Transparent" }Pass{HLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"#pragma vertex vert#pragma fragment frag//深度纹理TEXTURE2D(_CameraDepthTexture);SAMPLER(sampler_CameraDepthTexture);//法线纹理TEXTURE2D(_NormalTex);SAMPLER(sampler_NormalTex);CBUFFER_START(UnityPerMaterial)float4 _EdgeColor,_CenterColor,_NormalTex_ST;float _depthIntensity,_FlowSpeed;CBUFFER_ENDstruct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD;float4 normalUV : TEXCOORD1;};struct Varyings{float4 positionCS : SV_POSITION;float3 positionVS : TEXCOORD;float3 positionWS : TEXCOORD1;float2 uv : TEXCOORD2;float4 normalUV : TEXCOORD3;};Varyings vert(Attributes v){Varyings o = (Varyings)0;o.positionCS = TransformObjectToHClip(v.positionOS);o.positionWS = TransformObjectToWorld(v.positionOS);o.positionVS = TransformWorldToView(o.positionWS);o.normalUV.xy = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(1,1);//*float2(-1.15,0.8)是使U方向朝负方向流动V方向正常,正常来说是*float2(-1,1),而数值改变是为了让纹理的重复感消失o.normalUV.zw = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(-1.15,0.8);o.uv = v.uv;return o;}float4 frag(Varyings i):SV_Target{//根据深度差设置水面颜色float2 ScreenUV = i.positionCS.xy/_ScreenParams.xy; //屏幕UVfloat depthTex = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,ScreenUV); //采样深度图depthTex = LinearEyeDepth(depthTex,_ZBufferParams); //将深度纹理的深度值转换到视图空间//(此时水体面片不渲染到深度图中)用深度图中的深度值与水体面片的在视图空间的深度值做差值,两者交接处颜色为0float depthDifference = depthTex+i.positionVS.z; //i.positionVS.z为负值,做差值时需两者相加//_depthIntensity用于调节深度差变化depthDifference *= _depthIntensity; //归一化depthDifference = saturate(depthDifference);//水面颜色 (水下颜色可以与焦散相乘)float4 WaterColor_M = lerp(_EdgeColor,_CenterColor,depthDifference);//水面法线//利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果float4 NormalTex01 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.xy);float4 NormalTex02 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.zw);float4 normalTex = NormalTex01*NormalTex02;return normalTex;return WaterColor_M;}ENDHLSL}}}

三、水面高光 

float4 Specular =_SpecularColor*_SpecularIntensity*pow(max(0,dot(N,H)),_Shininess);

//H 为半角向量(入射光线和视线之间形成的半角向量)  H = L+V

//水面高光
//利用_NormalMixture来混合模型本身法线和法线纹理
float3 N = normalize(lerp(i.normalWS,normalTex,_NormalMixture));
Light light = GetMainLight();
float3 L = light.direction;
float3 V = normalize(_WorldSpaceCameraPos - i.positionWS);
float3 H = normalize(L+V);
float4 Specular = _SpecularColor * _SpecularIntensity * pow(max(0,dot(N,H)),_Shininess);

Shader"unity/Water02"
{Properties {[Header(Depth)][Space()]_depthIntensity("Depth Intensity",Range(0,0.2))=0.05[Header(WaterColor)][Space()]_CenterColor("Center Color",Color)=(1,1,1,1)_EdgeColor("Edge Color",Color)=(1,1,1,1)[Header(WaterFlowSpeed)][Space()]_FlowSpeed("Water FlowSpeed",float)=1[Header(Normal)][Space()]_NormalTex("NormalTex",2D)="white"{}_NormalMixture("Normal Mixture",float)=1[Header(Specular)][Space()]_SpecularColor("Specular Color",Color)=(1,1,1,1)_SpecularIntensity("Specular Intensity",float)=1_Shininess("Shininess",float)=1}SubShader{Tags{"RenderPipeline" = "UniversalPipeline" "Queue"="Transparent" }Pass{HLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"#pragma vertex vert#pragma fragment frag//深度纹理TEXTURE2D(_CameraDepthTexture);SAMPLER(sampler_CameraDepthTexture);//法线纹理TEXTURE2D(_NormalTex);SAMPLER(sampler_NormalTex);CBUFFER_START(UnityPerMaterial)float4 _EdgeColor,_CenterColor,_NormalTex_ST,_SpecularColor;float _depthIntensity,_FlowSpeed,_NormalMixture,_Shininess,_SpecularIntensity;CBUFFER_ENDstruct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD;float4 normalUV : TEXCOORD1;float3 normalOS : Normal;};struct Varyings{float4 positionCS : SV_POSITION;float3 positionVS : TEXCOORD;float3 positionWS : TEXCOORD1;float2 uv : TEXCOORD2;float4 normalUV : TEXCOORD3;float3 normalWS : TEXCOORD4;};Varyings vert(Attributes v){Varyings o = (Varyings)0;o.positionCS = TransformObjectToHClip(v.positionOS);o.positionWS = TransformObjectToWorld(v.positionOS);o.positionVS = TransformWorldToView(o.positionWS);o.normalUV.xy = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(1,1);//*float2(-1.15,0.8)是使U方向朝负方向流动V方向正常,正常来说是*float2(-1,1),而数值改变是为了让纹理的重复感消失o.normalUV.zw = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(-1.15,0.8);o.normalWS = TransformObjectToWorldNormal(v.normalOS);o.uv = v.uv;return o;}float4 frag(Varyings i):SV_Target{//根据深度差设置水面颜色float2 ScreenUV = i.positionCS.xy/_ScreenParams.xy; //屏幕UVfloat depthTex = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,ScreenUV); //采样深度图depthTex = LinearEyeDepth(depthTex,_ZBufferParams); //将深度纹理的深度值转换到视图空间//(此时水体面片不渲染到深度图中)用深度图中的深度值与水体面片的在视图空间的深度值做差值,两者交接处颜色为0float depthDifference = depthTex+i.positionVS.z; //i.positionVS.z为负值,做差值时需两者相加//_depthIntensity用于调节深度差变化depthDifference *= _depthIntensity; //归一化depthDifference = saturate(depthDifference);//水面颜色 (水下颜色可以与焦散相乘)float4 WaterColor_M = lerp(_EdgeColor,_CenterColor,depthDifference);//水面法线//利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果float4 NormalTex01 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.xy);float4 NormalTex02 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.zw);float4 normalTex = NormalTex01*NormalTex02;//水面高光//利用_NormalMixture来混合模型本身法线和法线纹理float3 N = normalize(lerp(i.normalWS,normalTex,_NormalMixture));Light light = GetMainLight();float3 L = light.direction;float3 V = normalize(_WorldSpaceCameraPos - i.positionWS);float3 H = normalize(L+V);float4 Specular = _SpecularColor * _SpecularIntensity * pow(max(0,dot(N,H)),_Shininess);float4 c;c = WaterColor_M;c += Specular;return c;//return WaterColor_M;}ENDHLSL}}}

四、水面反射以及菲尼尔

目前有好多种制作水面反射的方法

  1. 利用立方体纹理CubeMap
  2. 平面反射

          

目前还没有搞明白除了立方体纹理之外的其他反射效果如何制作,这里就先使用立方体纹理来制作反射效果吧

  • 首先在材质面板和Pass中定义立方体纹理,然后使用反射向量采样立方体纹理
  • 最后将反射颜色与菲尼尔相乘,使得平行看向水面时,反射率较强,垂直看向水面时,反射率较少
//水面反射以及菲尼尔
//利用_ReflectMixture来控制法线取值,与上一步制作高光的法线值区分
float3 N1 = lerp(i.normalWS,normalTex,_ReflectMixture);
float3 R = reflect(-V,N1); //反射向量
float4 ReflectTex = SAMPLE_TEXTURECUBE(_ReflectTex,sampler_ReflectTex,R);
float Fresnel = pow(max(0,1-dot(N,V)),_FresnelIntensity); //菲尼尔
float4 Reflect = ReflectTex*Fresnel;

Shader"unity/Water02"
{Properties {[Header(Depth)][Space()]_depthIntensity("Depth Intensity",Range(0,0.2))=0.05[Header(WaterColor)][Space()]_CenterColor("Center Color",Color)=(1,1,1,1)_EdgeColor("Edge Color",Color)=(1,1,1,1)[Header(WaterFlowSpeed)][Space()]_FlowSpeed("Water FlowSpeed",float)=1[Header(Normal)][Space()]_NormalTex("NormalTex",2D)="white"{}_NormalMixture("Normal Mixture",float)=1[Header(Specular)][Space()]_SpecularColor("Specular Color",Color)=(1,1,1,1)_SpecularIntensity("Specular Intensity",float)=1_Shininess("Shininess",float)=1[Header(Reflect)][Space()]_ReflectTex("ReflectTex",Cube)="white"{}_ReflectMixture("Reflect Mixture",float)=1_FresnelIntensity("Fresnel Intensity",float)=1}SubShader{Tags{"RenderPipeline" = "UniversalPipeline" "Queue"="Transparent" }Pass{HLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"#pragma vertex vert#pragma fragment frag//深度纹理TEXTURE2D(_CameraDepthTexture);SAMPLER(sampler_CameraDepthTexture);//法线纹理TEXTURE2D(_NormalTex);SAMPLER(sampler_NormalTex);//反射纹理TEXTURECUBE(_ReflectTex);SAMPLER(sampler_ReflectTex);CBUFFER_START(UnityPerMaterial)float4 _EdgeColor,_CenterColor,_NormalTex_ST,_SpecularColor;float _depthIntensity,_FlowSpeed,_NormalMixture,_Shininess,_SpecularIntensity,_FresnelIntensity,_ReflectMixture;CBUFFER_ENDstruct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD;float4 normalUV : TEXCOORD1;float3 normalOS : Normal;};struct Varyings{float4 positionCS : SV_POSITION;float3 positionVS : TEXCOORD;float3 positionWS : TEXCOORD1;float2 uv : TEXCOORD2;float4 normalUV : TEXCOORD3;float3 normalWS : TEXCOORD4;};Varyings vert(Attributes v){Varyings o = (Varyings)0;o.positionCS = TransformObjectToHClip(v.positionOS);o.positionWS = TransformObjectToWorld(v.positionOS);o.positionVS = TransformWorldToView(o.positionWS);o.normalUV.xy = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(1,1);//*float2(-1.15,0.8)是使U方向朝负方向流动V方向正常,正常来说是*float2(-1,1),而数值改变是为了让纹理的重复感消失o.normalUV.zw = TRANSFORM_TEX(v.normalUV,_NormalTex)-_Time.y*_FlowSpeed*float2(-1.15,0.8);o.normalWS = TransformObjectToWorldNormal(v.normalOS);o.uv = v.uv;return o;}float4 frag(Varyings i):SV_Target{//根据深度差设置水面颜色float2 ScreenUV = i.positionCS.xy/_ScreenParams.xy; //屏幕UVfloat depthTex = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,ScreenUV); //采样深度图depthTex = LinearEyeDepth(depthTex,_ZBufferParams); //将深度纹理的深度值转换到视图空间//(此时水体面片不渲染到深度图中)用深度图中的深度值与水体面片的在视图空间的深度值做差值,两者交接处颜色为0float depthDifference = depthTex+i.positionVS.z; //i.positionVS.z为负值,做差值时需两者相加//_depthIntensity用于调节深度差变化depthDifference *= _depthIntensity; //归一化depthDifference = saturate(depthDifference);//水面颜色 (水下颜色可以与焦散相乘)float4 WaterColor_M = lerp(_EdgeColor,_CenterColor,depthDifference);//水面法线//利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果float4 NormalTex01 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.xy);float4 NormalTex02 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.zw);float4 normalTex = NormalTex01*NormalTex02;//水面高光//利用_NormalMixture来混合模型本身法线和法线纹理float3 N = normalize(lerp(i.normalWS,normalTex,_NormalMixture));Light light = GetMainLight();float3 L = light.direction;float3 V = normalize(_WorldSpaceCameraPos - i.positionWS);float3 H = normalize(L+V);float4 Specular = _SpecularColor * _SpecularIntensity * pow(max(0,dot(N,H)),_Shininess);//水面反射以及菲尼尔//利用_ReflectMixture来控制法线取值,与上一步制作高光的法线值区分float3 N1 = lerp(i.normalWS,normalTex,_ReflectMixture);float3 R = reflect(-V,N1); //反射向量float4 ReflectTex = SAMPLE_TEXTURECUBE(_ReflectTex,sampler_ReflectTex,R);float Fresnel = pow(max(0,1-dot(N,V)),_FresnelIntensity); //菲尼尔float4 Reflect = ReflectTex*Fresnel;float4 c;c = WaterColor_M;c += Specular*Reflect;return c;return WaterColor_M;}ENDHLSL}}}

五、水下的折射扭曲

首先定义一个用于扭曲水下的纹理,采样此纹理,利用此纹理来改变屏幕UV,用扭曲后的屏幕UV来采样屏幕纹理

然后可以利用扭曲后的屏幕UV采样深度图,通过深度差来判断深度图中的物体是出于水面上还是水面下,若空间中的物体处于水面上,则采样屏幕纹理时的坐标使用水体面片的屏幕空间坐标

//水下的折射扭曲
//利用水体面片的世界空间下坐标采样用于扭曲水下的纹理
float3 DistortTex = UnpackNormal(SAMPLE_TEXTURE2D(_DistortTex,sampler_DistortTex,i.positionWS.xz*float2(_Refract_X,_Refract_Y)-_Time.y));
//偏移值
float2 offset = DistortTex.xy*_DistortIntensity;
//扭曲UV值
float2 DistortUV = ScreenUV + offset; //_DistortIntensity为扭曲强度值
//利用扭曲后的屏幕UV采样深度图
float DistortDepth = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,DistortUV);
//将深度图中的深度信息转换到视图空间
DistortDepth = LinearEyeDepth(DistortDepth,_ZBufferParams);
//计算深度图和水体面片在视图空间中的深度差(i.positionVS.z为负值,所以两者要相加)
float DistDepthDifferent = saturate(DistortDepth+i.positionVS.z);
//消除水面以上物体的扭曲,因为水面以上物体的深度值小于i.positionVS.z,所以DistDepthDifferent值为负时,使水面以上物体采样屏幕纹理的UV为屏幕UV(不进行扭曲)
if(DistDepthDifferent<=0)
{DistortUV = ScreenUV;}//最后利用上面计算得到的UV来采样屏幕纹理
float4 RefractTex = SAMPLE_TEXTURE2D(_CameraOpaqueTexture,sampler_CameraOpaqueTexture,DistortUV);

之后将折射扭曲与水体颜色值相乘

但是此时还是会有一点小Bug,就是会看到水下物体本身的轮廓

这个问题有会的宝子可以给点建议 

六、水下的焦散 

水下焦散的效果实现和之前学习的深度贴花的实现方法相同,需要利用面片在视图空间下的坐标值求出当前深度图中的像素在视图空间下的坐标值,再将此坐标值转换到世界空间下,用此坐标值作为UV来采样焦散纹理

//水下的焦散
//因为焦散纹理需要处于水底,而我们只能使用水体面片来采样焦散纹理。所以可以求出深度图中的像素位置在世界空间下的值,用此值作为UV来采样焦散纹理
float4 depthVS = 1;
depthVS.z = depthTex;
//求深度图中对应点的xy方向上的值
depthVS.xy = i.positionVS.xy * depthTex / -i.positionVS.z;
//将求得的视图空间下深度图中的位置信息转换到世界空间下
float3 depthWS = mul(unity_CameraToWorld,depthVS).xyz;
//用深度图中像素的在世界空间下位置作为UV来采样焦散纹理
//加depthWS.y的作用是使从上往下看同一个位置上的不同高度的点,在加上不同的高度值,从而使XZ方向的UV值错开从而采样不同的纹理
float2 uv1 = (depthWS.xz * _CausticTex_ST.xy + depthWS.y*_OffsetY)+_Time.y*_FlowSpeed;
float2 uv2 = (depthWS.xz * _CausticTex_ST.xy + depthWS.y*_OffsetY)+_Time.y*_FlowSpeed*float2(-1.15,0.9);
float4 CausticTex01 = SAMPLE_TEXTURE2D(_CausticTex,sampler_CausticTex,uv1);
float4 CausticTex02 = SAMPLE_TEXTURE2D(_CausticTex,sampler_CausticTex,uv2);
float4 CausticTex = min(CausticTex01,CausticTex02)*_CausticIntensity; //_CausticIntensity为焦散的强度值float4 c;
c = WaterColor_M;
c *= RefractTex;  //将折射扭曲与水体颜色相乘
c += Specular*Reflect;
c += CausticTex;
c = saturate(c);
return c;

七、水面上的泡沫

  •  首先需要声明泡沫纹理,然后采样该纹理

        o.uv = TRANSFORM_TEX(v.uv,_FoamTex); //使纹理的重复和平铺有效

        float4 FoamTex = SAMPLE_TEXTURE2D(_FoamTex,sampler_FoamTex,i.uv);

  • 然后利用深度差值和采样泡沫纹理后的值做step()运算
//水面的泡沫
//采样泡沫纹理
float4 FoamTex = SAMPLE_TEXTURE2D(_FoamTex,sampler_FoamTex,i.uv);
//_FoamNoise的值越大,FoamTex的黑色区域越多,后面求得的白色泡沫越少
FoamTex = pow(abs(FoamTex),_FoamNoise);
//step函数 step(a,b) 当a<b时,返回1; 当a>=b时,返回0 (此时靠近交接处的泡沫纹理的白色区域会形成泡沫遮罩,颜色为白色)
float FoamMask = step(depthDifference,FoamTex);
float Foam = FoamMask * _FoamColor;

八、代码部分

Shader"unity/Water02"
{Properties {[Header(Depth)][Space()]_depthIntensity("Depth Intensity",Range(0,0.2))=0.05[Header(WaterColor)][Space()]_CenterColor("Center Color",Color)=(1,1,1,1)_EdgeColor("Edge Color",Color)=(1,1,1,1)[Header(WaterFlowSpeed)][Space()]_FlowSpeed("Water FlowSpeed",float)=1[Header(Foam)][Space()]_FoamTex("FoamTex",2D)="white"{}_FoamColor("Foam Color",Color)=(1,1,1,1)_FoamNoise("FoamNoise",float)=1[Header(Normal)][Space()]_NormalTex("NormalTex",2D)="white"{}_NormalMixture("Normal Mixture",float)=1[Header(Specular)][Space()]_SpecularColor("Specular Color",Color)=(1,1,1,1)_SpecularIntensity("Specular Intensity",float)=1_Shininess("Shininess",float)=1[Header(Reflect)][Space()]_ReflectTex("ReflectTex",Cube)="white"{}_ReflectMixture("Reflect Mixture",float)=1_FresnelIntensity("Fresnel Intensity",float)=1[Header(Refract)][Space()][NoScaleOffset]_DistortTex("DistortTex",2D)="white"{}_Refract_X("Refract_X",float)=1_Refract_Y("Refract_Y",float)=1_DistortIntensity("Distort Intensity",float)=0 //折射纹理的扭曲强度[Header(Caustic)][Space()]_CausticTex("CausticTex",2D)="white"{}_OffsetY("Caustic OffsetY",float)=1_CausticIntensity("Caustic Intensity",float)=1}SubShader{Tags{"RenderPipeline" = "UniversalPipeline" "Queue"="Transparent" //一定要记得添加,要不然采样的屏幕纹理和深度纹理会有错误}// Blend SrcAlpha OneMinusSrcAlphaPass{HLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"#pragma vertex vert#pragma fragment frag//深度纹理TEXTURE2D(_CameraDepthTexture);SAMPLER(sampler_CameraDepthTexture);//泡沫纹理TEXTURE2D(_FoamTex);SAMPLER(sampler_FoamTex);//法线纹理TEXTURE2D(_NormalTex);SAMPLER(sampler_NormalTex);//反射纹理TEXTURECUBE(_ReflectTex);SAMPLER(sampler_ReflectTex);//折射纹理TEXTURE2D(_DistortTex);SAMPLER(sampler_DistortTex);//屏幕纹理TEXTURE2D(_CameraOpaqueTexture);SAMPLER(sampler_CameraOpaqueTexture);//焦散纹理TEXTURE2D(_CausticTex);SAMPLER(sampler_CausticTex);CBUFFER_START(UnityPerMaterial)float4 _EdgeColor,_CenterColor,_NormalTex_ST,_SpecularColor,_CausticTex_ST,_FoamTex_ST,_FoamColor;float _depthIntensity,_FlowSpeed,_NormalMixture,_Shininess,_SpecularIntensity,_FresnelIntensity,_ReflectMixture,_Refract_X,_Refract_Y,_DistortIntensity,_OffsetY,_CausticIntensity,_FoamNoise;CBUFFER_ENDstruct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD;float4 normalUV : TEXCOORD1;float3 normalOS : Normal;};struct Varyings{float4 positionCS : SV_POSITION;float2 uv : TEXCOORD;float3 positionVS : TEXCOORD1;float3 positionWS : TEXCOORD2;float4 normalUV : TEXCOORD3;float3 normalWS : TEXCOORD4;};Varyings vert(Attributes v){Varyings o = (Varyings)0;o.positionCS = TransformObjectToHClip(v.positionOS);o.positionWS = TransformObjectToWorld(v.positionOS);o.positionVS = TransformWorldToView(o.positionWS);o.normalUV.xy = TRANSFORM_TEX(v.normalUV,_NormalTex)+_Time.y*_FlowSpeed*float2(1,1);//*float2(-1.15,0.8)是使U方向朝负方向流动V方向正常,正常来说是*float2(-1,1),而数值改变是为了让纹理的重复感消失o.normalUV.zw = TRANSFORM_TEX(v.normalUV,_NormalTex)+_Time.y*_FlowSpeed*float2(-1.15,0.8);o.normalWS = TransformObjectToWorldNormal(v.normalOS);o.uv = TRANSFORM_TEX(v.uv,_FoamTex)+_Time.y*_FlowSpeed;return o;}float4 frag(Varyings i):SV_Target{//根据深度差设置水面颜色float2 ScreenUV = i.positionCS.xy/_ScreenParams.xy; //屏幕UVfloat depthTex = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,ScreenUV); //采样深度图depthTex = LinearEyeDepth(depthTex,_ZBufferParams); //将深度纹理的深度值转换到视图空间//(此时水体面片不渲染到深度图中)用深度图中的深度值与水体面片的在视图空间的深度值做差值,两者交接处颜色为0float depthDifference = depthTex+i.positionVS.z; //i.positionVS.z为负值,做差值时需两者相加//_depthIntensity用于调节深度差变化depthDifference *= _depthIntensity; //归一化depthDifference = saturate(depthDifference);//水面颜色 (水下颜色可以与焦散相乘)float4 WaterColor_M = lerp(_EdgeColor,_CenterColor,depthDifference);//水面的泡沫//采样泡沫纹理float4 FoamTex = SAMPLE_TEXTURE2D(_FoamTex,sampler_FoamTex,i.uv);//_FoamNoise的值越大,FoamTex的黑色区域越多,后面求得的白色泡沫越少FoamTex = pow(abs(FoamTex),_FoamNoise);//step函数 step(a,b) 当a<b时,返回1; 当a>=b时,返回0 (此时靠近交接处的泡沫纹理的白色区域会形成泡沫遮罩,颜色为白色)float FoamMask = step(depthDifference,FoamTex);float Foam = FoamMask * _FoamColor;//水面法线//利用两个流动不同方向的normalUV来采样法线纹理,最后将两者混合,做出水面流动的效果float4 NormalTex01 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.xy);float4 NormalTex02 = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.normalUV.zw);float4 normalTex = NormalTex01*NormalTex02;//水面高光//利用_NormalMixture来混合模型本身法线和法线纹理float3 N = normalize(lerp(i.normalWS,normalTex,_NormalMixture));Light light = GetMainLight();float3 L = light.direction;float3 V = normalize(_WorldSpaceCameraPos - i.positionWS);float3 H = normalize(L+V);float4 Specular = _SpecularColor * _SpecularIntensity * pow(max(0,dot(N,H)),_Shininess);//水面反射以及菲尼尔//利用_ReflectMixture来控制法线取值,与上一步制作高光的法线值区分float3 N1 = lerp(i.normalWS,normalTex,_ReflectMixture);float3 R = reflect(-V,N1); //反射向量float4 ReflectTex = SAMPLE_TEXTURECUBE(_ReflectTex,sampler_ReflectTex,R);float Fresnel = pow(max(0,1-dot(N,V)),_FresnelIntensity); //菲尼尔float4 Reflect = ReflectTex*Fresnel;//水下的折射扭曲//利用水体面片的世界空间下坐标采样用于扭曲水下的纹理float3 DistortTex = UnpackNormal(SAMPLE_TEXTURE2D(_DistortTex,sampler_DistortTex,i.positionWS.xz*float2(_Refract_X,_Refract_Y)+_Time.y));//偏移值float2 offset = DistortTex.xy*_DistortIntensity;//扭曲UV值float2 DistortUV = ScreenUV + offset; //_DistortIntensity为扭曲强度值//利用扭曲后的屏幕UV采样深度图float DistortDepth = SAMPLE_TEXTURE2D(_CameraDepthTexture,sampler_CameraDepthTexture,DistortUV);//将深度图中的深度信息转换到视图空间DistortDepth = LinearEyeDepth(DistortDepth,_ZBufferParams);//计算深度图和水体面片在视图空间中的深度差(i.positionVS.z为负值,所以两者要相加)float DistDepthDifferent = saturate(DistortDepth+i.positionVS.z);//消除水面以上物体的扭曲,因为水面以上物体的深度值小于i.positionVS.z,所以DistDepthDifferent值为负时,使水面以上物体采样屏幕纹理的UV为屏幕UV(不进行扭曲)if(DistDepthDifferent<=0){DistortUV = ScreenUV;}//最后利用上面计算得到的UV来采样屏幕纹理float4 RefractTex = SAMPLE_TEXTURE2D(_CameraOpaqueTexture,sampler_CameraOpaqueTexture,DistortUV);//水下的焦散//因为焦散纹理需要处于水底,而我们只能使用水体面片来采样焦散纹理。所以可以求出深度图中的像素位置在世界空间下的值,用此值作为UV来采样焦散纹理float4 depthVS = 1;depthVS.z = depthTex;//求深度图中对应点的xy方向上的值depthVS.xy = i.positionVS.xy * depthTex / -i.positionVS.z;//将求得的视图空间下深度图中的位置信息转换到世界空间下float3 depthWS = mul(unity_CameraToWorld,depthVS).xyz;//用深度图中像素的在世界空间下位置作为UV来采样焦散纹理//加depthWS.y的作用是使从上往下看同一个位置上的不同高度的点,在加上不同的高度值,从而使XZ方向的UV值错开从而采样不同的纹理float2 uv1 = (depthWS.xz * _CausticTex_ST.xy + depthWS.y*_OffsetY)-_Time.y*_FlowSpeed;float2 uv2 = (depthWS.xz * _CausticTex_ST.xy + depthWS.y*_OffsetY)-_Time.y*_FlowSpeed*float2(-1.15,0.9);float4 CausticTex01 = SAMPLE_TEXTURE2D(_CausticTex,sampler_CausticTex,uv1);float4 CausticTex02 = SAMPLE_TEXTURE2D(_CausticTex,sampler_CausticTex,uv2);float4 CausticTex = min(CausticTex01,CausticTex02)*_CausticIntensity; //_CausticIntensity为焦散的强度值float4 c;c = WaterColor_M * RefractTex;//将折射扭曲与水体颜色相乘c += Foam;c += Specular*Reflect;c += CausticTex;c = saturate(c);return c;return WaterColor_M;}ENDHLSL}}}

 

屏幕录制 2025-06-02 213020

http://www.xdnf.cn/news/775081.html

相关文章:

  • 类和对象(二)
  • 《Pytorch深度学习实践》ch3-反向传播
  • 使用ArcPy批量处理矢量数据
  • 力扣刷题Day 67:N 皇后(51)
  • 树莓派实验
  • 使用Bambi包进行贝叶斯混合效应模型分析
  • 强化学习-深度学习和强化学习领域
  • 通讯录Linux的实现
  • 如何选择合适的哈希算法以确保数据安全?
  • 列表推导式(Python)
  • 线程间和进程间是如何进行通信
  • PH热榜 | 2025-05-30
  • Linux中的mysql逻辑备份与恢复
  • 【AI+若依框架】基础应用篇
  • CUDA内存溢出问题解决方案
  • C++学习打卡1.01
  • SAP BC 修复MM60 报错的问题
  • MySQL 核心知识整理【一】
  • AI智能体|扣子(Coze)搭建【合同/文档审查】工作流
  • 应用程序错误 application error (0xc000007b) 处理方法
  • URL的结构与作用
  • ubuntu系统扩容
  • [SC]SystemC dont_initialize的应用场景详解(一)
  • 198. 打家劫舍
  • 如何用AI写作?
  • RFC 4862 IPv6 Stateless Address Autoconfiguration 翻译
  • [蓝桥杯]交换次数
  • 《汇编语言》第13章 int指令——实验13 编写、应用中断例程
  • Redis持久化机制详解:RDB与AOF的深度剖析
  • 麒麟信安安装谷歌浏览器