123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
-
- #ifndef UNIVERSAL_REALTIME_LIGHTS_INCLUDED
- #define UNIVERSAL_REALTIME_LIGHTS_INCLUDED
-
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LightCookie/LightCookie.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Clustering.hlsl"
-
- // Abstraction over Light shading data.
- struct Light
- {
- half3 direction;
- half3 color;
- float distanceAttenuation; // full-float precision required on some platforms
- half shadowAttenuation;
- uint layerMask;
- };
-
- #if USE_FORWARD_PLUS && defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
- #define FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK if (_AdditionalLightsColor[lightIndex].a > 0.0h) continue;
- #else
- #define FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
- #endif
-
- #if USE_FORWARD_PLUS
- #define LIGHT_LOOP_BEGIN(lightCount) { \
- uint lightIndex; \
- ClusterIterator _urp_internal_clusterIterator = ClusterInit(inputData.normalizedScreenSpaceUV, inputData.positionWS, 0); \
- [loop] while (ClusterNext(_urp_internal_clusterIterator, lightIndex)) { \
- lightIndex += URP_FP_DIRECTIONAL_LIGHTS_COUNT; \
- FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
- #define LIGHT_LOOP_END } }
- #else
- #define LIGHT_LOOP_BEGIN(lightCount) \
- for (uint lightIndex = 0u; lightIndex < lightCount; ++lightIndex) {
- #define LIGHT_LOOP_END }
- #endif
-
- ///////////////////////////////////////////////////////////////////////////////
- // Attenuation Functions /
- ///////////////////////////////////////////////////////////////////////////////
-
- // Matches Unity Vanilla HINT_NICE_QUALITY attenuation
- // Attenuation smoothly decreases to light range.
- float DistanceAttenuation(float distanceSqr, half2 distanceAttenuation)
- {
- // We use a shared distance attenuation for additional directional and puctual lights
- // for directional lights attenuation will be 1
- float lightAtten = rcp(distanceSqr);
- float2 distanceAttenuationFloat = float2(distanceAttenuation);
-
- // Use the smoothing factor also used in the Unity lightmapper.
- half factor = half(distanceSqr * distanceAttenuationFloat.x);
- half smoothFactor = saturate(half(1.0) - factor * factor);
- smoothFactor = smoothFactor * smoothFactor;
-
- return lightAtten * smoothFactor;
- }
-
- half AngleAttenuation(half3 spotDirection, half3 lightDirection, half2 spotAttenuation)
- {
- // Spot Attenuation with a linear falloff can be defined as
- // (SdotL - cosOuterAngle) / (cosInnerAngle - cosOuterAngle)
- // This can be rewritten as
- // invAngleRange = 1.0 / (cosInnerAngle - cosOuterAngle)
- // SdotL * invAngleRange + (-cosOuterAngle * invAngleRange)
- // SdotL * spotAttenuation.x + spotAttenuation.y
-
- // If we precompute the terms in a MAD instruction
- half SdotL = dot(spotDirection, lightDirection);
- half atten = saturate(SdotL * spotAttenuation.x + spotAttenuation.y);
- return atten * atten;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Light Abstraction //
- ///////////////////////////////////////////////////////////////////////////////
-
- Light GetMainLight()
- {
- Light light;
- light.direction = half3(_MainLightPosition.xyz);
- #if USE_FORWARD_PLUS
- #if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
- light.distanceAttenuation = _MainLightColor.a;
- #else
- light.distanceAttenuation = 1.0;
- #endif
- #else
- light.distanceAttenuation = unity_LightData.z; // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.
- #endif
- light.shadowAttenuation = 1.0;
- light.color = _MainLightColor.rgb;
-
- light.layerMask = _MainLightLayerMask;
-
- return light;
- }
-
- Light GetMainLight(float4 shadowCoord)
- {
- Light light = GetMainLight();
- light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
- return light;
- }
-
- Light GetMainLight(float4 shadowCoord, float3 positionWS, half4 shadowMask)
- {
- Light light = GetMainLight();
- light.shadowAttenuation = MainLightShadow(shadowCoord, positionWS, shadowMask, _MainLightOcclusionProbes);
-
- #if defined(_LIGHT_COOKIES)
- real3 cookieColor = SampleMainLightCookie(positionWS);
- light.color *= cookieColor;
- #endif
-
- return light;
- }
-
- Light GetMainLight(InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
- {
- Light light = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
-
- #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
- {
- light.color *= aoFactor.directAmbientOcclusion;
- }
- #endif
-
- return light;
- }
-
- // Fills a light struct given a perObjectLightIndex
- Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
- {
- // Abstraction over Light input constants
- #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
- float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
- half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
- half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
- half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
- uint lightLayerMask = _AdditionalLightsBuffer[perObjectLightIndex].layerMask;
- #else
- float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
- half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
- half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
- half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
- uint lightLayerMask = asuint(_AdditionalLightsLayerMasks[perObjectLightIndex]);
- #endif
-
- // Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
- // This way the following code will work for both directional and punctual lights.
- float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
- float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
-
- half3 lightDirection = half3(lightVector * rsqrt(distanceSqr));
- // full-float precision required on some platforms
- float attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
-
- Light light;
- light.direction = lightDirection;
- light.distanceAttenuation = attenuation;
- light.shadowAttenuation = 1.0; // This value can later be overridden in GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
- light.color = color;
- light.layerMask = lightLayerMask;
-
- return light;
- }
-
- uint GetPerObjectLightIndexOffset()
- {
- #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
- return uint(unity_LightData.x);
- #else
- return 0;
- #endif
- }
-
- // Returns a per-object index given a loop index.
- // This abstract the underlying data implementation for storing lights/light indices
- int GetPerObjectLightIndex(uint index)
- {
- /////////////////////////////////////////////////////////////////////////////////////////////
- // Structured Buffer Path /
- // /
- // Lights and light indices are stored in StructuredBuffer. We can just index them. /
- // Currently all non-mobile platforms take this path :( /
- // There are limitation in mobile GPUs to use SSBO (performance / no vertex shader support) /
- /////////////////////////////////////////////////////////////////////////////////////////////
- #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
- uint offset = uint(unity_LightData.x);
- return _AdditionalLightsIndices[offset + index];
-
- /////////////////////////////////////////////////////////////////////////////////////////////
- // UBO path /
- // /
- // We store 8 light indices in half4 unity_LightIndices[2]; /
- // Due to memory alignment unity doesn't support int[] or float[] /
- // Even trying to reinterpret cast the unity_LightIndices to float[] won't work /
- // it will cast to float4[] and create extra register pressure. :( /
- /////////////////////////////////////////////////////////////////////////////////////////////
- #else
- // since index is uint shader compiler will implement
- // div & mod as bitfield ops (shift and mask).
-
- // TODO: Can we index a float4? Currently compiler is
- // replacing unity_LightIndicesX[i] with a dp4 with identity matrix.
- // u_xlat16_40 = dot(unity_LightIndices[int(u_xlatu13)], ImmCB_0_0_0[u_xlati1]);
- // This increases both arithmetic and register pressure.
- //
- // NOTE: min16float4 bug workaround.
- // Take the "vec4" part into float4 tmp variable in order to force float4 math.
- // It appears indexing half4 as min16float4 on DX11 can fail. (dp4 {min16f})
- float4 tmp = unity_LightIndices[index / 4];
- return int(tmp[index % 4]);
- #endif
- }
-
- // Fills a light struct given a loop i index. This will convert the i
- // index to a perObjectLightIndex
- Light GetAdditionalLight(uint i, float3 positionWS)
- {
- #if USE_FORWARD_PLUS
- int lightIndex = i;
- #else
- int lightIndex = GetPerObjectLightIndex(i);
- #endif
- return GetAdditionalPerObjectLight(lightIndex, positionWS);
- }
-
- Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
- {
- #if USE_FORWARD_PLUS
- int lightIndex = i;
- #else
- int lightIndex = GetPerObjectLightIndex(i);
- #endif
- Light light = GetAdditionalPerObjectLight(lightIndex, positionWS);
-
- #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
- half4 occlusionProbeChannels = _AdditionalLightsBuffer[lightIndex].occlusionProbeChannels;
- #else
- half4 occlusionProbeChannels = _AdditionalLightsOcclusionProbes[lightIndex];
- #endif
- light.shadowAttenuation = AdditionalLightShadow(lightIndex, positionWS, light.direction, shadowMask, occlusionProbeChannels);
- #if defined(_LIGHT_COOKIES)
- real3 cookieColor = SampleAdditionalLightCookie(lightIndex, positionWS);
- light.color *= cookieColor;
- #endif
-
- return light;
- }
-
- Light GetAdditionalLight(uint i, InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
- {
- Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask);
-
- #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
- if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
- {
- light.color *= aoFactor.directAmbientOcclusion;
- }
- #endif
-
- return light;
- }
-
- int GetAdditionalLightsCount()
- {
- #if USE_FORWARD_PLUS
- // Counting the number of lights in clustered requires traversing the bit list, and is not needed up front.
- return 0;
- #else
- // TODO: we need to expose in SRP api an ability for the pipeline cap the amount of lights
- // in the culling. This way we could do the loop branch with an uniform
- // This would be helpful to support baking exceeding lights in SH as well
- return int(min(_AdditionalLightsCount.x, unity_LightData.y));
- #endif
- }
-
- half4 CalculateShadowMask(InputData inputData)
- {
- // To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
- #if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
- half4 shadowMask = inputData.shadowMask; // Shadowmask was sampled from lightmap
- #elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
- half4 shadowMask = inputData.shadowMask; // Shadowmask (probe occlusion) was sampled from APV
- #elif !defined (LIGHTMAP_ON)
- half4 shadowMask = unity_ProbesOcclusion; // Sample shadowmask (probe occlusion) from legacy probes
- #else
- half4 shadowMask = half4(1, 1, 1, 1); // Fallback shadowmask, fully unoccluded
- #endif
-
- return shadowMask;
- }
-
- #endif
|