Unity中URP实现水体(整理优化)

文章目录


前言

在之前的文章中,我们已经实现了水体几乎全部的效果。

但是,还有一些细节需要修改,代码可以优化。

在这篇文章中,我们就对水体Shader进行整理优化。


一、优化水的深度

1、我们把 水流动的方向 和 水深浅过渡值,整合到一个四维变量中

_WaterBase("Direction(XY) Atten(Z) Null(W)",Vector) = (1,1,1,1)

2、修改 水体流动方向

因为流动是,修改采样时使用的uv,在 顶点着色器 和 片元着色器 中,都有使用。所以,把它放在 v2f 结构体来存储,只需要计算一次。

  • 在v2f结构体定义

float2 timeOffset : TEXCOORD6;

  • 在顶点着色器计算,由方向值调节的流动
    代替原本所有语句中使用到的 _Time.y * _WaterSpeed

o.timeOffset = _Time.y * _WaterSpeed * _WaterBase.xy;

3、在片元着色器中,修改使用过渡变量

half4 waterColor = lerp(_WaterColor1, _WaterColor2, depthWater * _WaterBase.z);


二、优化泡沫

要优化泡沫的话,也是和深度同样的优化方法。只是我这里为了方便调节效果,就不做优化了。


三、优化水下的扭曲

1、修复原本扰动UV的计算

  • 这是原本的扭曲采样使用的uv,存在这种不正常的偏移效果

float2 distortUV = lerp(screenUV,normalTex.xy,_Distort);

  • 修改直接对屏幕uv乘以扰动值,在加上normalTex的方法实现线性过渡

float2 distortUV = screenUV * _Distort + normalTex.xy;


四、优化水面高光

1、把高光强度、光滑度、高光扭曲值,整合为一个四维变量

_SpecularBase("Specular : Intensity(X) Smoothness(Y) Distort(Z) Null(W)",Vector) = (0.6,10,0.5,1)

2、替换计算 高光反射 使用的法线 使用的 扭曲值

half4 N = lerp(half4(i.normalWS, 1), normalize(normalTex), _SpecularBase.z);

3、替换高光反射公式计算时,使用的光滑度

half4 specular = _SpecularColor * _SpecularBase.x * pow(max(0, dot(N.xyz, H)), _SpecularBase.y);


五、优化水的反射

  • 使用水下扭曲值,控制水反射法线的过渡值。从而和高光反射使用的法线分离开

half3 normalReflection = lerp(half4(i.normalWS, 1), normalize(normalTex), _Distort).xyz;


六、优化水的焦散

  • 水的焦散目前没有什么好优化的,就保持原本的吧。

七、最终优化代码

记着在优化时,编译Shader把所有的警告消除

复制代码
//水的深度
Shader "MyShader/URP/P4_8"
{
    Properties
    {
        [Header(Base)]
        _WaterColor1("WaterColor1",Color) = (1,1,1,1)
        _WaterColor2("WaterColor2",Color) = (1,1,1,1)
        [PowerSlider(3)]_WaterSpeed("WaterSpeed",Range(0,1)) = 0.1
        _WaterBase("Direction(XY) Atten(Z) Null(W)",Vector) = (1,1,1,1)

        [Header(Foam)]
        _FoamTex("FoamTex",2D) = "white"{}
        _FoamColor("FoamColor",Color) = (1,1,1,1)
        _FoamRange("FoamRange",Range(0,5)) = 1
        _FoamNoise("FoamNoise",Range(0,3)) = 1

        [Header(Distort)]
        _NormalTex("NormalTex",2D) = "white"{}
        [PowerSlider(3)]_Distort("Distort",Range(0,1)) = 0

        [Header(Specular)]
        _SpecularColor("Specular Color",Color) = (1,1,1,1)
        _SpecularBase("Specular : Intensity(X) Smoothness(Y) Distort(Z) Null(W)",Vector) = (0.6,10,0.5,1)

        [Header(Reflection)]
        _ReflectionTex("ReflectionTex",Cube) = "white"{}

        [Header(Caustics)]
        _CausticsTex("CausticsTex",2D) = "white"{}
    }
    SubShader
    {
        Tags
        {
            //告诉引擎,该Shader只用于 URP 渲染管线
            "RenderPipeline"="UniversalPipeline"
            //渲染类型
            "RenderType"="Transparent"
            //渲染队列
            "Queue"="Transparent"
        }
        //Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off
        Pass
        {

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // Pragmas
            #pragma target 2.0

            // Includes
            #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/Input.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            CBUFFER_START(UnityPerMaterial)
                half4 _WaterColor1;
                half4 _WaterColor2;

                half _WaterSpeed;
                half4 _WaterBase;

                half4 _FoamColor;
                half _FoamRange;
                half _FoamNoise;
                half4 _FoamTex_ST;

                half _Distort;
                half4 _NormalTex_ST;

                half4 _SpecularColor;
                half4 _SpecularBase;

                half4 _CausticsTex_ST;
            CBUFFER_END

            TEXTURE2D(_CameraDepthTexture);
            SAMPLER(sampler_CameraDepthTexture);
            TEXTURE2D(_FoamTex);
            SAMPLER(sampler_FoamTex);
            TEXTURE2D(_CameraOpaqueTexture);
            SAMPLER(sampler_CameraOpaqueTexture);
            TEXTURE2D(_NormalTex);
            SAMPLER(sampler_NormalTex);
            TEXTURECUBE(_ReflectionTex);
            SAMPLER(sampler_ReflectionTex);
            TEXTURE2D(_CausticsTex);
            SAMPLER(sampler_CausticsTex);
            //struct appdata
            //顶点着色器的输入
            struct Attributes
            {
                float3 positionOS : POSITION;
                float2 uv : TEXCOORD0;
                half3 normalOS : NORMAL;
            };

            //struct v2f
            //片元着色器的输入
            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0; //foamUV
                float4 screenPos : TEXCOORD1;
                float3 positionVS : TEXCOORD2;
                float3 positionWS : TEXCOORD3;
                float3 normalWS : TEXCOORD4;
                float4 normalUV : TEXCOORD5;
                float2 timeOffset : TEXCOORD6;
            };

            //v2f vert(Attributes v)
            //顶点着色器
            Varyings vert(Attributes v)
            {
                Varyings o = (Varyings)0;
                o.positionWS = TransformObjectToWorld(v.positionOS);
                o.positionVS = TransformWorldToView(o.positionWS);
                o.positionCS = TransformWViewToHClip(o.positionVS);

                o.screenPos = ComputeScreenPos(o.positionCS);
                //计算得到泡沫纹理采样需要的顶点世界空间下的坐标值的流动效果
                o.uv += o.positionWS.xz * _FoamTex_ST.xy + _Time.y * _WaterSpeed;
                //计算得到水下扭曲纹理的流动UV
                o.timeOffset = _Time.y * _WaterSpeed * _WaterBase.xy;
                o.normalUV.xy = TRANSFORM_TEX(v.uv, _NormalTex) + o.timeOffset;
                o.normalUV.zw = TRANSFORM_TEX(v.uv, _NormalTex) + o.timeOffset * float2(-1.3, 1.5);
                o.normalWS = TransformObjectToWorldNormal(v.normalOS);

                return o;
            }

            //fixed4 frag(v2f i) : SV_TARGET
            //片元着色器
            half4 frag(Varyings i) : SV_TARGET
            {
                //1、水的深度
                //获取屏幕空间下的 UV 坐标
                float2 screenUV = i.positionCS.xy / _ScreenParams.xy;
                half depthTex = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, screenUV).x;
                //深度图转化到观察空间下
                float depthScene = LinearEyeDepth(depthTex, _ZBufferParams);
                //获取水面模型顶点在观察空间下的Z值(可以在顶点着色器中,对其直接进行转化得到顶点观察空间下的坐标)
                float4 depthWater = depthScene + i.positionVS.z;

                //2、水的颜色,线性插值得到水 和 接触物体的水的 颜色的过度
                half4 waterColor = lerp(_WaterColor1, _WaterColor2, depthWater * _WaterBase.z);

                //3、水面泡沫
                //对泡沫纹理进行采样(这里使用顶点世界空间下的坐标进行纹理采样,防止水体缩放影响泡沫的平铺和重复方式)
                half4 foamTex = SAMPLE_TEXTURE2D(_FoamTex, sampler_FoamTex, i.uv.xy);

                foamTex = pow(abs(foamTex), _FoamNoise);

                //这里增加一个调整深度图范围的功能
                half4 foamRange = depthWater * _FoamRange;

                //使用泡沫纹理 和 泡沫范围 比较得到泡沫遮罩
                half4 foamMask = step(foamRange, foamTex);

                //给泡沫加上颜色
                half4 foamColor = foamMask * _FoamColor;

                //4、水下的扭曲
                half4 normalTex1 = SAMPLE_TEXTURE2D(_NormalTex, sampler_NormalTex, i.normalUV.xy);
                half4 normalTex2 = SAMPLE_TEXTURE2D(_NormalTex, sampler_NormalTex, i.normalUV.zw);
                half4 normalTex = normalTex1 * normalTex2;
                //float2 distortUV = lerp(screenUV,normalTex.xy,_Distort);
                float2 distortUV = screenUV * _Distort + normalTex.xy;
                half depthDistortTex = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, distortUV).x;
                half depthDistortScene = LinearEyeDepth(depthDistortTex, _ZBufferParams);
                half depthDistortWater = depthDistortScene + i.positionVS.z;
                float2 opaqueUV = distortUV;
                if (depthDistortWater < 0) opaqueUV = screenUV;
                half4 opaqueTex = SAMPLE_TEXTURE2D(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, opaqueUV);
                
                //5、水的高光
                //Specular = SpecularColor * Ks * pow(max(0,dot(N,H)), Shininess)
                Light light = GetMainLight();
                half3 L = light.direction;
                half3 V = normalize(_WorldSpaceCameraPos.xyz - i.positionWS.xyz);
                //修改法线实现,波光粼粼的效果
                half4 N = lerp(half4(i.normalWS, 1), normalize(normalTex), _SpecularBase.z);
                half3 H = normalize(L + V);
                half4 specular = _SpecularColor * _SpecularBase.x * pow(max(0, dot(N.xyz, H)), _SpecularBase.y);

                //6、水的反射
                half3 normalReflection = lerp(half4(i.normalWS, 1), normalize(normalTex), _Distort).xyz;
                half3 reflectionUV = reflect(-V, normalReflection.xyz);
                half4 reflectionTex = SAMPLE_TEXTURECUBE(_ReflectionTex, sampler_ReflectionTex, reflectionUV);
                half fresnel = 1 - saturate(dot(normalReflection, V));
                half4 reflection = reflectionTex * fresnel;

                //7、水的焦散
                float4 depthVS = 1;
                depthVS.xy = i.positionVS.xy * depthDistortScene / -i.positionVS.z;
                depthVS.z = depthDistortScene;
                float4 depthWS = mul(unity_CameraToWorld, depthVS);
                float4 depthOS = mul(unity_WorldToObject, depthWS);

                float2 uv1 = depthOS.xz * _CausticsTex_ST.xy + depthWS.y * 0.1 + i.timeOffset;
                float2 uv2 = depthOS.xz * _CausticsTex_ST.xy + depthWS.y * 0.1 + i.timeOffset * float2(-1.3, 1.5);

                half4 causticsTex1 = SAMPLE_TEXTURE2D(_CausticsTex, sampler_CausticsTex, uv1);
                half4 causticsTex2 = SAMPLE_TEXTURE2D(_CausticsTex, sampler_CausticsTex, uv2);
                half4 causticsTex = min(causticsTex1, causticsTex2);

                half4 col = (foamColor + waterColor) * opaqueTex + (specular * reflection) + causticsTex;

                return col;
            }
            ENDHLSL
        }
    }
    FallBack "Hidden/Shader Graph/FallbackError"
}
相关推荐
星夜泊客14 小时前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj202114 小时前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光15 小时前
Unity 模拟父子关系
android·unity·游戏引擎
在路上看风景18 小时前
26. Mipmap
unity
咸鱼永不翻身20 小时前
Unity视频资源压缩详解
unity·游戏引擎·音视频
在路上看风景20 小时前
4.2 OverDraw
unity
在路上看风景21 小时前
1.10 CDN缓存
unity
ellis19701 天前
Unity插件SafeArea Helper适配异形屏详解
unity
nnsix1 天前
Unity Physics.Raycast的 QueryTriggerInteraction枚举作用
unity·游戏引擎
地狱为王1 天前
Cesium for Unity叠加行政区划线
unity·gis·cesium