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_ONfloat4 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;#elsehalf4 shadowMask = half4(1, 1, 1, 1);#endif
#endif
//顶点处理#ifdef _ADDITIONAL_LIGHTS_VERTEXuint pixelLightCount = GetAdditionalLightsCount();#if _RECEIVESHADOW_ONfor (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);}#elsefor (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_ONLight 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_LIGHTSuint 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#elseLight 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_LIGHTSuint 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 OnZTest LEqualColorMask 0Cull[_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_Zo.positionHS.z = min(o.positionHS.z, UNITY_NEAR_CLIP_VALUE);#elseo.positionHS.z = max(o.positionHS.z, UNITY_NEAR_CLIP_VALUE);#endifreturn o;}half4 frag(Varyings i) : SV_TARGET{return 0;}ENDHLSL}