@@ -41,7 +41,6 @@ TEXTURE2D_X(_GBufferTexture4); // VTFeedbakc or Light layer or shadow mask
4141TEXTURE2D_X (_GBufferTexture5); // Light layer or shadow mask
4242TEXTURE2D_X (_GBufferTexture6); // shadow mask
4343
44-
4544TEXTURE2D_X (_LightLayersTexture);
4645#ifdef SHADOWS_SHADOWMASK
4746TEXTURE2D_X (_ShadowMaskTexture); // Alias for shadow mask, so we don't need to know which gbuffer is used for shadow mask
@@ -63,11 +62,11 @@ TEXTURE2D_X(_ShadowMaskTexture); // Alias for shadow mask, so we don't need to k
6362#define OUT_GBUFFER_OPTIONAL_SLOT_2 outGBuffer5
6463#endif
6564
66- #if defined (LIGHT_LAYERS) && defined (SHADOWS_SHADOWMASK)
67- #define OUT_GBUFFER_LIGHT_LAYERS OUT_GBUFFER_OPTIONAL_SLOT_1
65+ #if ( defined (LIGHT_LAYERS) || (SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP) ) && defined (SHADOWS_SHADOWMASK)
66+ #define OUT_GBUFFER_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI OUT_GBUFFER_OPTIONAL_SLOT_1
6867#define OUT_GBUFFER_SHADOWMASK OUT_GBUFFER_OPTIONAL_SLOT_2
69- #elif defined (LIGHT_LAYERS)
70- #define OUT_GBUFFER_LIGHT_LAYERS OUT_GBUFFER_OPTIONAL_SLOT_1
68+ #elif ( defined (LIGHT_LAYERS) || (SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP) )
69+ #define OUT_GBUFFER_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI OUT_GBUFFER_OPTIONAL_SLOT_1
7170#elif defined (SHADOWS_SHADOWMASK)
7271#define OUT_GBUFFER_SHADOWMASK OUT_GBUFFER_OPTIONAL_SLOT_1
7372#endif
@@ -194,7 +193,7 @@ float3 GetNormalForShadowBias(BSDFData bsdfData)
194193float GetAmbientOcclusionForMicroShadowing (BSDFData bsdfData)
195194{
196195 float sourceAO;
197- #if (SHADERPASS == SHADERPASS_DEFERRED_LIGHTING)
196+ #if (SHADERPASS == SHADERPASS_DEFERRED_LIGHTING) && ! defined (OUT_GBUFFER_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI)
198197 // Note: In deferred pass we don't have space in GBuffer to store ambientOcclusion so we use specularOcclusion instead
199198 sourceAO = bsdfData.specularOcclusion;
200199#else
@@ -462,6 +461,28 @@ BSDFData ConvertSurfaceDataToBSDFData(uint2 positionSS, SurfaceData surfaceData)
462461 return bsdfData;
463462}
464463
464+ // Store a 7-bit unorm payload, with a 1-bit isUninitializedGI flag.
465+ float EncodeIsUninitializedGIAndAO (bool isUninitializedGI, float ao)
466+ {
467+ // TODO: Could add dither while discretizing to 7-bit to break up any potential banding.
468+ float encoded = floor (saturate (ao) * 127.0 + 0.5 );
469+ encoded += isUninitializedGI ? 128.0 : 0.0 ;
470+ encoded *= (1.0 / 255.0 );
471+
472+ return encoded;
473+ }
474+
475+ bool DecodeIsUninitializedGIAndAO (float encoded, out float ao)
476+ {
477+ ao = encoded * 255.0 ;
478+ bool isUninitializedGI = ao > 127.5 ;
479+ ao -= isUninitializedGI ? 128.0 : 0.0 ;
480+ ao *= (1.0 / 127.0 );
481+ ao = saturate (ao); // For precision.
482+
483+ return isUninitializedGI;
484+ }
485+
465486//-----------------------------------------------------------------------------
466487// conversion function for deferred
467488//-----------------------------------------------------------------------------
@@ -666,7 +687,7 @@ void EncodeIntoGBuffer( SurfaceData surfaceData
666687 if (_DebugLightingMode == DEBUGLIGHTINGMODE_EMISSIVE_LIGHTING)
667688 {
668689 #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
669- if (!IsUninitializedGI (builtinData.bakeDiffuseLighting ))
690+ if (!IsUninitializedGI (builtinData))
670691 #endif
671692 {
672693 builtinData.bakeDiffuseLighting = real3 (0.0 , 0.0 , 0.0 );
@@ -679,33 +700,34 @@ void EncodeIntoGBuffer( SurfaceData surfaceData
679700 }
680701#endif
681702
682- // RT3 - 11f:11f:10f
683- // In deferred we encode emissive color with bakeDiffuseLighting. We don't have the room to store emissiveColor.
684- // It mean that any futher process that affect bakeDiffuseLighting will also affect emissiveColor, like SSAO for example.
685- #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
703+ outGBuffer3 = float4 (builtinData.emissiveColor * GetCurrentExposureMultiplier (), 0.0 );
686704
687- if (IsUninitializedGI (builtinData.bakeDiffuseLighting))
688- {
689- // builtinData.bakeDiffuseLighting contain uninitializedGI sentinel value.
690-
691- // This means probe volumes will not get applied to this pixel, only emissiveColor will.
692- // When length(emissiveColor) is much greater than length(probeVolumeOutgoingRadiance), this will visually look reasonable.
693- // Unfortunately this will break down when emissiveColor is faded out (result will pop).
694- // TODO: If evaluating probe volumes in lightloop, only write out sentinel value here, and re-render emissive surfaces.
695- // Pre-expose lighting buffer
696- outGBuffer3 = float4 (all (builtinData.emissiveColor == 0.0 ) ? builtinData.bakeDiffuseLighting : builtinData.emissiveColor * GetCurrentExposureMultiplier (), 0.0 );
697- }
698- else
705+ #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
706+ bool isUninitializedGI = IsUninitializedGI (builtinData);
707+ #else
708+ bool isUninitializedGI = false ;
699709#endif
710+ if (!isUninitializedGI)
700711 {
701- outGBuffer3 = float4 (builtinData.bakeDiffuseLighting * surfaceData.ambientOcclusion + builtinData.emissiveColor, 0.0 );
702- // Pre-expose lighting buffer
703- outGBuffer3.rgb *= GetCurrentExposureMultiplier ();
712+ // RT3 - 11f:11f:10f
713+ // In deferred we encode emissive color with bakeDiffuseLighting. We don't have the room to store emissiveColor.
714+ // It mean that any futher process that affect bakeDiffuseLighting will also affect emissiveColor, like SSAO for example.
715+ outGBuffer3.rgb += builtinData.bakeDiffuseLighting * (surfaceData.ambientOcclusion * GetCurrentExposureMultiplier ());
704716 }
705717
706- #ifdef LIGHT_LAYERS
718+ #if defined (LIGHT_LAYERS) || (SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP)
719+ float4 lightLayersAndAOAndUnitializedGI = 0.0 ;
720+
721+ #if defined (LIGHT_LAYERS)
707722 // Note: we need to mask out only 8bits of the layer mask before encoding it as otherwise any value > 255 will map to all layers active
708- OUT_GBUFFER_LIGHT_LAYERS = float4 (0.0 , 0.0 , 0.0 , (builtinData.renderingLayers & 0x000000FF ) / 255.0 );
723+ lightLayersAndAOAndUnitializedGI.w = (builtinData.renderingLayers & 0x000000FF ) / 255.0 ;
724+ #endif
725+
726+ #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
727+ lightLayersAndAOAndUnitializedGI.x = EncodeIsUninitializedGIAndAO (isUninitializedGI, surfaceData.ambientOcclusion);
728+ #endif
729+
730+ OUT_GBUFFER_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI = lightLayersAndAOAndUnitializedGI;
709731#endif
710732
711733#ifdef SHADOWS_SHADOWMASK
@@ -739,31 +761,44 @@ uint DecodeFromGBuffer(uint2 positionSS, uint tileFeatureFlags, out BSDFData bsd
739761 GBufferType1 inGBuffer1 = LOAD_TEXTURE2D_X (_GBufferTexture1, positionSS);
740762 GBufferType2 inGBuffer2 = LOAD_TEXTURE2D_X (_GBufferTexture2, positionSS);
741763
742- // BuiltinData
743- builtinData.bakeDiffuseLighting = LOAD_TEXTURE2D_X (_GBufferTexture3, positionSS).rgb; // This also contain emissive (and * AO if no lightlayers)
744-
745- #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
746- if (!IsUninitializedGI (builtinData.bakeDiffuseLighting))
747- #endif
748- {
749- // Inverse pre-exposure
750- builtinData.bakeDiffuseLighting *= GetInverseCurrentExposureMultiplier (); // zero-div guard
751- }
752-
753764 // In deferred ambient occlusion isn't available and is already apply on bakeDiffuseLighting for the GI part.
754765 // Caution: even if we store it in the GBuffer we need to apply it on GI and not on emissive color, so AO must be 1.0 in deferred
755766 bsdfData.ambientOcclusion = 1.0 ;
756767
768+ // BuiltinData
769+ builtinData.bakeDiffuseLighting = LOAD_TEXTURE2D_X (_GBufferTexture3, positionSS).rgb;
770+
771+ float4 inGBufferLightLayersAndAOAndUnitializedGI = 0.0 ;
772+
773+ #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE != PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
757774 // Avoid to introduce a new variant for light layer as it is already long to compile
758775 if (_EnableLightLayers)
776+ #else
759777 {
760- float4 inGBuffer4 = LOAD_TEXTURE2D_X (_LightLayersTexture, positionSS);
761- builtinData.renderingLayers = uint (inGBuffer4.w * 255.5 );
778+ inGBufferLightLayersAndAOAndUnitializedGI = LOAD_TEXTURE2D_X (_LightLayersTexture, positionSS);
762779 }
780+ #endif
781+
782+ #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
783+ if (DecodeIsUninitializedGIAndAO (inGBufferLightLayersAndAOAndUnitializedGI.x, bsdfData.ambientOcclusion))
784+ {
785+ // In this context the bakeDiffuseLighting RT stores only emissiveColor.
786+ // Inverse pre-exposure
787+ builtinData.emissiveColor = builtinData.bakeDiffuseLighting * GetInverseCurrentExposureMultiplier (); // zero-div guard
788+ builtinData.bakeDiffuseLighting = UNINITIALIZED_GI;
789+ }
763790 else
764791 {
765- builtinData.renderingLayers = DEFAULT_LIGHT_LAYERS;
792+ #else
793+ // In this context, the bakeDiffuseLighting RT stores emissive + lightmapBakedLighting * ao.
794+ // Inverse pre-exposure
795+ builtinData.bakeDiffuseLighting *= GetInverseCurrentExposureMultiplier (); // zero-div guard
796+ #endif
797+ #if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
766798 }
799+ #endif
800+
801+ builtinData.renderingLayers = _EnableLightLayers ? uint (inGBufferLightLayersAndAOAndUnitializedGI.w * 255.5 ) : DEFAULT_LIGHT_LAYERS;
767802
768803 // We know the GBufferType no need to use abstraction
769804#ifdef SHADOWS_SHADOWMASK
0 commit comments