因为近期需要将之前 Built-in RP 升级到 URP,所以啊,要调整的内容真的是多
其中,在以前自定义 shader 中使用到 阴影的部分,都需要调整一下,使用 URP 自带的 shader API(如果自己写阴影方案,但是又没有 unity 引擎源码,你会遇到一堆问题,例如,你可以看看我之前写的一篇:Unity Shader - Custom Shadow Map (New Version) - 这其中就遇到 LOD 问题、ReplaceShader 功能不够强大的问题)
OK,下面将的是:使用 URP 的 Shadow Caster Pass
ShaderLab 中引用其他 Shader 中的 Pass 是很简单的用到:UsePass
,如下:
// jave.lin : 使用 Universal 中自带的 Universal Render Pipeline/Lit Shader 中的 ShadowCaster Pass
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
用现成的多数情况下是比较方便的,但就是限制在使用现有的功能,虽然说可以修改 URP 的 shader ,但是如果你升级 URP 版本就不方便了
使用 URP 的 Shadow Caster 需要注意:该 Pass 使用了 Instancing,如果你的材质没有开启Instancing 开关,那么可以在 FrameDebugger 看到是没有合批的,一个一个的绘制,效率低下,如下图:
如果我们在材质勾上 instancing 就可以看到合批了
有两个选择:那么要 instancing? 还是 SRP Batcher 呢?这要看你自己去权衡,但是这里有一些建议:
如何 SRP Batcher 主要是将 uniform 变量都划分到对应的 CBuffer 块中,可以查看我之前一篇:Unity Shader - shader lab 的 SRP Batcher compatible 兼容性
OK,下面将的是自定义的 Shadow Caster Pass
自定义的好处就是,可以在很多功能上根据自己的需求来设置,最大化优化,但前提就是你要足够熟悉
从文档、还有 URP 的代码来看,shader 变体 需要注意几点:
Shader Pass 的 LightMode Tag,要设置为:ShadowCaster
,Like This : Tags{"LightMode" = "ShadowCaster"}
底层 pass filter 需要
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
控制是否开启、关闭接受功能的 变体,在 Light
的 Component 中调整:Shadow Type 即可看到效果
#pragma shader_feature _ALPHATEST_ON
shader_feature 的 alpha test 变体,便于树叶之类的镂空需要
总之 shader 变体就设置下面几个就好:
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma shader_feature _ALPHATEST_ON
如果说,你能确定你的 shader 不需要某些变体,如:已确定:需要阴影、且是软阴影,且是 alpha test 镂空,那么直接 #define
即可,不需要 Off 的情况,那么将这些变体宏统统改为 #define
明文定义,如下:
#define _MAIN_LIGHT_SHADOWS
#define _SHADOWS_SOFT
#define _ALPHATEST_ON
这样即可减少变体数量,但是代价就是不能中途同过 Shader.EnabledKeyword
, 或是 Shader.DisabledKeyword
C# 脚本API 来控制变体开关了,这需要你根据自己项目实际情况来选择
这和 Built-in RP 中的应用算法不太一样,但是这个可读性比 Built-in RP 的高很多,这两个参数具体在:
UniversalRenderPipelineAsset
资源的 Shadow/Depth Bias 和 Normal Bias
这两个参数都可以在:Shadows.hlsl
文件中的 ApplyShadowBias
方法中看到是如何应用的:
float3 ApplyShadowBias(float3 positionWS, float3 normalWS, float3 lightDirection)
{
float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS));
float scale = invNdotL * _ShadowBias.y;
// normal bias is negative since we want to apply an inset normal offset
positionWS = lightDirection * _ShadowBias.xxx + positionWS;
positionWS = normalWS * scale.xxx + positionWS;
return positionWS;
}
对应 Shader 的 Shadow Caster Pass 如下
Pass // jave.lin : 没有 ApplyShadowBias
{
Name "ShadowCaster"
Tags{ "LightMode" = "ShadowCaster" }
HLSLPROGRAM
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature _ALPHATEST_ON
// jave.lin : 根据你的 alpha test 是否开启而定
//#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
struct a2v {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o = (v2f)0;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
real4 frag(v2f i) : SV_Target
{
#if _ALPHATEST_ON
half4 col = tex2D(_MainTex, i.uv);
clip(col.a - 0.001);
#endif
return 0;
}
ENDHLSL
}
应用了 两个 bias 参数后,在 Depth Bias, Normal Bias 调整才能看到效果
shader 的 Shadow Caster Pass,如下:
Pass // jave.lin : 有 ApplyShadowBias
{
Name "ShadowCaster"
Tags{ "LightMode" = "ShadowCaster" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct a2v {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
// 以下三个 uniform 在 URP shadows.hlsl 相关代码中可以看到没有放到 CBuffer 块中,所以我们只要在 定义为不同的 uniform 即可
float3 _LightDirection;
float4 _ShadowBias; // x: depth bias, y: normal bias
half4 _MainLightShadowParams; // (x: shadowStrength, y: 1.0 if soft shadows, 0.0 otherwise)
// jave.lin 直接将:Shadows.hlsl 中的 ApplyShadowBias copy 过来
float3 ApplyShadowBias(float3 positionWS, float3 normalWS, float3 lightDirection)
{
float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS));
float scale = invNdotL * _ShadowBias.y;
// normal bias is negative since we want to apply an inset normal offset
positionWS = lightDirection * _ShadowBias.xxx + positionWS;
positionWS = normalWS * scale.xxx + positionWS;
return positionWS;
}
v2f vert(a2v v)
{
v2f o = (v2f)0;
float3 worldPos = TransformObjectToWorld(v.vertex.xyz);
half3 normalWS = TransformObjectToWorldNormal(v.normal);
worldPos = ApplyShadowBias(worldPos, normalWS, _LightDirection);
o.vertex = TransformWorldToHClip(worldPos);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
real4 frag(v2f i) : SV_Target
{
#if _ALPHATEST_ON
half4 col = tex2D(_MainTex, i.uv);
clip(col.a - 0.001);
#endif
return 0;
}
ENDHLSL
}
如果你的 shader lab 中各个 pass 使用到的 cbuffer 都最好定义在同一块,而不是每个 pass 中独立定义,这样才能最大限度发挥 SRP Batcher ,也提高 SRP Batcher Compatible 的可能
如:
Shader "xxx"
{
Properties { ... }
SubShader
{
Pass
{
Name "Body"
CBUFFER_START(UnityPerMaterial)
float4 _Params;
CBUFFER_END
}
Pass
{
Name "ShadowCaster"
CBUFFER_START(UnityPerMaterial)
float4 _Params;
CBUFFER_END
}
}
}
如上代码,可以看到 Body
, ShadowCaster
两个 Pass 中都有 CBUFFER 块的定义那么建议改为:
Shader "xxx"
{
Properties { ... }
SubShader
{
HLSLINCLUDE
CBUFFER_START(UnityPerMaterial)
float4 _Params;
CBUFFER_END
ENDHLSL
Pass
{
Name "Body"
}
Pass
{
Name "ShadowCaster"
}
}
}
就是把 CBUFFER 块定义在 HLSLINCLUDE ... ENDHLSL
中,也可以定义在独立的 *.hlsl
中,然后 #include "YourCBufferDef.hlsl"
进来也是可以的
浪费肯定会有的,但是,你要知道 CBUFFER 是共享的,而且我们这个不是 PerDraw 而是 PerMaterial 的 CBUFFER,几乎可以忽略不计,而且对 SRP Batcher Compatible 的话,通常情况下是有助于性能提升的
和 Built-in RP 中一样,在渲染提示的 Pass 中,只要添加对 Shadow Map 采样,在做深度比较,然后影响着色亮度即可达到 阴影 效果,下面是主要的渲染实体的 Pass 代码,主要看带有:jave.lin : shadow recieve 的注释部分的代码
Pass
{
HLSLPROGRAM
//#define _MAIN_LIGHT_SHADOWS
//#define _SHADOWS_SOFT
//#define _ALPHATEST_ON
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma shader_feature _ALPHATEST_ON
#pragma vertex vert
#pragma fragment frag
#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/CommonMaterial.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 shadowCoord : TEXCOORD1; // jave.lin : shadow recieve 在给到 fragment 时,要有阴影坐标
};
//CBUFFER_START(UnityPerMaterial)
// half4 _Color;
// half4 _Color1;
// float4 _MainTex_ST;
//CBUFFER_END
sampler2D _MainTex;
v2f vert (appdata v)
{
v2f o;
//o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
//o.vertex = TransformObjectToHClip(v.vertex.xyz);
float3 worldPos = TransformObjectToWorld(v.vertex.xyz);
o.vertex = TransformWorldToHClip(worldPos);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.shadowCoord = TransformWorldToShadowCoord(worldPos); // jave.lin : shadow recieve 将 世界坐标 转到 灯光坐标(阴影坐标)
return o;
}
half4 frag(v2f i) : SV_Target
{
half3 ambient = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
//Light mainLight = GetMainLight(i.shadowCoord); // jave.lin : shadow recieve 获取 shadowAttenuation 衰减值
//half shadow = mainLight.shadowAttenuation;
//return shadow;
//return unity_IndirectSpecColor;
half shadow = MainLightRealtimeShadow(i.shadowCoord); // jave.lin : shadow recieve 如果不需要用到 Light 结构的数据,可以直接使用该接口来获取
//real4 ambient = UNITY_LIGHTMODEL_AMBIENT;
//real4 ambient = glstate_lightmodel_ambient;
half4 col = tex2D(_MainTex, i.uv);
half4 finalCol = col * _Color * _Color1;
// 直接用 ambient 作为阴影色效果不太好
//finalCol.rgb = lerp(ambient.rgb, finalCol.rgb, shadow);
// 混合后的效果好很多
finalCol.rgb = lerp(finalCol.rgb * ambient.rgb, finalCol.rgb, shadow); // jave.lin : shadow recieve 我们可以将 ambient 作为阴影色
// jave.lin : shadow recieve 部分写法可以是:finalCol.rgb *= shadow; 也是看个人的项目需求来定
return finalCol;
}
ENDHLSL
}
阴影花纹(Shadow Pancaking)
引用 cat like coding 的博文中的图:
处理方式:
v2f vert(a2v v)
{
v2f o = (v2f)0;
float3 worldPos = TransformObjectToWorld(v.vertex.xyz);
half3 normalWS = TransformObjectToWorldNormal(v.normal);
worldPos = ApplyShadowBias(worldPos, normalWS, _LightDirection);
o.vertex = TransformWorldToHClip(worldPos);
// jave.lin : 参考 cat like coding 博主的处理方式
#if UNITY_REVERSED_Z
o.vertex.z = min(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#else
o.vertex.z = max(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#endif
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
理解 cat like coding 博主的这么处理的思路:
// jave.lin : 参考 cat like coding 博主的处理方式
#if UNITY_REVERSED_Z
o.vertex.z = min(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#else
o.vertex.z = max(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#endif
首先:UNITY_NEAR_CLIP_VALUE
单单从字面上理解就是 Unity相机的近截面值
这是里相机最近的有效值
我们知道,如果多边形的某些顶点如果离镜头过近,那么就会被 裁减掉
那么如果我们的 shadow space 空间的 camera 在拍摄某个 opaque 物体时,shadowmap 的内容就会出现镂空的问题,如下图:
解决它的方法就是:判断如果某些点比近截面还要 近
那么我们就将 这些点压扁到近截面 一样的位置就可以了
阴影的距离淡出
下面的 smoothstep 中 第一个参数是:开始弹出距离,第二个是,结束淡出距离,vz 就是 view space z 的意思
一般可以参数话调整,但是在 URP 中是没有这两个值的,你也可以扩展 URP 的脚本来控制
只要将下面的代码,再 fragment shader 中处理一下就可以了,传入一个 世界坐标位置,所以你可以理解为,将:世界坐标转为 视图坐标,取得 z 值做为距离
下面是在 FS 中计算 VZ 的,可以优化成:在 VS 中计算 VZ,然后作为 V2F 的插值变量传给 FS 即可
float GetDistanceFade(float3 positionWS)
{
float4 posVS = mul(GetWorldToViewMatrix(), float4(positionWS, 1));
//return posVS.z;
#if UNITY_REVERSED_Z
float vz = -posVS.z;
#else
float vz = posVS.z;
#endif
// jave.lin : 30.0 : start fade out distance, 40.0 : end fade out distance
float fade = 1 - smoothstep(30.0, 40.0, vz);
return fade;
}
应用 fade out 值:
half shadow = MainLightRealtimeShadow(i.shadowCoord); // jave.lin : shadow recieve 如果不需要用到 Light 结构的数据,可以直接使用该接口来获取
half shadowFadeOut = GetDistanceFade(i.positionWS); // jave.lin : 计算 shadow fade out
shadow = lerp(1, shadow, shadowFadeOut); // jave.lin : 阴影 shadow fade out
之前在项目中,发现很多 几何体表面 与 灯光方向 接近平行时,阴影会出现很多瑕疵
优化方法也比较简单,代码如下:
// jave.lin 优化 几何体表面 与 灯光方向 接近平行时,阴影会出现很多瑕疵的问题
half shadow = MainLightRealtimeShadow(i.shadowCoord); // jave.lin : shadow recieve 如果不需要用到 Light 结构的数据,可以直接使用该接口来获取
halfshadowFadeOut = GetDistanceFade(i.positionWS); // jave.lin : 计算 shadow fade out
shadow = lerp(1, shadow, shadowFadeOut); // jave.lin : 阴影 shadow fade out
// 假如你这里有个:diffuse
...
half diffuse = max(dot(N, L));
diffuse = min(diffuse, shadow);
half specular = ...
half factor = diffuse + specular * shadow;
// 这样使用 factor 来控制光阴的瑕疵就会少很多
// jave.lin 2021/10/14
Shader "Test/UnlitSTD"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1, 1, 1, 1)
_Color1 ("Color1", Color) = (1, 1, 1, 1)
[Toggle] _ALPHATEST ("Alpha Test On", Float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
half4 _Color;
half4 _Color1;
float4 _MainTex_ST;
CBUFFER_END
ENDHLSL
Pass
{
HLSLPROGRAM
//#define _MAIN_LIGHT_SHADOWS
//#define _SHADOWS_SOFT
//#define _ALPHATEST_ON
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma shader_feature _ALPHATEST_ON
#pragma vertex vert
#pragma fragment frag
#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/CommonMaterial.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 shadowCoord : TEXCOORD1; // jave.lin : shadow recieve 在给到 fragment 时,要有阴影坐标
float3 positionWS : TEXCOORD2;
};
//CBUFFER_START(UnityPerMaterial)
// half4 _Color;
// half4 _Color1;
// float4 _MainTex_ST;
//CBUFFER_END
sampler2D _MainTex;
v2f vert (appdata v)
{
v2f o;
//o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
//o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.positionWS = TransformObjectToWorld(v.vertex.xyz);
o.vertex = TransformWorldToHClip(o.positionWS);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.shadowCoord = TransformWorldToShadowCoord(o.positionWS); // jave.lin : shadow recieve 将 世界坐标 转到 灯光坐标(阴影坐标)
return o;
}
float GetDistanceFade(float3 positionWS)
{
float4 posVS = mul(GetWorldToViewMatrix(), float4(positionWS, 1));
//return posVS.z;
#if UNITY_REVERSED_Z
float vz = -posVS.z;
#else
float vz = posVS.z;
#endif
// jave.lin : 30.0 : start fade out distance, 40.0 : end fade out distance
float fade = 1 - smoothstep(30.0, 40.0, vz);
return fade;
}
half4 frag(v2f i) : SV_Target
{
half3 ambient = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
//Light mainLight = GetMainLight(i.shadowCoord); // jave.lin : shadow recieve 获取 shadowAttenuation 衰减值
//half shadow = mainLight.shadowAttenuation;
//return shadow;
//return unity_IndirectSpecColor;
half shadow = MainLightRealtimeShadow(i.shadowCoord); // jave.lin : shadow recieve 如果不需要用到 Light 结构的数据,可以直接使用该接口来获取
half shadowFadeOut = GetDistanceFade(i.positionWS); // jave.lin : 计算 shadow fade out
shadow = lerp(1, shadow, shadowFadeOut); // jave.lin : 阴影 shadow fade out
//real4 ambient = UNITY_LIGHTMODEL_AMBIENT;
//real4 ambient = glstate_lightmodel_ambient;
half4 col = tex2D(_MainTex, i.uv);
half4 finalCol = col * _Color * _Color1;
// 直接用 ambient 作为阴影色效果不太好
//finalCol.rgb = lerp(ambient.rgb, finalCol.rgb, shadow);
// 混合后的效果好很多
finalCol.rgb = lerp(finalCol.rgb * ambient.rgb, finalCol.rgb, shadow); // jave.lin : shadow recieve 我们可以将 ambient 作为阴影色
// jave.lin : shadow recieve 部分写法可以是:finalCol.rgb *= shadow; 也是看个人的项目需求来定
return finalCol;
}
ENDHLSL
}
Pass // jave.lin : 有 ApplyShadowBias
{
Name "ShadowCaster"
Tags{ "LightMode" = "ShadowCaster" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct a2v {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
// 以下三个 uniform 在 URP shadows.hlsl 相关代码中可以看到没有放到 CBuffer 块中,所以我们只要在 定义为不同的 uniform 即可
float3 _LightDirection;
float4 _ShadowBias; // x: depth bias, y: normal bias
half4 _MainLightShadowParams; // (x: shadowStrength, y: 1.0 if soft shadows, 0.0 otherwise)
// jave.lin 直接将:Shadows.hlsl 中的 ApplyShadowBias copy 过来
float3 ApplyShadowBias(float3 positionWS, float3 normalWS, float3 lightDirection)
{
float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS));
float scale = invNdotL * _ShadowBias.y;
// normal bias is negative since we want to apply an inset normal offset
positionWS = lightDirection * _ShadowBias.xxx + positionWS;
positionWS = normalWS * scale.xxx + positionWS;
return positionWS;
}
v2f vert(a2v v)
{
v2f o = (v2f)0;
float3 worldPos = TransformObjectToWorld(v.vertex.xyz);
half3 normalWS = TransformObjectToWorldNormal(v.normal);
worldPos = ApplyShadowBias(worldPos, normalWS, _LightDirection);
o.vertex = TransformWorldToHClip(worldPos);
// jave.lin : 参考 cat like coding 博主的处理方式
#if UNITY_REVERSED_Z
o.vertex.z = min(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#else
o.vertex.z = max(o.vertex.z, o.vertex.w * UNITY_NEAR_CLIP_VALUE);
#endif
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
real4 frag(v2f i) : SV_Target
{
#if _ALPHATEST_ON
half4 col = tex2D(_MainTex, i.uv);
clip(col.a - 0.001);
#endif
return 0;
}
ENDHLSL
}
// Pass // jave.lin : 没有 ApplyShadowBias
// {
// Name "ShadowCaster"
// Tags{ "LightMode" = "ShadowCaster" }
// HLSLPROGRAM
// #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// #pragma vertex vert
// #pragma fragment frag
// #pragma shader_feature _ALPHATEST_ON
// // jave.lin : 根据你的 alpha test 是否开启而定
// //#pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
// struct a2v {
// float4 vertex : POSITION;
// float2 uv : TEXCOORD0;
// };
// struct v2f {
// float4 vertex : SV_POSITION;
// float2 uv : TEXCOORD0;
// };
// v2f vert(a2v v)
// {
// v2f o = (v2f)0;
// o.vertex = TransformObjectToHClip(v.vertex.xyz);
// o.uv = TRANSFORM_TEX(v.uv, _MainTex);
// return o;
// }
// real4 frag(v2f i) : SV_Target
// {
//#if _ALPHATEST_ON
// half4 col = tex2D(_MainTex, i.uv);
// clip(col.a - 0.001);
//#endif
// return 0;
// }
// ENDHLSL
// }
// jave.lin : 使用 Universal 中自带的 Universal Render Pipeline/Lit Shader 中的 ShadowCaster Pass
//UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
}