Unity URP支持多光源阴影
前文:Unity URPShader支持多光源处理
上文只是简单的实现了光照照亮效果,但是并没有实现多光源的阴影投射功能,接下来就是对此功能的整合。
接收阴影
//声明需要的变体和文件
//平行光的阴影
#pragma shader_feature _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
//额外光的阴影
#pragma shader_feature _ _ADDITIONAL_LIGHT_SHADOWS
//阴影质量选择
#pragma shader_feature _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
//shadowCoord 代表主光源平行光采样ShadowMap的阴影UV,shadowMask是额外光的遮罩
#if _RECEIVESHADOW_ON
float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
o.shadowCoord = shadowCoord;
#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
half4 shadowMask = inputData.shadowMask;
#elif !defined(LIGHTMAP_ON)
half4 shadowMask = unity_ProbesOcclusion;
#else
half4 shadowMask = half4(1, 1, 1, 1);
#endif
#endif
//顶点处理
#ifdef _ADDITIONAL_LIGHTS_VERTEX
uint pixelLightCount = GetAdditionalLightsCount();
#if _RECEIVESHADOW_ON
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, positionWS, shadowMask);
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * (light.shadowAttenuation + 0.5));
lightColor += LightingLambert(attenuatedLightColor, light.direction, o.normalWS);
}
#else
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, positionWS);
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * (light.shadowAttenuation + 0.5));
lightColor += LightingLambert(attenuatedLightColor, light.direction, o.normalWS);
}
#endif
额外光处理的主要函数是GetAdditionalLight(),可以在RealtimeLights hlsl文件中找到几个重载方法。
//片元处理
//光照
half3 lightColor = i.lightColor;
#if _RECEIVESHADOW_ON
Light main_light = GetMainLight(i.shadowCoord);
half3 main_light_dir = normalize(main_light.direction);
half diffuse_term = dot(normalize(i.normalWS), main_light_dir) * 0.5 + 0.5;
lightColor += diffuse_term * main_light.color * (main_light.shadowAttenuation + 0.5);
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, i.positionWS.xyz, i.shadowMask);
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * (light.shadowAttenuation + 0.5));
lightColor += LightingLambert(attenuatedLightColor, light.direction, i.normalWS);
}
#endif
#else
Light main_light = GetMainLight();
half3 main_light_dir = normalize(main_light.direction);
half diffuse_term = dot(normalize(i.normalWS), main_light_dir) * 0.5 + 0.5;
lightColor += diffuse_term * main_light.color;
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, i.positionWS.xyz);
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * (light.shadowAttenuation + 0.5));
lightColor += LightingLambert(attenuatedLightColor, light.direction, i.normalWS);
}
#endif
#endif
投射阴影
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#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"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
};
struct Varyings
{
float4 positionHS : SV_POSITION;
};
half3 _LightDirection;
Varyings vert(Attributes v)
{
Varyings o;
float3 positionWS = TransformObjectToWorld(v.positionOS.xyz);
float3 normalWS = TransformObjectToWorldNormal(v.normalOS.xyz);
positionWS = ApplyShadowBias(positionWS, normalWS, _LightDirection);
o.positionHS = TransformWorldToHClip(positionWS);
#if UNITY_REVERSED_Z
o.positionHS.z = min(o.positionHS.z, UNITY_NEAR_CLIP_VALUE);
#else
o.positionHS.z = max(o.positionHS.z, UNITY_NEAR_CLIP_VALUE);
#endif
return o;
}
half4 frag(Varyings i) : SV_TARGET
{
return 0;
}
ENDHLSL
}