diff --git a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/FrameSettingsUI.Drawers.cs b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/FrameSettingsUI.Drawers.cs index 2327a7197df..1c484f26a06 100644 --- a/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/FrameSettingsUI.Drawers.cs +++ b/com.unity.render-pipelines.high-definition/Editor/RenderPipeline/Settings/FrameSettingsUI.Drawers.cs @@ -349,6 +349,7 @@ static void Drawer_SectionLightingSettings(SerializedFrameSettings serialized, E ); area.AmmendInfo(FrameSettingsField.ProbeVolumeDynamicGI, overrideable: () => hdrpSettings.supportProbeVolume && hdrpSettings.supportProbeVolumeDynamicGI); area.AmmendInfo(FrameSettingsField.ProbeVolumeDynamicGIInfiniteBounces, overrideable: () => hdrpSettings.supportProbeVolume && hdrpSettings.supportProbeVolumeDynamicGI); + area.AmmendInfo(FrameSettingsField.ProbeVolumeDynamicGIDirtyFlagsDisabled, overrideable: () => hdrpSettings.supportProbeVolume && hdrpSettings.supportProbeVolumeDynamicGI); area.AmmendInfo(FrameSettingsField.ProbeVolumeDynamicGIPropagationQuality, customGetter: () => (ScalableLevel3ForFrameSettingsUIOnly)serialized.probeVolumeDynamicGIPropagationQuality.intValue, // 3 levels customSetter: v => serialized.probeVolumeDynamicGIPropagationQuality.intValue = Math.Max(0, Math.Min((int)v, 2)), // Levels 0-2 diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs index 9daafe1693a..db28cbb7c95 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/LightingDebug.cs @@ -201,7 +201,8 @@ internal enum ProbeVolumeDebugMode None, VisualizeAtlas, VisualizeDebugColors, - VisualizeValidity + VisualizeValidity, + VisualizeDynamicGIDirtyFlags } /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/AmbientDice.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/AmbientDice.hlsl index 583242ec934..19686275681 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/AmbientDice.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/AmbientDice.hlsl @@ -80,29 +80,6 @@ float ComputeZonalHarmonicC2FromAmbientDiceSharpness(float sharpness) return sharpness > 2.33 ? rhs : lhs; } - -// https://www.desmos.com/calculator/1ajnhdbg6j -// Simple Least Squares Fit - raw data generated by directly projecting the ambient dice lobe to a zonal harmonic via integration. -// Likely contains ringing for some sharpness levels. -float ComputeZonalHarmonicC0FromAmbientDiceWrappedSharpness(float sharpness) -{ - // sharpness abs is to simply make the compiler happy. - return pow(abs(sharpness) * 0.816074 + 0.809515, -0.99663) * 2.87866 + -0.001; -} - -float ComputeZonalHarmonicC1FromAmbientDiceWrappedSharpness(float sharpness) -{ - return exp2(-7.01231 * pow(abs(sharpness * 1.36435 + -1.3829), -0.786179)) * -1.14392 + 1.04683; -} - -float ComputeZonalHarmonicC2FromAmbientDiceWrappedSharpness(float sharpness) -{ - float lhs = -0.438588 + 0.542959 * sharpness + -0.112098 * sharpness * sharpness + 0.00800693 * sharpness * sharpness * sharpness; - float rhs = exp2(-6.39474 * pow(abs(sharpness * 0.488674 + -2.37692), -0.559034)) * -0.816382 + 0.473311; - return sharpness > 5.0 ? rhs : lhs; -} - - #else // https://www.desmos.com/calculator/umjtgtzmk8 // Fit to pre-deringed data. @@ -127,6 +104,27 @@ float ComputeZonalHarmonicC2FromAmbientDiceSharpness(float sharpness) } #endif +// https://www.desmos.com/calculator/1ajnhdbg6j +// Simple Least Squares Fit - raw data generated by directly projecting the ambient dice lobe to a zonal harmonic via integration. +// Likely contains ringing for some sharpness levels. +float ComputeZonalHarmonicC0FromAmbientDiceWrappedSharpness(float sharpness) +{ + // sharpness abs is to simply make the compiler happy. + return pow(abs(sharpness) * 0.816074 + 0.809515, -0.99663) * 2.87866 + -0.001; +} + +float ComputeZonalHarmonicC1FromAmbientDiceWrappedSharpness(float sharpness) +{ + return exp2(-7.01231 * pow(abs(sharpness * 1.36435 + -1.3829), -0.786179)) * -1.14392 + 1.04683; +} + +float ComputeZonalHarmonicC2FromAmbientDiceWrappedSharpness(float sharpness) +{ + float lhs = -0.438588 + 0.542959 * sharpness + -0.112098 * sharpness * sharpness + 0.00800693 * sharpness * sharpness * sharpness; + float rhs = exp2(-6.39474 * pow(abs(sharpness * 0.488674 + -2.37692), -0.559034)) * -0.816382 + 0.473311; + return sharpness > 5.0 ? rhs : lhs; +} + float3 ComputeZonalHarmonicFromAmbientDiceSharpness(float sharpness) { return float3( diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader new file mode 100644 index 00000000000..599ae971300 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader @@ -0,0 +1,109 @@ +Shader "Hidden/Debug/DebugDirtyFlags" +{ + Properties + { + _ProbeVolumeResolution("_ProbeVolumeResolution", Vector) = (0, 0, 0, 0) + _ProbeVolumeProbeDisplayRadiusWS("_ProbeVolumeProbeDisplayRadiusWS", Float) = 1.0 + } + + SubShader + { + Tags{ "RenderPipeline" = "HDRenderPipeline" "RenderType" = "Opaque" "Queue" = "Transparent" } + ZWrite On + Cull Front + + Pass + { + Name "ForwardUnlit" + Tags{ "LightMode" = "Forward" } + + HLSLPROGRAM + + #pragma editor_sync_compilation + + #pragma vertex vert + #pragma fragment frag + + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl" + + struct appdata + { + uint vertexID : SV_VertexID; + }; + + struct v2f + { + float4 positionCS : SV_POSITION; + float3 color : COLOR; + float2 uv : TEXCOORD0; + }; + + float3 _ProbeVolumeResolution; + float4x4 _ProbeIndex3DToPositionWSMatrix; + float _ProbeVolumeProbeDisplayRadiusWS; + StructuredBuffer _ProbeVolumeDirtyFlags; + + uint3 ComputeWriteIndexFromReadIndex(uint readIndex, float3 resolution) + { + // _ProbeVolumeAtlasReadBuffer[z * resolutionY * resolutionX + y * resolutionX + x] + // TODO: Could implement as floating point operations, which is likely faster. + // Would need to verify precision. + uint x = readIndex % (uint)resolution.x; + uint y = (readIndex / (uint)resolution.x) % (uint)resolution.y; + uint z = readIndex / ((uint)resolution.y * (uint)resolution.x); + + return uint3(x, y, z); + } + + v2f vert(appdata v) + { + v2f o; + + uint probeIndex1D = v.vertexID / 6u; + uint probeTriangleIndex = (v.vertexID / 3u) & 1u; + uint probeVertexIndex = v.vertexID - probeIndex1D * 6u - probeTriangleIndex * 3u; + + bool dirty = IsProbeDirty(_ProbeVolumeDirtyFlags, probeIndex1D); + + float2 vertexPositionOS = (probeTriangleIndex == 1u) + ? float2((probeVertexIndex & 1u), saturate(probeVertexIndex)) + : float2(saturate(probeVertexIndex), saturate((float)probeVertexIndex - 1.0)); + o.uv = vertexPositionOS; + vertexPositionOS = vertexPositionOS * 2.0 - 1.0; + vertexPositionOS *= _ProbeVolumeProbeDisplayRadiusWS; + + float3 probeIndex3D = ComputeWriteIndexFromReadIndex(probeIndex1D, _ProbeVolumeResolution); + float3 probeOriginWS = mul(_ProbeIndex3DToPositionWSMatrix, float4(probeIndex3D, 1.0)).xyz; + float3 probeOriginRWS = GetCameraRelativePositionWS(probeOriginWS); + + float3 cameraRightWS = mul(float4(1.0, 0.0, 0.0, 0.0), UNITY_MATRIX_V).xyz; + float3 cameraUpWS = mul(float4(0.0, 1.0, 0.0, 0.0), UNITY_MATRIX_V).xyz; + + float3 positionRWS = (cameraRightWS * vertexPositionOS.x + cameraUpWS * vertexPositionOS.y) + probeOriginRWS; + + o.color = dirty ? float3(1, 0.5, 0) : float3(0.5, 0, 0); + o.positionCS = TransformWorldToHClip(positionRWS); + + return o; + } + + void ClipProbeSphere(float2 uv) + { + float2 positionProbeCard = uv * 2.0 - 1.0; + clip(dot(positionProbeCard, positionProbeCard) < 1.0 ? 1.0 : -1.0); + } + + float4 frag(v2f i) : SV_Target + { + ClipProbeSphere(i.uv); + return float4(i.color, 1.0); + } + + ENDHLSL + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader.meta new file mode 100644 index 00000000000..ae6eb4353c3 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: f6a2e5a840bb1f147a4801762aae0367 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeDynamicGI.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeDynamicGI.cs index ced27500f36..d8eea031112 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeDynamicGI.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeDynamicGI.cs @@ -49,7 +49,6 @@ public class ProbeDynamicGI : VolumeComponent [Tooltip("Advanced control to clear all dynamic GI buffers in the event lighting blows up when tuning")] public BoolParameter clear = new BoolParameter(false); - [Serializable] public sealed class ProbeVolumeDynamicGIBasisParameter : VolumeParameter { diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationAxes.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationAxes.compute index 48af128b9f5..dffa4f1e834 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationAxes.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationAxes.compute @@ -10,6 +10,7 @@ #pragma multi_compile BASIS_PROPAGATION_OVERRIDE_NONE BASIS_PROPAGATION_OVERRIDE_SPHERICAL_GAUSSIAN BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SOFTER BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SUPER_SOFT BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_ULTRA_SOFT #pragma multi_compile _ RADIANCE_ENCODING_LOGLUV RADIANCE_ENCODING_HALFLUV RADIANCE_ENCODING_R11G11B10 #pragma multi_compile PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L1 PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L2 +#pragma multi_compile _ DIRTY_FLAGS_DISABLED #include "Packages/com.unity.render-pipelines.high-definition-config/Runtime/ShaderConfig.cs.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" @@ -43,6 +44,11 @@ StructuredBuffer _SortedNeighborAxisLookups; StructuredBuffer _ProbeVolumeNeighbors; int _ProbeVolumeNeighborsCount; +#ifndef DIRTY_FLAGS_DISABLED +StructuredBuffer _ProbeVolumeDirtyFlags; +RWStructuredBuffer _ProbeVolumeNextDirtyFlags; +#endif + StructuredBuffer _HitRadianceCacheAxis; int _HitRadianceCacheAxisCount; @@ -231,7 +237,7 @@ float3 PropagateLightFromNeighborSHWithZHFit(SHIncomingIrradiance shIncomingIrra { float3 basisAxisHitDirectionWS = mul(neighborAxisLookup.neighborDirection, probeVolumeLtw); ZHWindow basisAxisHitZHWindow = ComputeZHWindowFromBasisAxisHit(basisAxisNeighborHit); - SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(shIncomingIrradiance, basisAxisHitZHWindow); + SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunctionInPlace(shIncomingIrradiance, basisAxisHitZHWindow); return ProbeVolumeEvaluateIncomingRadiance(shIncomingIrradiance, basisAxisHitDirectionWS) * hitWeight; } @@ -284,13 +290,21 @@ float3 PropagateLightFromNeighborSHWithMonteCarloNaiveProjection(SHIncomingIrrad return incomingHitRadiance; } +RADIANCE GetPreviousAxisRadiance(int index) +{ +#if defined(PREVIOUS_RADIANCE_CACHE_INVALID) + return ZeroRadiance(); +#else + return _PreviousRadianceCacheAxis[index]; +#endif +} + #define BASIS_FROM_SH_MODE_MONTE_CARLO_NAIVE_PROJECTION (0) #define BASIS_FROM_SH_MODE_SAMPLE_PEAKS (1) #define BASIS_FROM_SH_MODE_ZH_FIT (2) -// See note in ProbePropagationInitialize.compute. -// Sample Peaks turns out to be better than ZH Fit in practice for our combination of basis and SH order. -#define BASIS_FROM_SH_MODE BASIS_FROM_SH_MODE_SAMPLE_PEAKS +// Our ZH Fit produces results that are closer to the monte carlo naive projection ground turth than the sample peaks approach does. Both approaches are reasonable however. +#define BASIS_FROM_SH_MODE BASIS_FROM_SH_MODE_ZH_FIT [numthreads(GROUP_SIZE, 1, 1)] void PropagateLight(uint3 id : SV_DispatchThreadID) @@ -303,18 +317,21 @@ void PropagateLight(uint3 id : SV_DispatchThreadID) uint3 probeCoordinate = ProbeIndexToProbeCoordinatesUint(probeIndex); +#ifndef DIRTY_FLAGS_DISABLED + if (!IsProbeDirty(_ProbeVolumeDirtyFlags, probeIndex)) + { + _RadianceCacheAxis[index] = GetPreviousAxisRadiance(index); + return; + } +#endif + const float3x3 probeVolumeLtw = float3x3(_ProbeVolumeDGIBoundsRight, _ProbeVolumeDGIBoundsUp, cross(_ProbeVolumeDGIBoundsRight, _ProbeVolumeDGIBoundsUp)); const float3 probePositionWS = ProbeCoordinatesToWorldPosition(probeCoordinate, probeVolumeLtw); // Early out at far distances if (IsFarFromCamera(probePositionWS, _RangeInFrontOfCamera, _RangeBehindCamera)) { - #if defined(PREVIOUS_RADIANCE_CACHE_INVALID) - _RadianceCacheAxis[index] = ZeroRadiance(); - #else - _RadianceCacheAxis[index] = _PreviousRadianceCacheAxis[index]; - #endif - + _RadianceCacheAxis[index] = GetPreviousAxisRadiance(index); return; } @@ -406,6 +423,32 @@ void PropagateLight(uint3 id : SV_DispatchThreadID) } } - _RadianceCacheAxis[index] = EncodeRadiance((incomingHitRadiance + incomingMissRadiance) * _PropagationContribution); + const float3 radiance = (incomingHitRadiance + incomingMissRadiance) * _PropagationContribution; + _RadianceCacheAxis[index] = EncodeRadiance(radiance); + +#ifndef DIRTY_FLAGS_DISABLED + if (!IsSimilarEqual(GetPreviousAxisRadiance(index), radiance)) + { + for (int l = 0; l < PROPAGATION_AXIS_AMOUNT; ++l) + { + NeighborAxisLookup neighborAxisLookup = _SortedNeighborAxisLookups[neighborAxisIndexOffset + l]; + int i = neighborAxisLookup.index; + + int3 offset = GetNeighborAxisOffset(i); + // When we gathered radiance from neighbors in miss directions we were adding the offset, + // but here we try to predict which probes will gather changes from us so we subtract. + int3 neighborProbeCoordinate = probeCoordinate - offset; + + if(neighborProbeCoordinate.x >= 0 && neighborProbeCoordinate.x < (int)_ProbeVolumeDGIResolutionX && + neighborProbeCoordinate.y >= 0 && neighborProbeCoordinate.y < (int)_ProbeVolumeDGIResolutionY && + neighborProbeCoordinate.z >= 0 && neighborProbeCoordinate.z < (int)_ProbeVolumeDGIResolutionZ) + { + uint neighborProbeIndex = ProbeCoordinateToIndex(neighborProbeCoordinate); + SetProbeDirty(_ProbeVolumeNextDirtyFlags, neighborProbeIndex); + } + } + } +#endif + } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationBasis.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationBasis.hlsl index 247cae43288..8a247fdf984 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationBasis.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationBasis.hlsl @@ -67,6 +67,23 @@ float ComputeBasisAxisHitIntegral(BasisAxisHit basisAxisHit) return integral; } +float ComputeBasisAxisHitIntegralFromSharpness(BasisAxisHit basisAxisHit) +{ + float integral = 0.0; + +#if defined(BASIS_SPHERICAL_GAUSSIAN) + integral = SGIntegralFromSharpness(basisAxisHit.sharpness); +#elif defined(BASIS_SPHERICAL_GAUSSIAN_WINDOWED) + integral = SGClampedCosineWindowIntegralFromSharpness(basisAxisHit.sharpness); +#elif defined(BASIS_AMBIENT_DICE) + integral = AmbientDiceIntegralFromSharpness(basisAxisHit.sharpness); +#else +#error "Undefined Probe Propagation Basis" +#endif + + return integral; +} + BasisAxisHit ComputeBasisAxisHit(float3 axis, float sharpnessIn) { BasisAxisHit basisAxis; diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationCombine.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationCombine.compute index 890e2b4f86b..3f7b218a34d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationCombine.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationCombine.compute @@ -6,6 +6,7 @@ #pragma multi_compile BASIS_PROPAGATION_OVERRIDE_NONE BASIS_PROPAGATION_OVERRIDE_SPHERICAL_GAUSSIAN BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SOFTER BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SUPER_SOFT BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_ULTRA_SOFT #pragma multi_compile _ RADIANCE_ENCODING_LOGLUV RADIANCE_ENCODING_HALFLUV RADIANCE_ENCODING_R11G11B10 #pragma multi_compile PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L1 PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L2 +#pragma multi_compile _ DIRTY_FLAGS_DISABLED #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.hlsl" #include "Packages/com.unity.render-pipelines.high-definition-config/Runtime/ShaderConfig.cs.hlsl" @@ -34,6 +35,10 @@ float3 _ProbeVolumeAtlasSHRotateForward; float3 _ProbeVolumeDGIBoundsRight; float3 _ProbeVolumeDGIBoundsUp; +#ifndef DIRTY_FLAGS_DISABLED +RWStructuredBuffer _ProbeVolumeDirtyFlags; +#endif + StructuredBuffer _RadianceCacheAxis; int _RadianceCacheAxisCount; float _BakedLightingContribution; @@ -320,6 +325,11 @@ void CombinePropagationAxis(uint3 id : SV_DispatchThreadID) const uint readIndex = id.x; if (readIndex < _ProbeVolumeAtlasReadBufferCount) { +#ifndef DIRTY_FLAGS_DISABLED + if (!IsProbeDirty(_ProbeVolumeDirtyFlags, readIndex)) + return; +#endif + uint3 writeIndex = ComputeWriteIndexFromReadIndex(readIndex, _ProbeVolumeResolution); const float validity = ReadValidity(readIndex); diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl index 4c9b05daae5..5d8e5578638 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl @@ -43,4 +43,32 @@ int3 GetNeighborAxisOffset(int i) return NeighborAxisOffset[i]; } +void SetProbeDirty(RWStructuredBuffer buffer, uint probeIndex) +{ + uint index = probeIndex >> 5; + int bitmask = 1 << (probeIndex & 31); + InterlockedOr(buffer[index], bitmask); +} + +void ClearProbeDirty(RWStructuredBuffer buffer, uint probeIndex) +{ + uint index = probeIndex >> 5; + int bitmask = 1 << (probeIndex & 31); + InterlockedAnd(buffer[index], ~bitmask); +} + +bool IsProbeDirty(StructuredBuffer buffer, uint probeIndex) +{ + uint index = probeIndex >> 5; + int bitmask = 1 << (probeIndex & 31); + return (buffer[index] & bitmask) != 0; +} + +bool IsProbeDirty(RWStructuredBuffer buffer, uint probeIndex) +{ + uint index = probeIndex >> 5; + int bitmask = 1 << (probeIndex & 31); + return (buffer[index] & bitmask) != 0; +} + #endif // endof PROBE_PROPAGATION_GLOBALS diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationHits.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationHits.compute index 10ca7fa414c..f7687077840 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationHits.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationHits.compute @@ -8,6 +8,7 @@ #pragma multi_compile BASIS_SPHERICAL_GAUSSIAN BASIS_SPHERICAL_GAUSSIAN_WINDOWED BASIS_AMBIENT_DICE_SHARP BASIS_AMBIENT_DICE_SOFTER BASIS_AMBIENT_DICE_SUPER_SOFT BASIS_AMBIENT_DICE_ULTRA_SOFT #pragma multi_compile BASIS_PROPAGATION_OVERRIDE_NONE BASIS_PROPAGATION_OVERRIDE_SPHERICAL_GAUSSIAN BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SOFTER BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_SUPER_SOFT BASIS_PROPAGATION_OVERRIDE_AMBIENT_DICE_WRAPPED_ULTRA_SOFT #pragma multi_compile _ RADIANCE_ENCODING_LOGLUV RADIANCE_ENCODING_HALFLUV RADIANCE_ENCODING_R11G11B10 +#pragma multi_compile _ DIRTY_FLAGS_DISABLED #define SHADOW_MINIMAL #define LIGHT_EVALUATION_NO_HEIGHT_FOG @@ -25,6 +26,10 @@ RWStructuredBuffer _HitRadianceCacheAxis; int _HitRadianceCacheAxisCount; +#ifndef DIRTY_FLAGS_DISABLED +RWStructuredBuffer _ProbeVolumeDirtyFlags; +#endif + StructuredBuffer _ProbeVolumeNeighborHits; int _ProbeVolumeNeighborHitCount; @@ -129,6 +134,12 @@ float3 EvaluateBRDFLambertApproximate(uint probeIndex, float3 surfaceNormal, flo float integral = ComputeBasisAxisHitAndClampedCosineProductIntegral(basisAxisHit, surfaceNormal); + // Need to scale by our "normalized integral" of each lobe because our basis amplitude coefficients are defined around the assumption that + // integration in say a white furnace test includes this a post normalization by the lobe integral. + // We could just as easily push this scale factor into the amplitude coefficients and not have to worry about it here, + // but then we would have to worry about dividing it out in other locations in the pipeline. + integral *= ComputeBasisAxisHitIntegralFromSharpness(basisAxisHit); + color += prevAxisRadiance * integral; } @@ -224,6 +235,11 @@ void AccumulateLightingDirectional(uint3 id : SV_DispatchThreadID) lighting += UnpackEmission(neighborData.emission) * _BakedEmissionMultiplier; lighting += UnpackEmission(neighborData.mixedLighting) * _MixedLightingMultiplier; +#ifndef DIRTY_FLAGS_DISABLED + if (!IsSimilarEqual(_HitRadianceCacheAxis[hitAxisIndex], lighting)) + SetProbeDirty(_ProbeVolumeDirtyFlags, probeIndex); +#endif + _HitRadianceCacheAxis[hitAxisIndex] = EncodeRadiance(lighting); } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationInitialize.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationInitialize.compute index c4bc2cae525..76faa126401 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationInitialize.compute +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationInitialize.compute @@ -160,8 +160,8 @@ void ComputeProbeBasisFromSHZHFit(SHIncomingIrradiance shIncomingIrradiance, flo // but it can be approximately represented as an ZH. float3 basisAxisHitDirectionWS = mul(basisAxisHit.mean, probeVolumeLtw); ZHWindow basisAxisHitZHWindow = ComputeZHWindowFromBasisAxisHit(basisAxisHit); - SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(shIncomingIrradiance, basisAxisHitZHWindow); - float3 incomingHitRadiance = ProbeVolumeEvaluateIncomingRadiance(shIncomingIrradiance, basisAxisHitDirectionWS); + SHIncomingIrradiance shIncomingIrradianceConvolved = SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(shIncomingIrradiance, basisAxisHitZHWindow); + float3 incomingHitRadiance = ProbeVolumeEvaluateIncomingRadiance(shIncomingIrradianceConvolved, basisAxisHitDirectionWS); // ComputeZHWindowFromBasisAxisHit() returns a normalized (amplitude == 1) window. // We need to scale down the radiance by the actual amplitude of the window to complete the projection. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute new file mode 100644 index 00000000000..0cca8f9d2ba --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute @@ -0,0 +1,48 @@ +#pragma kernel ResetDirtyFlags +#define GROUP_SIZE 64 +//#pragma enable_d3d11_debug_symbols + +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationGlobals.hlsl" + +RWStructuredBuffer _ProbeVolumeDirtyFlags; +uint _ProbeCount; +uint _ResolutionXY; +uint _ResolutionX; +uint _ResolutionY; +uint _ResolutionZ; +int _DirtyAll; + +uint3 ProbeIndexToProbeCoordinatesUint(uint probeIndex) +{ + uint probeZ = probeIndex / _ResolutionXY; + probeIndex -= probeZ * _ResolutionXY; + + uint probeY = probeIndex / _ResolutionX; + uint probeX = probeIndex % _ResolutionX; + + return uint3(probeX, probeY, probeZ); +} + +bool IsBoundaryProbe(uint3 probeCoordinate) +{ + return probeCoordinate.x == 0 + || probeCoordinate.y == 0 + || probeCoordinate.z == 0 + || probeCoordinate.x + 1 == _ResolutionX + || probeCoordinate.y + 1 == _ResolutionY + || probeCoordinate.z + 1 == _ResolutionZ; +} + +[numthreads(GROUP_SIZE, 1, 1)] +void ResetDirtyFlags(uint3 id : SV_DispatchThreadID) +{ + const uint probeIndex = id.x; + if (probeIndex < _ProbeCount) + { + uint3 probeCoordinate = ProbeIndexToProbeCoordinatesUint(probeIndex); + if (_DirtyAll || IsBoundaryProbe(probeCoordinate)) + SetProbeDirty(_ProbeVolumeDirtyFlags, probeIndex); + else + ClearProbeDirty(_ProbeVolumeDirtyFlags, probeIndex); + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute.meta new file mode 100644 index 00000000000..3347ae106b7 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: be093379a7b1d124faedbe93be2b4aed +ComputeShaderImporter: + externalObjects: {} + currentAPIMask: 4 + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.cs index 99393b0e9fb..0e0e233d79c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Experimental.Rendering; @@ -37,6 +36,8 @@ internal struct ProbeVolumePropagationPipelineData public ComputeBuffer radianceCacheAxis0; public ComputeBuffer radianceCacheAxis1; public ComputeBuffer hitRadianceCache; + public ComputeBuffer dirtyFlags0; + public ComputeBuffer dirtyFlags1; public int radianceReadIndex; public int buffersDataVersion; public int simulationFrameTick; @@ -52,6 +53,16 @@ public ComputeBuffer GetWriteRadianceCacheAxis() return (radianceReadIndex == 0) ? radianceCacheAxis1 : radianceCacheAxis0; } + public ComputeBuffer GetDirtyFlags() + { + return (radianceReadIndex == 0) ? dirtyFlags0 : dirtyFlags1; + } + + public ComputeBuffer GetNextDirtyFlags() + { + return (radianceReadIndex == 0) ? dirtyFlags1 : dirtyFlags0; + } + public void SwapRadianceCaches() { radianceReadIndex = (radianceReadIndex + 1) % 2; @@ -64,6 +75,19 @@ public void SwapRadianceCaches() }; } + internal struct ProbeVolumeDynamicGIDispatchData + { + public ProbeDynamicGI giSettings; + public ShaderVariablesGlobal globalCB; + public SphericalHarmonicsL2 ambientProbe; + public bool infiniteBounces; + public bool dirtyFlagsDisabled; + public int propagationQuality; + public ProbeVolumeDynamicGIMixedLightMode mixedLightMode; + public ProbeVolumeDynamicGIRadianceEncoding radianceEncoding; + public ProbeVolumesEncodingModes encodingMode; + } + public partial class ProbeVolumeDynamicGI { private static ProbeVolumeDynamicGI s_Instance = new ProbeVolumeDynamicGI(); @@ -79,6 +103,7 @@ public partial class ProbeVolumeDynamicGI private ComputeShader _PropagationClearRadianceShader = null; private ComputeShader _PropagationInitializeShader = null; private ComputeShader _PropagationHitsShader = null; + private ComputeShader _PropagationResetDirtyFlags = null; private ComputeShader _PropagationAxesShader = null; private ComputeShader _PropagationCombineShader = null; @@ -91,6 +116,10 @@ public partial class ProbeVolumeDynamicGI private int _probeVolumeSimulationRequestCount = 0; private int _probeVolumeSimulationFrameTick = 0; + private Material _DebugDirtyFlagsMaterial = null; + private Shader _DebugDirtyFlagsShader = null; + private MaterialPropertyBlock _DebugDirtyFlagsMaterialPropertyBlock = null; + public enum PropagationQuality { Low, @@ -613,11 +642,14 @@ internal void Allocate(RenderPipelineResources resources) _PropagationClearRadianceShader = resources.shaders.probePropagationClearRadianceCS; _PropagationInitializeShader = resources.shaders.probePropagationInitializeCS; _PropagationHitsShader = resources.shaders.probePropagationHitsCS; + _PropagationResetDirtyFlags = resources.shaders.probePropagationResetDirtyFlagsCS; _PropagationAxesShader = resources.shaders.probePropagationAxesCS; _PropagationCombineShader = resources.shaders.probePropagationCombineCS; ProbeVolume.EnsureBuffer(ref _sortedNeighborAxisLookupsBuffer, _sortedNeighborAxisLookups.Length); + _DebugDirtyFlagsShader = resources.shaders.probeVolumeDebugDirtyFlags; + #if UNITY_EDITOR _ProbeVolumeDebugNeighbors = resources.shaders.probeVolumeDebugNeighbors; dummyColor = RTHandles.Alloc(kDummyRTWidth, kDummyRTHeight, dimension: TextureDimension.Tex2D, colorFormat: GraphicsFormat.R8G8B8A8_UNorm, name: "Dummy color"); @@ -772,39 +804,39 @@ static void SetRadianceEncodingKeywords(ComputeShader shader, ProbeVolumeDynamic } internal void DispatchProbePropagation(CommandBuffer cmd, ProbeVolumeHandle probeVolume, - ProbeDynamicGI giSettings, in ShaderVariablesGlobal shaderGlobals, - RenderTargetIdentifier probeVolumeAtlasSHRTHandle, bool infiniteBounces, - PropagationQuality propagationQuality, SphericalHarmonicsL2 ambientProbe, - ProbeVolumeDynamicGIMixedLightMode mixedLightMode, ProbeVolumeDynamicGIRadianceEncoding radianceEncoding, - ProbeVolumesEncodingModes encodingMode) + RenderTargetIdentifier probeVolumeAtlasSHRTHandle, in ProbeVolumeDynamicGIDispatchData data) { - ProbeVolume.EnsureVolumeBuffers(probeVolume, encodingMode); + ProbeVolume.EnsureVolumeBuffers(probeVolume, data.encodingMode); - var previousRadianceCacheInvalid = InitializePropagationBuffers(probeVolume, radianceEncoding); - if (previousRadianceCacheInvalid || giSettings.clear.value || _clearAllActive) + var previousRadianceCacheInvalid = InitializePropagationBuffers(probeVolume, data.radianceEncoding); + var dirtyAll = false; + if (previousRadianceCacheInvalid || data.giSettings.clear.value || _clearAllActive) { - using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIClear))) - DispatchClearPreviousRadianceCache(cmd, probeVolume, radianceEncoding); + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIInitialize))) + DispatchPropagationInitialize(cmd, probeVolume, in data); - var initializeRadianceCacheWithBakedSH = true; - if (initializeRadianceCacheWithBakedSH) - { - using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIInitialize))) - DispatchPropagationInitialize(cmd, probeVolume, in giSettings, in shaderGlobals, radianceEncoding); - previousRadianceCacheInvalid = false; - } + previousRadianceCacheInvalid = false; + dirtyAll = true; } if (probeVolume.HitNeighborAxisLength != 0) { using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIHits))) - DispatchPropagationHits(cmd, probeVolume, in giSettings, infiniteBounces, previousRadianceCacheInvalid, mixedLightMode, radianceEncoding); + { + DispatchPropagationHits(cmd, probeVolume, previousRadianceCacheInvalid, in data); + } } + if (!data.dirtyFlagsDisabled) + { + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIResetDirtyFlags))) + DispatchResetDirtyFlags(cmd, probeVolume, dirtyAll); + } + using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGIAxes))) - DispatchPropagationAxes(cmd, probeVolume, in giSettings, previousRadianceCacheInvalid, propagationQuality, ambientProbe, radianceEncoding); + DispatchPropagationAxes(cmd, probeVolume, previousRadianceCacheInvalid, in data); using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGICombine))) - DispatchPropagationCombine(cmd, probeVolume, in giSettings, in shaderGlobals, probeVolumeAtlasSHRTHandle, radianceEncoding); + DispatchPropagationCombine(cmd, probeVolume, probeVolumeAtlasSHRTHandle, in data); _stats.Simulated(probeVolume); ref var propagationPipelineData = ref probeVolume.GetPropagationPipelineData(); @@ -847,16 +879,15 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); } - void DispatchPropagationInitialize(CommandBuffer cmd, ProbeVolumeHandle probeVolume, in ProbeDynamicGI giSettings, - in ShaderVariablesGlobal shaderGlobals, ProbeVolumeDynamicGIRadianceEncoding radianceEncoding) + void DispatchPropagationInitialize(CommandBuffer cmd, ProbeVolumeHandle probeVolume, in ProbeVolumeDynamicGIDispatchData data) { int numProbes = probeVolume.parameters.resolutionX * probeVolume.parameters.resolutionY * probeVolume.parameters.resolutionZ; ProbeVolume.ProbeVolumeAtlasKey key = probeVolume.ComputeProbeVolumeAtlasKey(); var kernel = _PropagationInitializeShader.FindKernel("InitializePropagationAxis"); var shader = _PropagationInitializeShader; - SetRadianceEncodingKeywords(shader, radianceEncoding); - SetBasisKeywords(giSettings.basis.value, giSettings.basisPropagationOverride.value, shader); + SetRadianceEncodingKeywords(shader, data.radianceEncoding); + SetBasisKeywords(data.giSettings.basis.value, data.giSettings.basisPropagationOverride.value, shader); ref var pipelineData = ref probeVolume.GetPipelineData(); var obb = pipelineData.BoundingBox; @@ -872,8 +903,8 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro 1.0f / (float) probeVolume.parameters.resolutionZ )); - cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCount, shaderGlobals._ProbeVolumeAtlasResolutionAndSliceCount); - cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCountInverse, shaderGlobals._ProbeVolumeAtlasResolutionAndSliceCountInverse); + cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCount, data.globalCB._ProbeVolumeAtlasResolutionAndSliceCount); + cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCountInverse, data.globalCB._ProbeVolumeAtlasResolutionAndSliceCountInverse); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateRight, key.rotation * new Vector3(1.0f, 0.0f, 0.0f)); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateUp, key.rotation * new Vector3(0.0f, 1.0f, 0.0f)); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateForward, key.rotation * new Vector3(0.0f, 0.0f, 1.0f)); @@ -896,31 +927,32 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsRight", obb.right); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsUp", obb.up); - cmd.SetComputeFloatParam(shader, "_PropagationSharpness", giSettings.propagationSharpness.value); - cmd.SetComputeFloatParam(shader, "_Sharpness", giSettings.sharpness.value); + cmd.SetComputeFloatParam(shader, "_PropagationSharpness", data.giSettings.propagationSharpness.value); + cmd.SetComputeFloatParam(shader, "_Sharpness", data.giSettings.sharpness.value); int dispatchX = (numProbes + 63) / 64; cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); } - void DispatchPropagationHits(CommandBuffer cmd, ProbeVolumeHandle probeVolume, in ProbeDynamicGI giSettings, bool infiniteBounces, - bool previousRadianceCacheInvalid, ProbeVolumeDynamicGIMixedLightMode mixedLightMode, ProbeVolumeDynamicGIRadianceEncoding radianceEncoding) + void DispatchPropagationHits(CommandBuffer cmd, ProbeVolumeHandle probeVolume, + bool previousRadianceCacheInvalid, in ProbeVolumeDynamicGIDispatchData data) { var kernel = _PropagationHitsShader.FindKernel("AccumulateLightingDirectional"); var shader = _PropagationHitsShader; - + ref var pipelineData = ref probeVolume.GetPipelineData(); ref var propagationPipelineData = ref probeVolume.GetPropagationPipelineData(); - SetRadianceEncodingKeywords(shader, radianceEncoding); - SetBasisKeywords(giSettings.basis.value, giSettings.basisPropagationOverride.value, shader); + SetRadianceEncodingKeywords(shader, data.radianceEncoding); + SetBasisKeywords(data.giSettings.basis.value, data.giSettings.basisPropagationOverride.value, shader); + CoreUtils.SetKeyword(shader, "DIRTY_FLAGS_DISABLED", data.dirtyFlagsDisabled); var obb = pipelineData.BoundingBox; - var data = pipelineData.EngineData; - cmd.SetComputeFloatParam(shader, "_ProbeVolumeDGIMaxNeighborDistance", data.maxNeighborDistance); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionXY", (int)data.resolutionXY); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionX", (int)data.resolutionX); - cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIResolutionInverse", data.resolutionInverse); + var engineData = pipelineData.EngineData; + cmd.SetComputeFloatParam(shader, "_ProbeVolumeDGIMaxNeighborDistance", engineData.maxNeighborDistance); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionXY", (int)engineData.resolutionXY); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionX", (int)engineData.resolutionX); + cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIResolutionInverse", engineData.resolutionInverse); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsRight", obb.right); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsUp", obb.up); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsExtents", new Vector3(obb.extentX, obb.extentY, obb.extentZ)); @@ -928,12 +960,13 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeNeighborHits", propagationPipelineData.neighborHits); cmd.SetComputeIntParam(shader, "_ProbeVolumeNeighborHitCount", propagationPipelineData.neighborHits.count); - cmd.SetComputeFloatParam(shader, "_MaxAlbedo", giSettings.maxAlbedo.value); - cmd.SetComputeFloatParam(shader, "_RayBias", giSettings.bias.value); - cmd.SetComputeFloatParam(shader, "_LeakMitigation", giSettings.leakMitigation.value); - cmd.SetComputeFloatParam(shader, "_Sharpness", giSettings.sharpness.value); + cmd.SetComputeFloatParam(shader, "_MaxAlbedo", data.giSettings.maxAlbedo.value); + cmd.SetComputeFloatParam(shader, "_RayBias", data.giSettings.bias.value); + cmd.SetComputeFloatParam(shader, "_LeakMitigation", data.giSettings.leakMitigation.value); + cmd.SetComputeFloatParam(shader, "_Sharpness", data.giSettings.sharpness.value); cmd.SetComputeVectorArrayParam(shader, "_RayAxis", s_NeighborAxis); + var mixedLightMode = data.mixedLightMode; float infBounce; #if UNITY_EDITOR @@ -963,20 +996,21 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro else #endif { - cmd.SetComputeFloatParam(shader, "_RangeBehindCamera", giSettings.rangeBehindCamera.value); - cmd.SetComputeFloatParam(shader, "_RangeInFrontOfCamera", giSettings.rangeInFrontOfCamera.value); + cmd.SetComputeFloatParam(shader, "_RangeBehindCamera", data.giSettings.rangeBehindCamera.value); + cmd.SetComputeFloatParam(shader, "_RangeInFrontOfCamera", data.giSettings.rangeInFrontOfCamera.value); } - cmd.SetComputeFloatParam(shader, "_IndirectScale", mixedLightMode != ProbeVolumeDynamicGIMixedLightMode.MixedOnly ? giSettings.indirectMultiplier.value : 0f); - cmd.SetComputeFloatParam(shader, "_BakedEmissionMultiplier", giSettings.bakedEmissionMultiplier.value); + cmd.SetComputeFloatParam(shader, "_IndirectScale", mixedLightMode != ProbeVolumeDynamicGIMixedLightMode.MixedOnly ? data.giSettings.indirectMultiplier.value : 0f); + cmd.SetComputeFloatParam(shader, "_BakedEmissionMultiplier", data.giSettings.bakedEmissionMultiplier.value); var forceRealtime = mixedLightMode == ProbeVolumeDynamicGIMixedLightMode.ForceRealtime; - cmd.SetComputeFloatParam(shader, "_MixedLightingMultiplier", !forceRealtime ? giSettings.indirectMultiplier.value : 0f); + cmd.SetComputeFloatParam(shader, "_MixedLightingMultiplier", !forceRealtime ? data.giSettings.indirectMultiplier.value : 0f); cmd.SetComputeIntParam(shader, "_MixedLightsAsRealtimeEnabled", forceRealtime || !probeVolume.DynamicGIMixedLightsBaked() ? 1 : 0); - infBounce = infiniteBounces ? giSettings.infiniteBounce.value : 0f; + infBounce = data.infiniteBounces ? data.giSettings.infiniteBounce.value : 0f; } + cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeDirtyFlags", propagationPipelineData.GetDirtyFlags()); cmd.SetComputeBufferParam(shader, kernel, "_PreviousRadianceCacheAxis", propagationPipelineData.GetReadRadianceCacheAxis()); cmd.SetComputeIntParam(shader, "_RadianceCacheAxisCount", propagationPipelineData.radianceCacheAxis0.count); cmd.SetComputeBufferParam(shader, kernel, "_HitRadianceCacheAxis", propagationPipelineData.hitRadianceCache); @@ -994,9 +1028,29 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); } - void DispatchPropagationAxes(CommandBuffer cmd, ProbeVolumeHandle probeVolume, in ProbeDynamicGI giSettings, - bool previousRadianceCacheInvalid, PropagationQuality propagationQuality, SphericalHarmonicsL2 ambientProbe, - ProbeVolumeDynamicGIRadianceEncoding radianceEncoding) + void DispatchResetDirtyFlags(CommandBuffer cmd, ProbeVolumeHandle probeVolume, bool dirtyAll) + { + var kernel = _PropagationResetDirtyFlags.FindKernel("ResetDirtyFlags"); + var shader = _PropagationResetDirtyFlags; + + var data = probeVolume.GetPipelineData().EngineData; + var propagationPipelineData = probeVolume.GetPropagationPipelineData(); + int numProbes = (int)data.resolutionXY * (int)data.resolution.z; + + cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeDirtyFlags", propagationPipelineData.GetNextDirtyFlags()); + cmd.SetComputeIntParam(shader, "_ProbeCount", numProbes); + cmd.SetComputeIntParam(shader, "_ResolutionXY", (int)data.resolutionXY); + cmd.SetComputeIntParam(shader, "_ResolutionX", (int)data.resolutionX); + cmd.SetComputeIntParam(shader, "_ResolutionY", (int)data.resolution.y); + cmd.SetComputeIntParam(shader, "_ResolutionZ", (int)data.resolution.z); + cmd.SetComputeIntParam(shader, "_DirtyAll", dirtyAll ? 1 : 0); + + int dispatchX = (numProbes + 63) / 64; + cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); + } + + void DispatchPropagationAxes(CommandBuffer cmd, ProbeVolumeHandle probeVolume, + bool previousRadianceCacheInvalid, in ProbeVolumeDynamicGIDispatchData data) { var kernel = _PropagationAxesShader.FindKernel("PropagateLight"); var shader = _PropagationAxesShader; @@ -1004,13 +1058,15 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro ref var pipelineData = ref probeVolume.GetPipelineData(); ref var propagationPipelineData = ref probeVolume.GetPropagationPipelineData(); - SetRadianceEncodingKeywords(shader, radianceEncoding); - SetBasisKeywords(giSettings.basis.value, giSettings.basisPropagationOverride.value, shader); + SetRadianceEncodingKeywords(shader, data.radianceEncoding); + SetBasisKeywords(data.giSettings.basis.value, data.giSettings.basisPropagationOverride.value, shader); + CoreUtils.SetKeyword(shader, "DIRTY_FLAGS_DISABLED", data.dirtyFlagsDisabled); var obb = pipelineData.BoundingBox; - var data = pipelineData.EngineData; + var engineData = pipelineData.EngineData; + var propagationQuality = (PropagationQuality)data.propagationQuality; - switch (giSettings.neighborVolumePropagationMode.value) + switch (data.giSettings.neighborVolumePropagationMode.value) { case ProbeDynamicGI.DynamicGINeighboringVolumePropagationMode.SampleNeighborsDirectionOnly: { @@ -1042,8 +1098,8 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro else #endif { - cmd.SetComputeFloatParam(shader, "_RangeBehindCamera", giSettings.rangeBehindCamera.value); - cmd.SetComputeFloatParam(shader, "_RangeInFrontOfCamera", giSettings.rangeInFrontOfCamera.value); + cmd.SetComputeFloatParam(shader, "_RangeBehindCamera", data.giSettings.rangeBehindCamera.value); + cmd.SetComputeFloatParam(shader, "_RangeInFrontOfCamera", data.giSettings.rangeInFrontOfCamera.value); } int propagationAxisAmount; @@ -1072,14 +1128,14 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro } } - cmd.SetComputeFloatParam(shader, "_ProbeVolumeDGIMaxNeighborDistance", data.maxNeighborDistance); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionXY", (int)data.resolutionXY); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionX", (int)data.resolutionX); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionY", (int)data.resolution.y); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionZ", (int)data.resolution.z); - cmd.SetComputeIntParam(shader, "_ProbeVolumeDGILightLayers", unchecked((int)data.lightLayers)); + cmd.SetComputeFloatParam(shader, "_ProbeVolumeDGIMaxNeighborDistance", engineData.maxNeighborDistance); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionXY", (int)engineData.resolutionXY); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionX", (int)engineData.resolutionX); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionY", (int)engineData.resolution.y); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIResolutionZ", (int)engineData.resolution.z); + cmd.SetComputeIntParam(shader, "_ProbeVolumeDGILightLayers", unchecked((int)engineData.lightLayers)); cmd.SetComputeIntParam(shader, "_ProbeVolumeDGIEngineDataIndex", pipelineData.EngineDataIndex); - cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIResolutionInverse", data.resolutionInverse); + cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIResolutionInverse", engineData.resolutionInverse); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsRight", obb.right); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsUp", obb.up); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsExtents", new Vector3(obb.extentX, obb.extentY, obb.extentZ)); @@ -1088,27 +1144,30 @@ void DispatchClearPreviousRadianceCache(CommandBuffer cmd, ProbeVolumeHandle pro cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeNeighbors", propagationPipelineData.neighbors); cmd.SetComputeIntParam(shader, "_ProbeVolumeNeighborsCount", propagationPipelineData.neighbors.count); cmd.SetComputeIntParam(shader, "_ProbeVolumeProbeCount", propagationPipelineData.neighbors.count / s_NeighborAxis.Length); - cmd.SetComputeFloatParam(shader, "_LeakMitigation", giSettings.leakMitigation.value); - cmd.SetComputeFloatParam(shader, "_PropagationContribution", giSettings.propagationContribution.value); - cmd.SetComputeFloatParam(shader, "_Sharpness", giSettings.sharpness.value); + cmd.SetComputeFloatParam(shader, "_LeakMitigation", data.giSettings.leakMitigation.value); + cmd.SetComputeFloatParam(shader, "_PropagationContribution", data.giSettings.propagationContribution.value); + cmd.SetComputeFloatParam(shader, "_Sharpness", data.giSettings.sharpness.value); cmd.SetComputeVectorArrayParam(shader, "_RayAxis", s_NeighborAxis); + cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeDirtyFlags", propagationPipelineData.GetDirtyFlags()); + cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeNextDirtyFlags", propagationPipelineData.GetNextDirtyFlags()); + cmd.SetComputeBufferParam(shader, kernel, "_HitRadianceCacheAxis", propagationPipelineData.hitRadianceCache); cmd.SetComputeIntParam(shader, "_HitRadianceCacheAxisCount", probeVolume.HitNeighborAxisLength); - UpdateAmbientProbe(ambientProbe, giSettings.skyMultiplier.value); + UpdateAmbientProbe(data.ambientProbe, data.giSettings.skyMultiplier.value); cmd.SetComputeVectorArrayParam(shader, "_AmbientProbe", s_AmbientProbe); cmd.SetComputeBufferParam(shader, kernel, "_PreviousRadianceCacheAxis", propagationPipelineData.GetReadRadianceCacheAxis()); cmd.SetComputeBufferParam(shader, kernel, "_RadianceCacheAxis", propagationPipelineData.GetWriteRadianceCacheAxis()); - PrecomputeAxisCacheLookup(cmd, propagationAxisAmount, giSettings.basis.value, giSettings.sharpness.value, - giSettings.basisPropagationOverride.value, giSettings.propagationSharpness.value); + PrecomputeAxisCacheLookup(cmd, propagationAxisAmount, data.giSettings.basis.value, data.giSettings.sharpness.value, + data.giSettings.basisPropagationOverride.value, data.giSettings.propagationSharpness.value); cmd.SetComputeBufferParam(shader, kernel, "_SortedNeighborAxisLookups", _sortedNeighborAxisLookupsBuffer); CoreUtils.SetKeyword(shader, "PREVIOUS_RADIANCE_CACHE_INVALID", previousRadianceCacheInvalid); - cmd.SetComputeFloatParam(shader, "_PropagationSharpness", giSettings.propagationSharpness.value); - cmd.SetComputeFloatParam(shader, "_Sharpness", giSettings.sharpness.value); + cmd.SetComputeFloatParam(shader, "_PropagationSharpness", data.giSettings.propagationSharpness.value); + cmd.SetComputeFloatParam(shader, "_Sharpness", data.giSettings.sharpness.value); int numHits = propagationPipelineData.neighbors.count; int dispatchX = (numHits + 63) / 64; @@ -1135,17 +1194,17 @@ static void UpdateAmbientProbe(SphericalHarmonicsL2 ambientProbe, float multipli s_AmbientProbe[6] = c6; } - void DispatchPropagationCombine(CommandBuffer cmd, ProbeVolumeHandle probeVolume, in ProbeDynamicGI giSettings, - in ShaderVariablesGlobal shaderGlobals, RenderTargetIdentifier probeVolumeAtlasSHRTHandle, - ProbeVolumeDynamicGIRadianceEncoding radianceEncoding) + void DispatchPropagationCombine(CommandBuffer cmd, ProbeVolumeHandle probeVolume, + RenderTargetIdentifier probeVolumeAtlasSHRTHandle, in ProbeVolumeDynamicGIDispatchData data) { int numProbes = probeVolume.parameters.resolutionX * probeVolume.parameters.resolutionY * probeVolume.parameters.resolutionZ; ProbeVolume.ProbeVolumeAtlasKey key = probeVolume.ComputeProbeVolumeAtlasKey(); var kernel = _PropagationCombineShader.FindKernel("CombinePropagationAxis"); var shader = _PropagationCombineShader; - SetRadianceEncodingKeywords(shader, radianceEncoding); - SetBasisKeywords(giSettings.basis.value, giSettings.basisPropagationOverride.value, shader); + SetRadianceEncodingKeywords(shader, data.radianceEncoding); + SetBasisKeywords(data.giSettings.basis.value, data.giSettings.basisPropagationOverride.value, shader); + CoreUtils.SetKeyword(shader, "DIRTY_FLAGS_DISABLED", data.dirtyFlagsDisabled); ref var pipelineData = ref probeVolume.GetPipelineData(); var obb = pipelineData.BoundingBox; @@ -1161,8 +1220,8 @@ static void UpdateAmbientProbe(SphericalHarmonicsL2 ambientProbe, float multipli 1.0f / (float) probeVolume.parameters.resolutionZ )); - cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCount, shaderGlobals._ProbeVolumeAtlasResolutionAndSliceCount); - cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCountInverse, shaderGlobals._ProbeVolumeAtlasResolutionAndSliceCountInverse); + cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCount, data.globalCB._ProbeVolumeAtlasResolutionAndSliceCount); + cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasResolutionAndSliceCountInverse, data.globalCB._ProbeVolumeAtlasResolutionAndSliceCountInverse); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateRight, key.rotation * new Vector3(1.0f, 0.0f, 0.0f)); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateUp, key.rotation * new Vector3(0.0f, 1.0f, 0.0f)); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeAtlasSHRotateForward, key.rotation * new Vector3(0.0f, 0.0f, 1.0f)); @@ -1180,25 +1239,26 @@ static void UpdateAmbientProbe(SphericalHarmonicsL2 ambientProbe, float multipli ref var propagationPipelineData = ref probeVolume.GetPropagationPipelineData(); cmd.SetComputeBufferParam(shader, kernel, "_RadianceCacheAxis", propagationPipelineData.GetWriteRadianceCacheAxis()); cmd.SetComputeIntParam(shader, "_RadianceCacheAxisCount", propagationPipelineData.radianceCacheAxis0.count); + cmd.SetComputeBufferParam(shader, kernel, "_ProbeVolumeDirtyFlags", propagationPipelineData.GetDirtyFlags()); - var dynamicAmount = giSettings.dynamicAmount.value; + var dynamicAmount = data.giSettings.dynamicAmount.value; #if UNITY_EDITOR // When preparing mixed lights we set Indirect Scale to 1.0 for hit pass to get raw values in there. // So here we multiply output by correct Indirect Scale from settings to preview how it would look // during final propagation when Indirect Scale is applied to mixed lights as well as realtime lights. if (ProbeVolume.preparingMixedLights) - dynamicAmount *= giSettings.indirectMultiplier.value; + dynamicAmount *= data.giSettings.indirectMultiplier.value; #endif cmd.SetComputeFloatParam(shader, "_DynamicPropagationContribution", dynamicAmount); - cmd.SetComputeFloatParam(shader, "_BakedLightingContribution", giSettings.fallbackAmount.value); + cmd.SetComputeFloatParam(shader, "_BakedLightingContribution", data.giSettings.fallbackAmount.value); cmd.SetComputeVectorArrayParam(shader, "_RayAxis", s_NeighborAxis); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsRight", obb.right); cmd.SetComputeVectorParam(shader, "_ProbeVolumeDGIBoundsUp", obb.up); - cmd.SetComputeFloatParam(shader, "_PropagationSharpness", giSettings.propagationSharpness.value); - cmd.SetComputeFloatParam(shader, "_Sharpness", giSettings.sharpness.value); + cmd.SetComputeFloatParam(shader, "_PropagationSharpness", data.giSettings.propagationSharpness.value); + cmd.SetComputeFloatParam(shader, "_Sharpness", data.giSettings.sharpness.value); int dispatchX = (numProbes + 63) / 64; cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); @@ -1219,6 +1279,7 @@ static void UpdateAmbientProbe(SphericalHarmonicsL2 ambientProbe, float multipli CoreUtils.SetKeyword(cmd, "PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L1", false); CoreUtils.SetKeyword(cmd, "PROBE_VOLUMES_ENCODING_SPHERICAL_HARMONICS_L2", true); + CoreUtils.SetKeyword(shader, "DIRTY_FLAGS_DISABLED", true); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeResolution, (Vector3)size); cmd.SetComputeVectorParam(shader, HDShaderIDs._ProbeVolumeResolutionInverse, new Vector3( @@ -1273,7 +1334,62 @@ static void UpdateAmbientProbe(SphericalHarmonicsL2 ambientProbe, float multipli int dispatchX = (numProbes + 63) / 64; cmd.DispatchCompute(shader, kernel, dispatchX, 1, 1); } - + + Material GetDebugDirtyProbeMaterial() + { + if (_DebugDirtyFlagsMaterial == null && _DebugDirtyFlagsShader != null) + { + _DebugDirtyFlagsMaterial = new Material(_DebugDirtyFlagsShader); + } + + return _DebugDirtyFlagsMaterial; + } + + MaterialPropertyBlock GetDebugDirtyProbeMaterialPropertyBlock() + { + if (_DebugDirtyFlagsMaterialPropertyBlock == null) + { + _DebugDirtyFlagsMaterialPropertyBlock = new MaterialPropertyBlock(); + } + + return _DebugDirtyFlagsMaterialPropertyBlock; + } + + internal void DebugDrawDirtyFlags(CommandBuffer cmd, ProbeVolumeHandle probeVolume) + { + var dirtyFlags = probeVolume.GetPropagationPipelineData().GetDirtyFlags(); + if (dirtyFlags == null || !dirtyFlags.IsValid()) + return; + + var material = GetDebugDirtyProbeMaterial(); + if (material == null) + return; + + var materialPropertyBlock = GetDebugDirtyProbeMaterialPropertyBlock(); + + var parameters = probeVolume.parameters; + + var probeIndex3DToPositionWSMatrix = VolumeUtils.ComputeProbeIndex3DToPositionWSMatrix( + probeVolume.position, + probeVolume.rotation, + parameters.size, + parameters.resolutionX, + parameters.resolutionY, + parameters.resolutionZ); + + var resolution = new Vector3(parameters.resolutionX, parameters.resolutionY, parameters.resolutionZ); + var probeRadiusWS = (parameters.size.x / resolution.x + parameters.size.y / resolution.y + parameters.size.z / resolution.z) * (1f / 3f * 1f / 32f); + + materialPropertyBlock.SetVector("_ProbeVolumeResolution", resolution); + materialPropertyBlock.SetMatrix("_ProbeIndex3DToPositionWSMatrix", probeIndex3DToPositionWSMatrix); + materialPropertyBlock.SetFloat("_ProbeVolumeProbeDisplayRadiusWS", probeRadiusWS); + materialPropertyBlock.SetBuffer("_ProbeVolumeDirtyFlags", dirtyFlags); + + var probeCount = VolumeUtils.ComputeProbeCount(parameters.resolutionX, parameters.resolutionY, parameters.resolutionZ); + + cmd.DrawProcedural(Matrix4x4.identity, material, 0, MeshTopology.Triangles, 3 * 2 * probeCount, 1, materialPropertyBlock); + } + internal static bool CleanupPropagation(ProbeVolumeHandle probeVolume) { ref var propagationPipelineData = ref probeVolume.GetPropagationPipelineData(); @@ -1283,6 +1399,8 @@ internal static bool CleanupPropagation(ProbeVolumeHandle probeVolume) didDispose |= ProbeVolume.CleanupBuffer(propagationPipelineData.radianceCacheAxis0); didDispose |= ProbeVolume.CleanupBuffer(propagationPipelineData.radianceCacheAxis1); didDispose |= ProbeVolume.CleanupBuffer(propagationPipelineData.hitRadianceCache); + didDispose |= ProbeVolume.CleanupBuffer(propagationPipelineData.dirtyFlags0); + didDispose |= ProbeVolume.CleanupBuffer(propagationPipelineData.dirtyFlags1); propagationPipelineData.buffersDataVersion = -1; propagationPipelineData.simulationFrameTick = -1; @@ -1308,6 +1426,10 @@ static bool InitializePropagationInputBuffers(ProbeVolumeHandle probeVolume) ProbeVolume.EnsureBuffer(ref propagationPipelineData.neighbors, probeVolume.NeighborAxisLength); probeVolume.SetNeighborAxis(propagationPipelineData.neighbors); + var packedDirtyFlagsLength = probeVolume.DataValidityLength >> 5; + ProbeVolume.EnsureBuffer(ref propagationPipelineData.dirtyFlags0, packedDirtyFlagsLength); + ProbeVolume.EnsureBuffer(ref propagationPipelineData.dirtyFlags1, packedDirtyFlagsLength); + propagationPipelineData.buffersDataVersion = dataVersion; return true; } @@ -1447,7 +1569,7 @@ internal static float GetMaxNeighborDistance(in ProbeVolumeArtistParameters para var hitWeightsGoal = 0f; var propagationWeights = 0f; var propagationWeightsGoal = 0f; - for (int sortedAxisIndex = 0; sortedAxisIndex < axisAmount; sortedAxisIndex++) + for (int sortedAxisIndex = 0; sortedAxisIndex < s_NeighborAxis.Length; sortedAxisIndex++) { if (sortedAxisIndex < axisAmount) { @@ -1457,14 +1579,13 @@ internal static float GetMaxNeighborDistance(in ProbeVolumeArtistParameters para hitWeightsGoal += _sortedNeighborAxisLookups[sortedAxisStart + sortedAxisIndex].hitWeight; propagationWeightsGoal += _sortedNeighborAxisLookups[sortedAxisStart + sortedAxisIndex].propagationWeight; - } float hitWeightsNormalization = hitWeightsGoal / hitWeights; float propagationWeightsNormalization = propagationWeightsGoal / propagationWeights; for (int sortedAxisIndex = 0; sortedAxisIndex < axisAmount; sortedAxisIndex++) { _sortedNeighborAxisLookups[sortedAxisStart + sortedAxisIndex].hitWeight *= hitWeightsNormalization; - _sortedNeighborAxisLookups[sortedAxisStart + sortedAxisIndex].propagationWeight /= propagationWeightsNormalization; + _sortedNeighborAxisLookups[sortedAxisStart + sortedAxisIndex].propagationWeight *= propagationWeightsNormalization; } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.hlsl index 09e37466945..182171e03be 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGI.hlsl @@ -341,5 +341,28 @@ float3 DecodeRadiance(RADIANCE packedValue) #endif } +bool IsSimilarEqual(RADIANCE packedA, float3 b) +{ +#if defined(RADIANCE_ENCODING_LOGLUV) + const int3 componentsA = int3(packedA & 255, packedA >> 8 & 255, packedA >> 16); + + const float3 logLuvB = LogluvFromRgb(b); + const int3 componentsB = int3( + min(255, (uint)round(logLuvB.x * 255)), + min(255, (uint)round(logLuvB.y * 255)), + min(65535, (uint)round(logLuvB.z * 65535))); + + return all(abs(componentsA - componentsB) < int3(2, 2, 32)); + +#else + // TODO: Add a better comparison for HalfLuv and R11G11B10 if they are needed. They'll be giving a lot of false negatives now. + + const float3 a = DecodeRadiance(packedA); + + // Comparison with NaN always gives false. But if max is 0 then min is also 0. + // So we accept NaN from the division as true by flipping the condition twice. + return !any(min(a, b) / max(a, b) < 0.99); +#endif +} #endif // endof PROBE_VOLUME_DYNAMIC_GI diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGIEditor.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGIEditor.cs index baa7dafb2d7..bc5895759e9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGIEditor.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeDynamicGIEditor.cs @@ -172,7 +172,7 @@ internal void DebugDrawNeighborhood(ProbeVolumeHandle probeVolume, Camera camera } } } - + private void ResolveExtraDataRequest(ref ProbeBakeNeighborData neighborData) { for (int i = 0; i < s_NeighborAxis.Length; ++i) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeSphericalHarmonicsLighting.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeSphericalHarmonicsLighting.hlsl index 88e63bb4fd4..3de233472f8 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeSphericalHarmonicsLighting.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/DynamicGI/ProbeVolumeSphericalHarmonicsLighting.hlsl @@ -926,7 +926,7 @@ void SHIncomingIrradianceConvolveZHWindow(inout SHIncomingIrradiance shIncomingI shIncomingIrradiance.data[8] *= zhWindow.data[2]; } -void SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(inout SHIncomingIrradiance shIncomingIrradiance, ZHWindow zhWindow) +void SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunctionInPlace(inout SHIncomingIrradiance shIncomingIrradiance, ZHWindow zhWindow) { zhWindow.data[0] *= SPHERICAL_HARMONIC_DELTA_FUNCTION_INVERSE_L0; zhWindow.data[1] *= SPHERICAL_HARMONIC_DELTA_FUNCTION_INVERSE_L1; @@ -945,113 +945,44 @@ void SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(inout SHIncomingIr shIncomingIrradiance.data[8] *= zhWindow.data[2]; } -void SHIncomingIrradianceConvolveDirectionalZHWindow(inout SHIncomingIrradiance shIncomingIrradiance, ZHWindow zhWindow, float3 zhDirection) -{ - SHWindow shWindow = SHWindowComputeFromZHWindow(zhWindow, zhDirection); - - SHIncomingIrradianceConvolveSHWindow(shIncomingIrradiance, shWindow); -} - -// optimal linear direction, related to bent normal, etc. -float3 SHOutgoingRadiosityScalarGetOptimalLinearDirection(const SHOutgoingRadiosityScalar shOutgoingRadiosityScalar) -{ - return float3(-shOutgoingRadiosityScalar.data[3], -shOutgoingRadiosityScalar.data[1], shOutgoingRadiosityScalar.data[2]); -} - -//////////// Francesco's Versions - -real3 SHEvalLinearL1(real3 N, real3 shAr, real3 shAg, real3 shAb) -{ - real3 x1; - x1.r = dot(shAr, N); - x1.g = dot(shAg, N); - x1.b = dot(shAb, N); - - return x1; -} - - -float3 FCCEvaluate(SHIncomingIrradiance shIncomingIrradiance, float3 direction) +SHIncomingIrradiance SHIncomingIrradianceConvolveZHWindowWithoutDeltaFunction(SHIncomingIrradiance shIncomingIrradiance, ZHWindow zhWindow) { - float4 shAr = float4(shIncomingIrradiance.data[1].r, shIncomingIrradiance.data[2].r, shIncomingIrradiance.data[3].r, shIncomingIrradiance.data[0].r); - float4 shAg = float4(shIncomingIrradiance.data[1].g, shIncomingIrradiance.data[2].g, shIncomingIrradiance.data[3].g, shIncomingIrradiance.data[0].g); - float4 shAb = float4(shIncomingIrradiance.data[1].b, shIncomingIrradiance.data[2].b, shIncomingIrradiance.data[3].b, shIncomingIrradiance.data[0].b); - float3 L1Eval = SHEvalLinearL1(direction, shAr.xyz, shAg.xyz, shAb.xyz); - - float3 output = shIncomingIrradiance.data[0]; - output += L1Eval; - - output += SHEvalLinearL2(direction, float4(shIncomingIrradiance.data[4].r, shIncomingIrradiance.data[5].r, shIncomingIrradiance.data[6].r, shIncomingIrradiance.data[7].r), - float4(shIncomingIrradiance.data[4].g, shIncomingIrradiance.data[5].g, shIncomingIrradiance.data[6].g, shIncomingIrradiance.data[7].g), - float4(shIncomingIrradiance.data[4].b, shIncomingIrradiance.data[5].b, shIncomingIrradiance.data[6].b, shIncomingIrradiance.data[7].b), - float4(shIncomingIrradiance.data[8], 1.0f)); - return output; -} - - -// Constants from SetSHEMapConstants function in the Stupid Spherical Harmonics Tricks paper: -// http://www.ppsloan.org/publications/StupidSH36.pdf -// [SH basis coeff] * [clamped cosine convolution factor] -#define fC0 (rsqrt(PI * 4.0) * rsqrt(PI * 4.0)) // Equivalent (0.282095 * (1.0 / (2.0 * sqrtPI))) -#define fC1 (rsqrt(PI * 4.0 / 3.0) * rsqrt(PI * 3.0)) // Equivalent to (0.488603 * (sqrt ( 3.0) / ( 3.0 * sqrtPI))) -#define fC2 (rsqrt(PI * 4.0 / 15.0) * rsqrt(PI * 64.0 / 15.0)) // Equivalent to (1.092548 * (sqrt (15.0) / ( 8.0 * sqrtPI))) -#define fC3 (rsqrt(PI * 16.0 / 5.0) * rsqrt(PI * 256.0 / 5.0)) // Equivalent to (0.315392 * (sqrt ( 5.0) / (16.0 * sqrtPI))) -#define fC4 (rsqrt(PI * 16.0 / 15.0) * rsqrt(PI * 256.0 / 15.0)) // Equivalent to (0.546274 * 0.5 * (sqrt (15.0) / ( 8.0 * sqrtPI))) - -void FCCAddToOutputRepresentation(float3 value, float3 direction, inout SHIncomingIrradiance shIncomingIrradiance) -{ - static const float ConvolveCosineLobeBandFactor[] = { fC0, -fC1, fC1, -fC1, fC2, -fC2, fC3, -fC2, fC4 }; - - const float kNormalization = 2.9567930857315701067858823529412f; // 16*kPI/17 + SHIncomingIrradiance shIncomingIrradianceConvolved; + for (int c = 0; c < SH_COEFFICIENT_COUNT; ++c) + { + shIncomingIrradianceConvolved.data[c] = shIncomingIrradiance.data[c]; + } - float weight = kNormalization; + zhWindow.data[0] *= SPHERICAL_HARMONIC_DELTA_FUNCTION_INVERSE_L0; + zhWindow.data[1] *= SPHERICAL_HARMONIC_DELTA_FUNCTION_INVERSE_L1; + zhWindow.data[2] *= SPHERICAL_HARMONIC_DELTA_FUNCTION_INVERSE_L2; - float3 L0 = value * ConvolveCosineLobeBandFactor[0] * weight; - float3 L1_0 = -direction.y * value * ConvolveCosineLobeBandFactor[1] * weight; - float3 L1_1 = direction.z * value * ConvolveCosineLobeBandFactor[2] * weight; - float3 L1_2 = -direction.x * value * ConvolveCosineLobeBandFactor[3] * weight; + shIncomingIrradianceConvolved.data[0] *= zhWindow.data[0]; - shIncomingIrradiance.data[0] += L0; - shIncomingIrradiance.data[1] += L1_0; - shIncomingIrradiance.data[2] += L1_1; - shIncomingIrradiance.data[3] += L1_2; + shIncomingIrradianceConvolved.data[1] *= zhWindow.data[1]; + shIncomingIrradianceConvolved.data[2] *= zhWindow.data[1]; + shIncomingIrradianceConvolved.data[3] *= zhWindow.data[1]; - float3 L2_0 = direction.x * direction.y * value * ConvolveCosineLobeBandFactor[4] * weight; - float3 L2_1 = -direction.y * direction.z * value * ConvolveCosineLobeBandFactor[5] * weight; - float3 L2_2 = (3.0 * direction.z * direction.z - 1.0f) * value * ConvolveCosineLobeBandFactor[6] * weight; - float3 L2_3 = -direction.x * direction.z * value * ConvolveCosineLobeBandFactor[7] * weight; - float3 L2_4 = (direction.x * direction.x - direction.y * direction.y) * value * ConvolveCosineLobeBandFactor[8] * weight; + shIncomingIrradianceConvolved.data[4] *= zhWindow.data[2]; + shIncomingIrradianceConvolved.data[5] *= zhWindow.data[2]; + shIncomingIrradianceConvolved.data[6] *= zhWindow.data[2]; + shIncomingIrradianceConvolved.data[7] *= zhWindow.data[2]; + shIncomingIrradianceConvolved.data[8] *= zhWindow.data[2]; - shIncomingIrradiance.data[4] += L2_0; - shIncomingIrradiance.data[5] += L2_1; - shIncomingIrradiance.data[6] += L2_2; - shIncomingIrradiance.data[7] += L2_3; - shIncomingIrradiance.data[8] += L2_4; + return shIncomingIrradianceConvolved; } -float3 DecodeSH(float l0, float3 l1) +void SHIncomingIrradianceConvolveDirectionalZHWindow(inout SHIncomingIrradiance shIncomingIrradiance, ZHWindow zhWindow, float3 zhDirection) { - // TODO: We're working on irradiance instead of radiance coefficients - // Add safety margin 2 to avoid out-of-bounds values - const float l1scale = 2;//1.7320508f; // 3/(2*sqrt(3)) * 2 + SHWindow shWindow = SHWindowComputeFromZHWindow(zhWindow, zhDirection); - return (l1 - 0.5f) * 2.0f * l1scale * l0; + SHIncomingIrradianceConvolveSHWindow(shIncomingIrradiance, shWindow); } -void DecodeSH_L2(float3 l0, inout float4 l2_R, inout float4 l2_G, inout float4 l2_B, inout float4 l2_C) +// optimal linear direction, related to bent normal, etc. +float3 SHOutgoingRadiosityScalarGetOptimalLinearDirection(const SHOutgoingRadiosityScalar shOutgoingRadiosityScalar) { - // TODO: We're working on irradiance instead of radiance coefficients - // Add safety margin 2 to avoid out-of-bounds values - const float l2scale = 3.5777088f; // 4/sqrt(5) * 2 - - l2_R = (l2_R - 0.5f) * l2scale * l0.r; - l2_G = (l2_G - 0.5f) * l2scale * l0.g; - l2_B = (l2_B - 0.5f) * l2scale * l0.b; - l2_C = (l2_C - 0.5f) * l2scale; - - l2_C.r *= l0.r; - l2_C.g *= l0.g; - l2_C.b *= l0.b; + return float3(-shOutgoingRadiosityScalar.data[3], -shOutgoingRadiosityScalar.data[1], shOutgoingRadiosityScalar.data[2]); } float ComputeZHNewWindowCoefficient(float g, float l) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeLighting.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeLighting.cs index 06991618cd9..7dd4cdb2b31 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeLighting.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/ProbeVolumeLighting.cs @@ -213,12 +213,18 @@ internal int GetProbeVolumeAtlasSHRTDepthSliceCount() private static Material GetDebugSHPreviewMaterial() { - return (s_DebugSHPreviewMaterial != null) ? s_DebugSHPreviewMaterial : new Material(Shader.Find("Hidden/Debug/ProbeVolumeSHPreview")); + if (s_DebugSHPreviewMaterial == null) + s_DebugSHPreviewMaterial = new Material(Shader.Find("Hidden/Debug/ProbeVolumeSHPreview")); + + return s_DebugSHPreviewMaterial; } private static MaterialPropertyBlock GetDebugSHPreviewMaterialPropertyBlock() { - return (s_DebugSHPreviewMaterialPropertyBlock != null) ? s_DebugSHPreviewMaterialPropertyBlock : new MaterialPropertyBlock(); + if (s_DebugSHPreviewMaterialPropertyBlock == null) + s_DebugSHPreviewMaterialPropertyBlock = new MaterialPropertyBlock(); + + return s_DebugSHPreviewMaterialPropertyBlock; } #endif @@ -395,6 +401,14 @@ void CleanupProbeVolumes() { DestroyProbeVolumeBuffers(); + if (SupportDynamicGI) + { + ProbeVolumeManager.manager.UpdateVolumesToRender(); + var volumes = ProbeVolumeManager.manager.GetVolumesToRender(); + foreach (var volume in volumes) + ProbeVolumeDynamicGI.instance.ClearProbePropagation(volume); + } + #if UNITY_EDITOR UnityEditor.Lightmapping.lightingDataCleared -= OnLightingDataCleared; #endif @@ -1087,15 +1101,8 @@ struct ProbeVolumeDynamicGICommonData { public ProbeVolumeDynamicGIMode mode; public List volumes; - public ProbeDynamicGI giSettings; - public ShaderVariablesGlobal globalCB; - public SphericalHarmonicsL2 ambientProbe; - public bool infiniteBounces; - public int propagationQuality; + public ProbeVolumeDynamicGIDispatchData dispatchData; public int maxSimulationsPerFrameOverride; - public ProbeVolumeDynamicGIMixedLightMode mixedLightMode; - public ProbeVolumeDynamicGIRadianceEncoding radianceEncoding; - public ProbeVolumesEncodingModes encodingMode; } class ProbeVolumeDynamicGIPassData @@ -1121,18 +1128,19 @@ ProbeVolumeDynamicGICommonData PrepareProbeVolumeDynamicGIData(HDCamera hdCamera return data; data.volumes = ProbeVolumeManager.manager.GetVolumesToRender(); - data.giSettings = hdCamera.volumeStack.GetComponent(); - data.globalCB = m_ShaderVariablesGlobalCB; - data.ambientProbe = m_SkyManager.GetAmbientProbe(hdCamera); + data.dispatchData.giSettings = hdCamera.volumeStack.GetComponent(); + data.dispatchData.globalCB = m_ShaderVariablesGlobalCB; + data.dispatchData.ambientProbe = m_SkyManager.GetAmbientProbe(hdCamera); if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolumeDynamicGI) && SupportDynamicGI) { - data.infiniteBounces = hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolumeDynamicGIInfiniteBounces); - data.propagationQuality = hdCamera.frameSettings.probeVolumeDynamicGIPropagationQuality; + data.dispatchData.infiniteBounces = hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolumeDynamicGIInfiniteBounces); + data.dispatchData.dirtyFlagsDisabled = hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolumeDynamicGIDirtyFlagsDisabled); + data.dispatchData.propagationQuality = hdCamera.frameSettings.probeVolumeDynamicGIPropagationQuality; data.maxSimulationsPerFrameOverride = hdCamera.frameSettings.probeVolumeDynamicGIMaxSimulationsPerFrame; - data.mixedLightMode = hdCamera.frameSettings.probeVolumeDynamicGIMixedLightMode; - data.radianceEncoding = hdCamera.frameSettings.probeVolumeDynamicGIRadianceEncoding; - data.encodingMode = (ProbeVolumesEncodingModes)hdCamera.frameSettings.probeVolumeEncoding; + data.dispatchData.mixedLightMode = hdCamera.frameSettings.probeVolumeDynamicGIMixedLightMode; + data.dispatchData.radianceEncoding = hdCamera.frameSettings.probeVolumeDynamicGIRadianceEncoding; + data.dispatchData.encodingMode = (ProbeVolumesEncodingModes)hdCamera.frameSettings.probeVolumeEncoding; data.mode = ProbeVolumeDynamicGIMode.Dispatch; m_WasProbeVolumeDynamicGIEnabled = true; @@ -1146,14 +1154,14 @@ ProbeVolumeDynamicGICommonData PrepareProbeVolumeDynamicGIData(HDCamera hdCamera return data; } - static void ExecuteProbeVolumeDynamicGI(CommandBuffer cmd, ProbeVolumeDynamicGICommonData data, RenderTargetIdentifier probeVolumeAtlas) + static void ExecuteProbeVolumeDynamicGI(CommandBuffer cmd, in ProbeVolumeDynamicGICommonData data, RenderTargetIdentifier probeVolumeAtlas) { using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.ProbeVolumeDynamicGI))) { if (data.mode == ProbeVolumeDynamicGIMode.Dispatch) { // Update Probe Volume Data via Dynamic GI Propagation - float maxRange = Mathf.Max(data.giSettings.rangeBehindCamera.value, data.giSettings.rangeInFrontOfCamera.value); + float maxRange = Mathf.Max(data.dispatchData.giSettings.rangeBehindCamera.value, data.dispatchData.giSettings.rangeInFrontOfCamera.value); int maxSimulationsPerFrame = data.maxSimulationsPerFrameOverride; #if UNITY_EDITOR @@ -1195,10 +1203,7 @@ static void ExecuteProbeVolumeDynamicGI(CommandBuffer cmd, ProbeVolumeDynamicGIC { var simulationRequest = sortedRequests[i]; ProbeVolumeHandle volume = data.volumes[simulationRequest.probeVolumeIndex]; - ProbeVolumeDynamicGI.instance.DispatchProbePropagation(cmd, volume, data.giSettings, - in data.globalCB, probeVolumeAtlas, data.infiniteBounces, - (ProbeVolumeDynamicGI.PropagationQuality)data.propagationQuality, data.ambientProbe, - data.mixedLightMode, data.radianceEncoding, data.encodingMode); + ProbeVolumeDynamicGI.instance.DispatchProbePropagation(cmd, volume, probeVolumeAtlas, in data.dispatchData); } } else if (data.mode == ProbeVolumeDynamicGIMode.Clear) @@ -1452,6 +1457,10 @@ void RenderProbeVolumeDebugOverlay(in DebugParameters debugParameters, CommandBu { DisplayProbeVolumeAtlas(cmd, debugParameters.probeVolumeOverlayParameters, debugParameters.debugOverlay); } + else if (SupportDynamicGI && lightingDebug.probeVolumeDebugMode == ProbeVolumeDebugMode.VisualizeDynamicGIDirtyFlags) + { + DebugDrawProbeVolumeDirtyFlags(cmd); + } } } } @@ -1576,6 +1585,13 @@ static void DisplayProbeVolumeAtlas(CommandBuffer cmd, in ProbeVolumeDebugOverla debugOverlay.Next(); } + static void DebugDrawProbeVolumeDirtyFlags(CommandBuffer cmd) + { + var volumes = ProbeVolumeManager.manager.GetVolumesToRender(); + foreach (var volume in volumes) + ProbeVolumeDynamicGI.instance.DebugDrawDirtyFlags(cmd, volume); + } + #if UNITY_EDITOR internal void DrawProbeVolumeDebugSHPreview(ProbeVolume probeVolume, Camera camera) { diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/VolumeUtils.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/VolumeUtils.cs index dcd063d5150..ca7715e2f5b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/VolumeUtils.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ProbeVolume/VolumeUtils.cs @@ -7,6 +7,11 @@ namespace UnityEngine.Rendering.HighDefinition internal static class VolumeUtils { internal static Bounds ComputeBoundsWS(Transform transform, Vector3 size) + { + return ComputeBoundsWS(transform.position, transform.rotation, size); + } + + internal static Bounds ComputeBoundsWS(Vector3 position, Quaternion rotation, Vector3 size) { // Unity Bounds class has guards that will break assignment of Positive/Negative infinity. // In our case, we want these assignments to force the first iteration of the loop to assign the first position as the min and max. @@ -25,7 +30,7 @@ internal static Bounds ComputeBoundsWS(Transform transform, Vector3 size) positionOS.y = positionOS.y * size.y - 0.5f * size.y; positionOS.z = positionOS.z * size.z - 0.5f * size.z; - Vector3 positionWS = (transform.rotation * positionOS) + transform.position; + Vector3 positionWS = (rotation * positionOS) + position; boundsMin = Vector3.Min(boundsMin, positionWS); boundsMax = Vector3.Max(boundsMax, positionWS); @@ -38,19 +43,24 @@ internal static Bounds ComputeBoundsWS(Transform transform, Vector3 size) } internal static Matrix4x4 ComputeProbeIndex3DToPositionWSMatrix(Transform transform, Vector3 size, int resolutionX, int resolutionY, int resolutionZ) + { + return ComputeProbeIndex3DToPositionWSMatrix(transform.position, transform.rotation, size, resolutionX, resolutionY, resolutionZ); + } + + internal static Matrix4x4 ComputeProbeIndex3DToPositionWSMatrix(Vector3 position, Quaternion rotation, Vector3 size, int resolutionX, int resolutionY, int resolutionZ) { Vector3 scale = ComputeCellSizeWS(size, resolutionX, resolutionY, resolutionZ); // Handle half probe offset from bounds. - Vector3 translation = (transform.rotation * new Vector3( + Vector3 translation = (rotation * new Vector3( 0.5f * scale.x - size.x * 0.5f, 0.5f * scale.y - size.y * 0.5f, 0.5f * scale.z - size.z * 0.5f ) ) - + transform.position; + + position; - return Matrix4x4.TRS(translation, transform.rotation, scale); + return Matrix4x4.TRS(translation, rotation, scale); } internal static Vector3 ComputeCellSizeWS(Vector3 size, int resolutionX, int resolutionY, int resolutionZ) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs index 2eaa4ca183d..0feda5be82b 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -254,6 +254,7 @@ internal enum HDProfileId ProbeVolumeDynamicGIClear, ProbeVolumeDynamicGIInitialize, ProbeVolumeDynamicGIHits, + ProbeVolumeDynamicGIResetDirtyFlags, ProbeVolumeDynamicGIAxes, ProbeVolumeDynamicGICombine, diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index 8d7d950c06c..2bda83f3499 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -158,7 +158,7 @@ private void BeginRenderGraph(ScriptableRenderContext renderContext, CommandBuff passData.probeVolumesAtlas = builder.WriteTexture(m_ProbeVolumeList.rgResources.probeVolumesAtlas); builder.SetRenderFunc((ProbeVolumeDynamicGIPassData passData, RenderGraphContext ctx) => - ExecuteProbeVolumeDynamicGI(ctx.cmd, passData.commonData, passData.probeVolumesAtlas)); + ExecuteProbeVolumeDynamicGI(ctx.cmd, in passData.commonData, passData.probeVolumesAtlas)); } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 038b320cb4d..f3813f3bd93 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -2969,7 +2969,7 @@ void AsyncSSAODispatch(CommandBuffer c, HDGPUAsyncTaskParams a) ProbeVolumeDynamicGICommonData commonData = PrepareProbeVolumeDynamicGIData(hdCamera); if (commonData.mode != ProbeVolumeDynamicGIMode.None) { - ExecuteProbeVolumeDynamicGI(cmd, commonData, m_ProbeVolumeAtlasSHRTHandle); + ExecuteProbeVolumeDynamicGI(cmd, in commonData, m_ProbeVolumeAtlasSHRTHandle); } hdCamera.xr.StartSinglePass(cmd); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs index cc0d9b853f7..9297702cd40 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPipelineResources.cs @@ -352,12 +352,16 @@ public sealed class ShaderResources public ComputeShader probePropagationInitializeCS; [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationHits.compute")] public ComputeShader probePropagationHitsCS; + [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationResetDirtyFlags.compute")] + public ComputeShader probePropagationResetDirtyFlagsCS; [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationAxes.compute")] public ComputeShader probePropagationAxesCS; [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/ProbePropagationCombine.compute")] public ComputeShader probePropagationCombineCS; [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/DebugNeighbors.shader")] public Shader probeVolumeDebugNeighbors; + [Reload("Runtime/Lighting/ProbeVolume/DynamicGI/DebugDirtyFlags.shader")] + public Shader probeVolumeDebugDirtyFlags; // Iterator to retrieve all compute shaders in reflection so we don't have to keep a list of // used compute shaders up to date (prefer editor-only usage) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs index ba3a27d008c..00c4e570cf4 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs @@ -325,6 +325,8 @@ public enum FrameSettingsField ProbeVolumeDynamicGIMixedLightMode = 54, [FrameSettingsField(1, customOrderInGroup: 5, displayedName: "Radiance Encoding", positiveDependencies: new[] { ProbeVolume, ProbeVolumeDynamicGI }, type: FrameSettingsFieldAttribute.DisplayType.Others, targetType: typeof(ProbeVolumeDynamicGIRadianceEncoding))] ProbeVolumeDynamicGIRadianceEncoding = 55, + [FrameSettingsField(1, customOrderInGroup: 5, displayedName: "Disable Dirty Flags", positiveDependencies: new[] { ProbeVolume, ProbeVolumeDynamicGI })] + ProbeVolumeDynamicGIDirtyFlagsDisabled = 58, /// When enabled, Cameras using these Frame Settings render subsurface scattering (SSS) Materials with an added transmission effect (only if you enable Transmission on the SSS Material in the Material's Inspector). [FrameSettingsField(1, autoName: Transmission, tooltip: "When enabled, Cameras using these Frame Settings render subsurface scattering (SSS) Materials with an added transmission effect (only if you enable Transmission on the SSS Material in the Material's Inspector).")]