Skip to content

Commit 8c1fcce

Browse files
committed
Fix double dark ao and ao in lightloop (#12)
Fix double dark AO + material AO availability in light loop for probe volumes. Probe Volumes: Pack AO and isUninitializedGI flag into .x channel of light layers GBuffer RT to fix double dark AO and to allow emissive surfaces to receive probe volume lighting. Also perform small restructuring to a probe volume bilateral filter function to remove a shader warning
1 parent a2dfe57 commit 8c1fcce

File tree

10 files changed

+138
-83
lines changed

10 files changed

+138
-83
lines changed

com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,7 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS
394394
float reflectionProbeNormalizationWeight = 0.0f;
395395

396396
#if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
397-
bool uninitialized = IsUninitializedGI(builtinData.bakeDiffuseLighting);
398-
builtinData.bakeDiffuseLighting = uninitialized ? float3(0.0, 0.0, 0.0) : builtinData.bakeDiffuseLighting;
397+
bool uninitialized = TryClearUninitializedGI(builtinData);
399398

400399
// If probe volume feature is enabled, this bit is enabled for all tiles to handle ambient probe fallback.
401400
// No need to branch internally on _EnableProbeVolumes uniform.
@@ -444,15 +443,6 @@ void LightLoop( float3 V, PositionInputs posInput, PreLightData preLightData, BS
444443

445444
#endif
446445

447-
#if (SHADERPASS == SHADERPASS_DEFERRED_LIGHTING)
448-
// If we are deferred we should apply baked AO here as it was already apply for lightmap.
449-
// But in deferred ambientOcclusion is white so we should use specularOcclusion instead. It is the
450-
// same case than for Microshadow so we can reuse this function. It should not be apply in forward
451-
// as in this case the baked AO is correctly apply in PostBSDF()
452-
// This is apply only on bakeDiffuseLighting as ModifyBakedDiffuseLighting combine both bakeDiffuseLighting and backBakeDiffuseLighting
453-
builtinDataProbeVolumes.bakeDiffuseLighting *= GetAmbientOcclusionForMicroShadowing(bsdfData);
454-
#endif
455-
456446
ApplyDebugToBuiltinData(builtinDataProbeVolumes);
457447

458448
// Note: builtinDataProbeVolumes.bakeDiffuseLighting and builtinDataProbeVolumes.backBakeDiffuseLighting were combine inside of ModifyBakedDiffuseLighting().

com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeAccumulate.hlsl

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,19 @@
7171

7272
#if PROBE_VOLUMES_BILATERAL_FILTERING_MODE != PROBEVOLUMESBILATERALFILTERINGMODES_DISABLED
7373
#if SHADEROPTIONS_PROBE_VOLUMES_BILATERAL_FILTERING_SAMPLE_MODE == PROBEVOLUMESBILATERALFILTERINGSAMPLEMODES_APPROXIMATE_SAMPLE
74-
probeVolumeTexel3D = ProbeVolumeComputeTexel3DFromBilateralFilter(
75-
probeVolumeTexel3D,
76-
probeVolumeData,
77-
posInput.positionWS, // unbiased
78-
samplePositionWS, // biased
79-
normalWS,
80-
obbFrame,
81-
obbExtents,
82-
obbCenter
83-
);
74+
if (_ProbeVolumeLeakMitigationMode != LEAKMITIGATIONMODE_NORMAL_BIAS)
75+
{
76+
probeVolumeTexel3D = ProbeVolumeComputeTexel3DFromBilateralFilter(
77+
probeVolumeTexel3D,
78+
probeVolumeData,
79+
posInput.positionWS, // unbiased
80+
samplePositionWS, // biased
81+
normalWS,
82+
obbFrame,
83+
obbExtents,
84+
obbCenter
85+
);
86+
}
8487
#else // SHADEROPTIONS_PROBE_VOLUMES_BILATERAL_FILTERING_SAMPLE_MODE == PROBEVOLUMESBILATERALFILTERINGSAMPLEMODES_PRECISE_LOAD
8588
float weights[8];
8689
ProbeVolumeComputeWeightsFromBilateralFilter(

com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeBilateralFilter.hlsl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,6 @@ float3 ProbeVolumeComputeTexel3DFromBilateralFilter(
360360
float3 obbExtents,
361361
float3 obbCenter)
362362
{
363-
if (_ProbeVolumeLeakMitigationMode == LEAKMITIGATIONMODE_NORMAL_BIAS) { return probeVolumeTexel3D; }
364-
365363
float3 probeVolumeTexel3DMin = floor(probeVolumeTexel3D - 0.5) + 0.5;
366364

367365
float weights[8]; for (uint i = 0; i < 8; ++i) { weights[i] = 1.0; }
@@ -420,11 +418,6 @@ float3 ProbeVolumeComputeTexel3DFromBilateralFilter(
420418
);
421419
}
422420
#endif
423-
else
424-
{
425-
// Fallback to no bilateral filter if _ProbeVolumeLeakMitigationMode is configured to a mode unsupported in ShaderConfig.
426-
return probeVolumeTexel3D;
427-
}
428421

429422
ProbeVolumeEvaluateAndAccumulateTrilinearWeights(weights, probeVolumeTexel3D, probeVolumeTexel3DMin);
430423

com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinGIUtilities.hlsl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@
1515

1616
#define UNINITIALIZED_GI float3((1 << 11), 1, (1 << 10))
1717

18-
bool IsUninitializedGI(float3 bakedGI)
18+
bool IsUninitializedGI(BuiltinData builtinData)
1919
{
20-
const float3 unitializedGI = UNINITIALIZED_GI;
21-
return all(bakedGI == unitializedGI);
20+
return all(builtinData.bakeDiffuseLighting == UNINITIALIZED_GI);
21+
}
22+
23+
bool TryClearUninitializedGI(inout BuiltinData builtinData)
24+
{
25+
bool isUninitializedGI = IsUninitializedGI(builtinData);
26+
builtinData.bakeDiffuseLighting = isUninitializedGI ? float3(0.0, 0.0, 0.0) : builtinData.bakeDiffuseLighting;
27+
return isUninitializedGI;
2228
}
2329
#endif
2430

com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinUtilities.hlsl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ void PostInitBuiltinData( float3 V, PositionInputs posInput, SurfaceData surfa
104104
inout BuiltinData builtinData)
105105
{
106106
#if SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP
107-
if (IsUninitializedGI(builtinData.bakeDiffuseLighting))
107+
if (IsUninitializedGI(builtinData))
108+
{
108109
return;
110+
}
109111
#else
110112
// Apply control from the indirect lighting volume settings - This is apply here so we don't affect emissive
111113
// color in case of lit deferred for example and avoid material to have to deal with it

com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public struct BSDFData
120120
public Vector3 fresnel0;
121121

122122
[SurfaceDataAttributes(precision = FieldPrecision.Real)]
123-
public float ambientOcclusion; // Caution: This is accessible only if light layer is enabled, otherwise it is 1
123+
public float ambientOcclusion;
124124
[SurfaceDataAttributes(precision = FieldPrecision.Real)]
125125
public float specularOcclusion;
126126

@@ -196,7 +196,9 @@ protected void GetGBufferOptions(HDRenderPipelineAsset asset, out int gBufferCou
196196
// Caution: This must be in sync with GBUFFERMATERIAL_COUNT definition in
197197
supportShadowMask = asset.currentPlatformRenderPipelineSettings.supportShadowMask;
198198
supportLightLayers = asset.currentPlatformRenderPipelineSettings.supportLightLayers;
199-
gBufferCount = 4 + (supportShadowMask ? 1 : 0) + (supportLightLayers ? 1 : 0);
199+
gBufferCount = GetMaterialGBufferCountRequired()
200+
+ (supportShadowMask ? 1 : 0)
201+
+ ((supportLightLayers || (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.LightLoop)) ? 1 : 0);
200202
#if ENABLE_VIRTUALTEXTURES
201203
gBufferCount++;
202204
#endif
@@ -238,17 +240,24 @@ public override void GetMaterialGBufferDescription(HDRenderPipelineAsset asset,
238240
enableWrite[3] = true;
239241

240242
#if ENABLE_VIRTUALTEXTURES
241-
int index = 4;
243+
int index = GetMaterialGBufferCountRequired();
242244
RTFormat[index] = VTBufferManager.GetFeedbackBufferFormat();
243245
gBufferUsage[index] = GBufferUsage.VTFeedback;
244246
enableWrite[index] = false;
245247
index++;
246248
#else
247-
int index = 4;
249+
int index = GetMaterialGBufferCountRequired();
248250
#endif
249251

250-
if (supportLightLayers)
252+
if (supportLightLayers || (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.LightLoop))
251253
{
254+
// Probe Volume Light Loop evaluation mode requires AO and an unitializedGI flag to be stored in the GBuffer.
255+
// Use the previously unused R channel of the light layer RT to store this data.
256+
// This means that we allocate this light layer RT if light layers is enabled OR Probe Volume Light Loop evaluation is enabled.
257+
// This seems reasonable, as light layers are particularly important for controlling the look of surfaces in a fully deferred context.
258+
// Probe Volumes are designed for this fully deferred context.
259+
// My theory is it will be uncommon for a user to have light layers disabled, but probe volumes enabled.
260+
// Typically, they will want both.
252261
RTFormat[index] = GraphicsFormat.R8G8B8A8_UNorm;
253262
gBufferUsage[index] = GBufferUsage.LightLayers;
254263
index++;
@@ -264,6 +273,11 @@ public override void GetMaterialGBufferDescription(HDRenderPipelineAsset asset,
264273
}
265274
}
266275

276+
private int GetMaterialGBufferCountRequired()
277+
{
278+
return 4;
279+
}
280+
267281

268282
//-----------------------------------------------------------------------------
269283
// Init precomputed texture

com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl

Lines changed: 77 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ TEXTURE2D_X(_GBufferTexture4); // VTFeedbakc or Light layer or shadow mask
4141
TEXTURE2D_X(_GBufferTexture5); // Light layer or shadow mask
4242
TEXTURE2D_X(_GBufferTexture6); // shadow mask
4343

44-
4544
TEXTURE2D_X(_LightLayersTexture);
4645
#ifdef SHADOWS_SHADOWMASK
4746
TEXTURE2D_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)
194193
float 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

com.unity.render-pipelines.high-definition/Runtime/Material/MaterialEvaluation.hlsl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ void ApplyAmbientOcclusionFactor(AmbientOcclusionFactor aoFactor, inout BuiltinD
118118
// This is a tradeoff to avoid storing the precomputed (from data) AO in the GBuffer.
119119
// (This is also why GetScreenSpaceAmbientOcclusion*() is effectively called with AOFromData = 1.0 in Lit:PostEvaluateBSDF() in the
120120
// deferred case since DecodeFromGBuffer will init bsdfData.ambientOcclusion to 1.0 and we will only have SSAO in the aoFactor here)
121+
//
122+
// In the context of Probe Volumes, the above constraints are not true. Ambient Occlusion is packed in the unused bakeDiffuseLighting
123+
// buffer, so material ambient occlusion is available in the light loop, and is correctly applied without double darkening.
121124
builtinData.bakeDiffuseLighting *= aoFactor.indirectAmbientOcclusion;
122125
lighting.indirect.specularReflected *= aoFactor.indirectSpecularOcclusion;
123126
lighting.direct.diffuse *= aoFactor.directAmbientOcclusion;

com.unity.render-pipelines.high-definition/Runtime/Material/MaterialGBufferMacros.hlsl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
#define GBufferType4 float4
1313
#define GBufferType5 float4
1414
#define GBufferType6 float4
15+
#define GBufferType7 float4
1516

16-
#ifdef LIGHT_LAYERS
17-
#define GBUFFERMATERIAL_LIGHT_LAYERS 1
17+
#if defined(LIGHT_LAYERS) || (SHADEROPTIONS_PROBE_VOLUMES_EVALUATION_MODE == PROBEVOLUMESEVALUATIONMODES_LIGHT_LOOP)
18+
#define GBUFFERMATERIAL_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI 1
1819
#else
19-
#define GBUFFERMATERIAL_LIGHT_LAYERS 0
20+
#define GBUFFERMATERIAL_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI 0
2021
#endif
2122

2223
#ifdef SHADOWS_SHADOWMASK
@@ -41,7 +42,7 @@
4142
#endif
4243

4344
// Caution: This must be in sync with Lit.cs GetMaterialGBufferCount()
44-
#define GBUFFERMATERIAL_COUNT (4 + GBUFFERMATERIAL_VTFEEDBACK + GBUFFERMATERIAL_LIGHT_LAYERS + GBUFFERMATERIAL_SHADOWMASK)
45+
#define GBUFFERMATERIAL_COUNT (4 + GBUFFERMATERIAL_VTFEEDBACK + GBUFFERMATERIAL_LIGHT_LAYERS_AND_AO_AND_UNITIALIZED_GI + GBUFFERMATERIAL_SHADOWMASK)
4546

4647
// Only one deferred layout is allowed for a HDRenderPipeline, this will be detect by the redefinition of GBUFFERMATERIAL_COUNT
4748
// If GBUFFERMATERIAL_COUNT is define two time, the shaders will not compile

com.unity.render-pipelines.high-definition/Runtime/Material/MaterialGBufferUninitializedEncode.hlsl.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)