在URP中实现平面透射阴影
关于平面投射阴影,网上已经有很多文章介绍相关原理和优缺点:
这里记录一下在URP中的实现:
- 将URP Simple Lit Shader 源码拷贝新建一个Shader
- 修改成如下
// Shader targeted for low end devices. Single Pass Forward Rendering.
Shader "Custom/URP/Simple Lit"
{
// Keep properties of StandardSpecular shader for upgrade reasons.
Properties
{
[MainTexture] _BaseMap("Base Map (RGB) Smoothness / Alpha (A)", 2D) = "white" {}
[MainColor] _BaseColor("Base Color", Color) = (1, 1, 1, 1)
_Cutoff("Alpha Clipping", Range(0.0, 1.0)) = 0.5
_Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5
_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 0.5)
_SpecGlossMap("Specular Map", 2D) = "white" {}
_SmoothnessSource("Smoothness Source", Float) = 0.0
_SpecularHighlights("Specular Highlights", Float) = 1.0
[HideInInspector] _BumpScale("Scale", Float) = 1.0
[NoScaleOffset] _BumpMap("Normal Map", 2D) = "bump" {}
[HDR] _EmissionColor("Emission Color", Color) = (0,0,0)
[NoScaleOffset]_EmissionMap("Emission Map", 2D) = "white" {}
// Blending state
_Surface("__surface", Float) = 0.0
_Blend("__blend", Float) = 0.0
_Cull("__cull", Float) = 2.0
[ToggleUI] _AlphaClip("__clip", Float) = 0.0
[HideInInspector] _SrcBlend("__src", Float) = 1.0
[HideInInspector] _DstBlend("__dst", Float) = 0.0
[HideInInspector] _ZWrite("__zw", Float) = 1.0
[ToggleUI] _ReceiveShadows("Receive Shadows", Float) = 1.0
// Editmode props
_QueueOffset("Queue offset", Float) = 0.0
// ObsoleteProperties
[HideInInspector] _MainTex("BaseMap", 2D) = "white" {}
[HideInInspector] _Color("Base Color", Color) = (1, 1, 1, 1)
[HideInInspector] _Shininess("Smoothness", Float) = 0.0
[HideInInspector] _GlossinessSource("GlossinessSource", Float) = 0.0
[HideInInspector] _SpecSource("SpecularHighlights", Float) = 0.0
[HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {}
[HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {}
[HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {}
}
SubShader
{
Tags
{
"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" "IgnoreProjector" = "True" "ShaderModel"="4.5"
}
LOD 300
Pass
{
Name "PlanarShadowCaster"
Tags
{
"RenderType"="Transparent"
"Queue" = "Transparent"
"RenderPipeline" = "Universal"
"LightMode" = "SRPDefaultUnlit"
}
//用使用模板测试以保证alpha显示正确
Stencil
{
Ref 0
Comp equal
Pass incrWrap
Fail keep
ZFail keep
}
//透明混合模式
// Blend SrcAlpha OneMinusSrcAlpha
Blend One Zero
//关闭深度写入
ZWrite off
//深度稍微偏移防止阴影与地面穿插
Offset -1 , 0
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
ENDHLSL
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
float _GroundLevel;
// float4 _ShadowColor;
// float _ShadowFalloff;
float3 ShadowProjectPos(float4 vertPos, Light mainLight)
{
float3 shadowPos;
//得到顶点的世界空间坐标
float3 worldPos = TransformObjectToWorld(vertPos.xyz);
_GroundLevel = 0.5;
//灯光方向
float3 lightDir = normalize(mainLight.direction.xyz);
//阴影的世界空间坐标(低于地面的部分不做改变)
shadowPos.y = min(worldPos.y, _GroundLevel);
shadowPos.xz = worldPos.xz - lightDir.xz * max(0, worldPos.y - _GroundLevel) / lightDir.y;
return shadowPos;
}
v2f vert(appdata v)
{
v2f o;
Light mainLight = GetMainLight();
//得到阴影的世界空间坐标
float3 shadowPos = ShadowProjectPos(v.vertex, mainLight);
//转换到裁切空间
o.vertex = TransformWorldToHClip(shadowPos);
//得到中心点世界坐标
float3 center = float3(unity_ObjectToWorld[0].w, _GroundLevel, unity_ObjectToWorld[2].w);
//计算阴影衰减
float falloff = 1 - saturate(distance(shadowPos, center) * 0.2);
//阴影颜色
o.color = float4(0.18,.18,.18,1);
o.color.a *= 1;
return o;
}
half4 frag(v2f i) : SV_Target
{
return i.color;
}
ENDHLSL
}
Pass
{
Name "ForwardLit"
Tags
{
"LightMode" = "UniversalForward"
}
// Use same blending / depth states as Standard shader
Blend[_SrcBlend][_DstBlend]
ZWrite On
Cull[_Cull]
HLSLPROGRAM
// #pragma exclude_renderers gles gles3 glcore
// #pragma target 4.5
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local _RECEIVE_SHADOWS_OFF
#pragma shader_feature_local_fragment _SURFACE_TYPE_TRANSPARENT
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON
#pragma shader_feature_local_fragment _ _SPECGLOSSMAP _SPECULAR_COLOR
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Universal Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
#pragma multi_compile_fragment _ _LIGHT_LAYERS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile _ _CLUSTERED_RENDERING
// -------------------------------------
// Unity defined keywords
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile_fog
#pragma multi_compile_fragment _ DEBUG_DISPLAY
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#pragma multi_compile _ DOTS_INSTANCING_ON
#pragma vertex LitPassVertexSimple
#pragma fragment LitPassFragmentSimple
// #define BUMP_SCALE_NOT_SUPPORTED 1
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitForwardPass.hlsl"
ENDHLSL
}
// Pass
// {
// Name "ShadowCaster"
// Tags
// {
// "LightMode" = "ShadowCaster"
// }
//
// ZWrite On
// ZTest LEqual
// ColorMask 0
// Cull[_Cull]
//
// HLSLPROGRAM
// #pragma exclude_renderers gles gles3 glcore
// #pragma target 4.5
//
// // -------------------------------------
// // Material Keywords
// #pragma shader_feature_local_fragment _ALPHATEST_ON
// #pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
//
// //--------------------------------------
// // GPU Instancing
// #pragma multi_compile_instancing
// #pragma multi_compile _ DOTS_INSTANCING_ON
//
// // -------------------------------------
// // Universal Pipeline keywords
//
// // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
// #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
//
// #pragma vertex ShadowPassVertex
// #pragma fragment ShadowPassFragment
//
// #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
// #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
// ENDHLSL
// }
Pass
{
Name "GBuffer"
Tags
{
"LightMode" = "UniversalGBuffer"
}
ZWrite[_ZWrite]
ZTest LEqual
Cull[_Cull]
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
// -------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
//#pragma shader_feature _ALPHAPREMULTIPLY_ON
#pragma shader_feature_local_fragment _ _SPECGLOSSMAP _SPECULAR_COLOR
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local _RECEIVE_SHADOWS_OFF
// -------------------------------------
// Universal Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
//#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
//#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
#pragma multi_compile_fragment _ _LIGHT_LAYERS
// -------------------------------------
// Unity defined keywords
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
#pragma multi_compile_fragment _ _RENDER_PASS_ENABLED
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#pragma multi_compile _ DOTS_INSTANCING_ON
#pragma vertex LitPassVertexSimple
#pragma fragment LitPassFragmentSimple
#define BUMP_SCALE_NOT_SUPPORTED 1
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitGBufferPass.hlsl"
ENDHLSL
}
Pass
{
Name "DepthOnly"
Tags
{
"LightMode" = "DepthOnly"
}
ZWrite On
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
// -------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
// // This pass is used when drawing to a _CameraNormalsTexture texture
// Pass
// {
// Name "DepthNormals"
// Tags
// {
// "LightMode" = "DepthNormals"
// }
//
// ZWrite On
// Cull[_Cull]
//
// HLSLPROGRAM
// #pragma exclude_renderers gles gles3 glcore
// #pragma target 4.5
//
// #pragma vertex DepthNormalsVertex
// #pragma fragment DepthNormalsFragment
//
// // -------------------------------------
// // Material Keywords
// #pragma shader_feature_local _NORMALMAP
// #pragma shader_feature_local_fragment _ALPHATEST_ON
// #pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
//
// //--------------------------------------
// // GPU Instancing
// #pragma multi_compile_instancing
// #pragma multi_compile _ DOTS_INSTANCING_ON
//
// #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
// #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl"
// ENDHLSL
// }
}
SubShader
{
Tags
{
"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "SimpleLit" "IgnoreProjector" = "True" "ShaderModel"="2.0"
}
LOD 300
Pass
{
Name "ForwardLit"
Tags
{
"LightMode" = "UniversalForward"
}
// Use same blending / depth states as Standard shader
Blend[_SrcBlend][_DstBlend]
ZWrite On
Cull[_Cull]
HLSLPROGRAM
#pragma only_renderers gles gles3 glcore d3d11
#pragma target 2.0
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local _RECEIVE_SHADOWS_OFF
#pragma shader_feature_local_fragment _SURFACE_TYPE_TRANSPARENT
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON
#pragma shader_feature_local_fragment _ _SPECGLOSSMAP _SPECULAR_COLOR
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Universal Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fragment _ _LIGHT_LAYERS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile _ _CLUSTERED_RENDERING
// -------------------------------------
// Unity defined keywords
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile_fog
#pragma multi_compile_fragment _ DEBUG_DISPLAY
#pragma vertex LitPassVertexSimple
#pragma fragment LitPassFragmentSimple
#define BUMP_SCALE_NOT_SUPPORTED 1
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitForwardPass.hlsl"
ENDHLSL
}
Pass
{
Name "PlanarShadowCaster"
Tags
{
"RenderType"="Opaque"
"Queue" = "Opaque"
"RenderPipeline" = "Universal"
"LightMode" = "SRPDefaultUnlit"
}
//用使用模板测试以保证alpha显示正确
Stencil
{
Ref 0
Comp equal
Pass incrWrap
Fail keep
ZFail keep
}
//透明混合模式
Blend SrcAlpha OneMinusSrcAlpha
//关闭深度写入
ZWrite off
//深度稍微偏移防止阴影与地面穿插
Offset -1 , 0
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
ENDHLSL
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 color : COLOR;
};
float _GroundLevel;
float4 _ShadowColor;
float _ShadowFalloff;
float3 ShadowProjectPos(float4 vertPos, Light mainLight)
{
float3 shadowPos;
//得到顶点的世界空间坐标
float3 worldPos = TransformObjectToWorld(vertPos.xyz);
//灯光方向
float3 lightDir = normalize(mainLight.direction.xyz);
//阴影的世界空间坐标(低于地面的部分不做改变)
shadowPos.y = min(worldPos.y, _GroundLevel);
shadowPos.xz = worldPos.xz - lightDir.xz * max(0, worldPos.y - _GroundLevel) / lightDir.y;
return shadowPos;
}
v2f vert(appdata v)
{
v2f o;
Light mainLight = GetMainLight();
//得到阴影的世界空间坐标
float3 shadowPos = ShadowProjectPos(v.vertex, mainLight);
//转换到裁切空间
o.vertex = TransformWorldToHClip(shadowPos);
//得到中心点世界坐标
float3 center = float3(unity_ObjectToWorld[0].w, _GroundLevel, unity_ObjectToWorld[2].w);
//计算阴影衰减
float falloff = 1 - saturate(distance(shadowPos, center) * _ShadowFalloff);
//阴影颜色
o.color = _ShadowColor;
o.color.a *= falloff;
return o;
}
half4 frag(v2f i) : SV_Target
{
return i.color;
}
ENDHLSL
}
// Pass
// {
// Name "ShadowCaster"
// Tags
// {
// "LightMode" = "ShadowCaster"
// }
//
// ZWrite On
// ZTest LEqual
// ColorMask 0
// Cull[_Cull]
//
// HLSLPROGRAM
// #pragma only_renderers gles gles3 glcore d3d11
// #pragma target 2.0
//
// // -------------------------------------
// // Material Keywords
// #pragma shader_feature_local_fragment _ALPHATEST_ON
// #pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
//
// // -------------------------------------
// // Universal Pipeline keywords
//
// // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
// #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
//
// #pragma vertex ShadowPassVertex
// #pragma fragment ShadowPassFragment
//
// #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
// #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
// ENDHLSL
// }
Pass
{
Name "DepthOnly"
Tags
{
"LightMode" = "DepthOnly"
}
ZWrite On
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma only_renderers gles gles3 glcore d3d11
#pragma target 2.0
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
}
Fallback "Hidden/Universal Render Pipeline/FallbackError"
CustomEditor "UnityEditor.Rendering.Universal.ShaderGUI.SimpleLitShader"
}