Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added the support of volumetric clouds for baked and realtime reflection probes.
- Added a property to control the fallback of the last bounce of a RTGI, RTR, RR ray to keep a previously existing side effect on user demand (case 1350590).
- Added a parameter to control the vertical shape offset of the volumetric clouds (case 1358528).
- Added an option to render screen space global illumination in half resolution to achieve real-time compatible performance in high resolutions (case 1353727).

### Fixed
- Fixed Intensity Multiplier not affecting realtime global illumination.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ HDRP uses the [Volume](Volumes.md) framework to calculate SSGI, so to enable and
| - **Half Resolution Denoiser** | Enable this feature to evaluate the spatio-temporal filter in half resolution. This decreases the resource intensity of denoising but reduces quality. |
| - **Denoiser Radius** | Set the radius of the spatio-temporal filter. |
| - **Second Denoiser Pass** | Enable this feature to process a second denoiser pass. This helps to remove noise from the effect. |
| **Full Resolution** | Enable this feature to increase the ray budget to one ray per pixel, per frame. Disable this feature to decrease the ray budget to one ray per four pixels, per frame.|
| **Depth Tolerance** | Use the slider to control the tolerance when comparing the depth of the GameObjects on screen and the depth buffer. Because the SSR algorithm can not distinguish thin GameObjects from thick ones, this property helps trace rays behind GameObjects. The algorithm applies this property to every GameObject uniformly. |
| **Ray Miss** | Determines what HDRP does when a screen space global illumination (SSGI) ray doesn't find an intersection. Choose from one of the following options: <br/>&#8226;**Reflection probes**: HDRP uses reflection probes in your scene to calculate the missing SSGI intersection.<br/>&#8226;**Sky**: HDRP uses the sky defined by the current [Volume](Volumes.md) settings to calculate the missing SSGI intersection.<br/>&#8226;**Both**: HDRP uses both reflection probes and the sky defined by the current [Volume](Volumes.md) settings to calculate the missing SSGI intersection.<br/>&#8226;**Nothing**: HDRP does not calculate indirect lighting when SSGI doesn't find an intersection.<br/><br/>This property is set to **Both** by default. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class GlobalIlluminatorEditor : VolumeComponentWithQualityEditor
SerializedDataParameter m_RayMiss;

// Screen space global illumination parameters
SerializedDataParameter m_FullResolutionSS;
SerializedDataParameter m_DepthBufferThickness;
SerializedDataParameter m_RaySteps;

Expand Down Expand Up @@ -60,6 +61,7 @@ public override void OnEnable()
m_RayMiss = Unpack(o.Find(x => x.rayMiss));

// SSGI Parameters
m_FullResolutionSS = Unpack(o.Find(x => x.fullResolutionSS));
m_DepthBufferThickness = Unpack(o.Find(x => x.depthBufferThickness));
m_RaySteps = Unpack(o.Find(x => x.maxRaySteps));

Expand Down Expand Up @@ -98,6 +100,7 @@ public override void OnEnable()
}

static public readonly GUIContent k_RayLengthText = EditorGUIUtility.TrTextContent("Max Ray Length", "Controls the maximal length of global illumination rays. The higher this value is, the more expensive ray traced global illumination is.");
static public readonly GUIContent k_FullResolutionSSText = EditorGUIUtility.TrTextContent("Full Resolution", "Controls if the screen space global illumination should be evaluated at half resolution.");
static public readonly GUIContent k_DepthBufferThicknessText = EditorGUIUtility.TrTextContent("Depth Tolerance", "Controls the tolerance when comparing the depth of two pixels.");
static public readonly GUIContent k_RayMissFallbackHierarchyText = EditorGUIUtility.TrTextContent("Ray Miss", "Controls the fallback hierarchy for indirect diffuse in case the ray misses.");
static public readonly GUIContent k_LastBounceFallbackHierarchyText = EditorGUIUtility.TrTextContent("Last Bounce", "Controls the fallback hierarchy for lighting the last bounce.");
Expand Down Expand Up @@ -245,6 +248,7 @@ public override void OnInspectorGUI()
PropertyField(m_RaySteps);
DenoiserSSGUI();
}
PropertyField(m_FullResolutionSS, k_FullResolutionSSText);
PropertyField(m_DepthBufferThickness, k_DepthBufferThicknessText);
PropertyField(m_RayMiss, k_RayMissFallbackHierarchyText);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ bool UsesQualityMode()
displayName = "Screen Space Global Illumination";
}

/// <summary>
/// Defines if the screen space global illumination should be evaluated at full resolution.
/// </summary>
public BoolParameter fullResolutionSS = new BoolParameter(true);

/// <summary>
/// The number of steps that should be used during the ray marching pass.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,18 @@ TextureHandle TraceSSGI(RenderGraph renderGraph, HDCamera hdCamera, GlobalIllumi
{
builder.EnableAsyncCompute(false);

//if (true)
if (giSettings.fullResolutionSS.value)
{
passData.texWidth = hdCamera.actualWidth;
passData.texHeight = hdCamera.actualHeight;
passData.halfScreenSize.Set(passData.texWidth * 0.5f, passData.texHeight * 0.5f, 2.0f / passData.texWidth, 2.0f / passData.texHeight);
}
/*
else
{
passData.texWidth = hdCamera.actualWidth / 2;
passData.texHeight = hdCamera.actualHeight / 2;
passData.halfScreenSize.Set(passData.texWidth, passData.texHeight, 1.0f / passData.texWidth, 1.0f / passData.texHeight);
}
*/
passData.viewCount = hdCamera.viewCount;

// Set the generation parameters
Expand All @@ -189,8 +187,8 @@ TextureHandle TraceSSGI(RenderGraph renderGraph, HDCamera hdCamera, GlobalIllumi

// Grab the right kernel
passData.ssGICS = asset.renderPipelineResources.shaders.screenSpaceGlobalIlluminationCS;
passData.traceKernel = true ? m_TraceGlobalIlluminationKernel : m_TraceGlobalIlluminationHalfKernel;
passData.projectKernel = true ? m_ReprojectGlobalIlluminationKernel : m_ReprojectGlobalIlluminationHalfKernel;
passData.traceKernel = giSettings.fullResolutionSS.value ? m_TraceGlobalIlluminationKernel : m_TraceGlobalIlluminationHalfKernel;
passData.projectKernel = giSettings.fullResolutionSS.value ? m_ReprojectGlobalIlluminationKernel : m_ReprojectGlobalIlluminationHalfKernel;

BlueNoise blueNoise = GetBlueNoiseManager();
passData.ditheredTextureSet = blueNoise.DitheredTextureSet8SPP();
Expand Down Expand Up @@ -384,7 +382,7 @@ class ConvertSSGIPassData
public TextureHandle outputBuffer;
}

TextureHandle ConvertSSGI(RenderGraph renderGraph, HDCamera hdCamera, bool halfResolution,
TextureHandle ConvertSSGI(RenderGraph renderGraph, HDCamera hdCamera, bool fullResolution,
TextureHandle depthPyramid, TextureHandle stencilBuffer, TextureHandle normalBuffer,
TextureHandle inputBuffer)
{
Expand All @@ -393,7 +391,7 @@ TextureHandle ConvertSSGI(RenderGraph renderGraph, HDCamera hdCamera, bool halfR
builder.EnableAsyncCompute(false);

// Set the camera parameters
if (!halfResolution)
if (fullResolution)
{
passData.texWidth = hdCamera.actualWidth;
passData.texHeight = hdCamera.actualHeight;
Expand All @@ -407,7 +405,7 @@ TextureHandle ConvertSSGI(RenderGraph renderGraph, HDCamera hdCamera, bool halfR

// Grab the right kernel
passData.ssGICS = m_Asset.renderPipelineResources.shaders.screenSpaceGlobalIlluminationCS;
passData.convertKernel = halfResolution ? m_ConvertSSGIHalfKernel : m_ConvertSSGIKernel;
passData.convertKernel = fullResolution ? m_ConvertSSGIKernel : m_ConvertSSGIHalfKernel;

passData.offsetBuffer = m_DepthBufferMipChainInfo.GetOffsetBufferData(m_DepthPyramidMipLevelOffsetsBuffer);

Expand Down Expand Up @@ -446,13 +444,13 @@ TextureHandle ConvertSSGI(RenderGraph renderGraph, HDCamera hdCamera, bool halfR
}
}

TextureHandle DenoiseSSGI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle rtGIBuffer, TextureHandle depthPyramid, TextureHandle normalBuffer, TextureHandle motionVectorBuffer, TextureHandle historyValidationTexture)
TextureHandle DenoiseSSGI(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle rtGIBuffer, TextureHandle depthPyramid, TextureHandle normalBuffer, TextureHandle motionVectorBuffer, TextureHandle historyValidationTexture, bool fullResolution)
{
var giSettings = hdCamera.volumeStack.GetComponent<GlobalIllumination>();
if (giSettings.denoiseSS)
{
// Evaluate the history's validity
float historyValidity0 = EvaluateIndirectDiffuseHistoryValidity0(hdCamera, true, false);
float historyValidity0 = EvaluateIndirectDiffuseHistoryValidity0(hdCamera, fullResolution, false);

HDTemporalFilter temporalFilter = GetTemporalFilter();
HDDiffuseDenoiser diffuseDenoiser = GetDiffuseDenoiser();
Expand All @@ -465,34 +463,47 @@ TextureHandle DenoiseSSGI(RenderGraph renderGraph, HDCamera hdCamera, TextureHan
filterParams.occluderMotionRejection = false;
filterParams.receiverMotionRejection = false;
filterParams.exposureControl = true;
filterParams.fullResolution = fullResolution;
TextureHandle denoisedRTGI = temporalFilter.Denoise(renderGraph, hdCamera, filterParams, rtGIBuffer, renderGraph.defaultResources.blackTextureXR, historyBufferHF, depthPyramid, normalBuffer, motionVectorBuffer, historyValidationTexture);

// Apply the diffuse denoiser
rtGIBuffer = diffuseDenoiser.Denoise(renderGraph, hdCamera, singleChannel: false, kernelSize: giSettings.denoiserRadiusSS, halfResolutionFilter: giSettings.halfResolutionDenoiserSS, jitterFilter: giSettings.secondDenoiserPassSS, denoisedRTGI, depthPyramid, normalBuffer, rtGIBuffer);
HDDiffuseDenoiser.DiffuseDenoiserParameters ddParams;
ddParams.singleChannel = false;
ddParams.kernelSize = giSettings.denoiserRadiusSS;
ddParams.halfResolutionFilter = giSettings.halfResolutionDenoiserSS;
ddParams.jitterFilter = giSettings.secondDenoiserPassSS;
ddParams.fullResolutionInput = fullResolution;
rtGIBuffer = diffuseDenoiser.Denoise(renderGraph, hdCamera, ddParams, denoisedRTGI, depthPyramid, normalBuffer, rtGIBuffer);

// If the second pass is requested, do it otherwise blit
if (giSettings.secondDenoiserPassSS)
{
float historyValidity1 = EvaluateIndirectDiffuseHistoryValidity1(hdCamera, true, false);
float historyValidity1 = EvaluateIndirectDiffuseHistoryValidity1(hdCamera, fullResolution, false);

// Run the temporal denoiser
// Run the temporal filter
TextureHandle historyBufferLF = renderGraph.ImportTexture(RequestIndirectDiffuseHistoryTextureLF(hdCamera));
filterParams.singleChannel = false;
filterParams.historyValidity = historyValidity1;
filterParams.occluderMotionRejection = false;
filterParams.receiverMotionRejection = false;
filterParams.exposureControl = true;
filterParams.fullResolution = fullResolution;
denoisedRTGI = temporalFilter.Denoise(renderGraph, hdCamera, filterParams, rtGIBuffer, renderGraph.defaultResources.blackTextureXR, historyBufferLF, depthPyramid, normalBuffer, motionVectorBuffer, historyValidationTexture);

// Apply the diffuse denoiser
rtGIBuffer = diffuseDenoiser.Denoise(renderGraph, hdCamera, singleChannel: false, kernelSize: giSettings.denoiserRadiusSS * 0.5f, halfResolutionFilter: giSettings.halfResolutionDenoiserSS, jitterFilter: false, denoisedRTGI, depthPyramid, normalBuffer, rtGIBuffer);
// Apply the diffuse filter
ddParams.singleChannel = false;
ddParams.kernelSize = giSettings.denoiserRadiusSS * 0.5f;
ddParams.halfResolutionFilter = giSettings.halfResolutionDenoiserSS;
ddParams.jitterFilter = false;
ddParams.fullResolutionInput = fullResolution;
rtGIBuffer = diffuseDenoiser.Denoise(renderGraph, hdCamera, ddParams, denoisedRTGI, depthPyramid, normalBuffer, rtGIBuffer);

// Propagate the history validity for the second buffer
PropagateIndirectDiffuseHistoryValidity1(hdCamera, true, false);
PropagateIndirectDiffuseHistoryValidity1(hdCamera, fullResolution, false);
}

// Propagate the history validity for the first buffer
PropagateIndirectDiffuseHistoryValidity0(hdCamera, true, false);
PropagateIndirectDiffuseHistoryValidity0(hdCamera, fullResolution, false);

return rtGIBuffer;
}
Expand All @@ -513,17 +524,16 @@ TextureHandle RenderSSGI(RenderGraph renderGraph, HDCamera hdCamera,
TextureHandle colorBuffer = TraceSSGI(renderGraph, hdCamera, giSettings, depthPyramid, normalBuffer, stencilBuffer, motionVectorsBuffer, lightList);

// Denoise the result
TextureHandle denoisedSSGI = DenoiseSSGI(renderGraph, hdCamera, colorBuffer, depthPyramid, normalBuffer, motionVectorsBuffer, historyValidationTexture);
TextureHandle denoisedSSGI = DenoiseSSGI(renderGraph, hdCamera, colorBuffer, depthPyramid, normalBuffer, motionVectorsBuffer, historyValidationTexture, giSettings.fullResolutionSS.value);

// Convert back the result to RGB space
colorBuffer = ConvertSSGI(renderGraph, hdCamera, false, depthPyramid, stencilBuffer, normalBuffer, denoisedSSGI);
colorBuffer = ConvertSSGI(renderGraph, hdCamera, giSettings.fullResolutionSS.value, depthPyramid, stencilBuffer, normalBuffer, denoisedSSGI);

/*
// Upscale it if required
// If this was a half resolution effect, we still have to upscale it
if (!giSettings.fullResolutionSS)
if (!giSettings.fullResolutionSS.value)
colorBuffer = UpscaleSSGI(renderGraph, hdCamera, giSettings, info, depthPyramid, colorBuffer);
*/

return colorBuffer;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,22 @@ void TRACE_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uin

// Compute the pixel position to process
uint2 currentCoord = dispatchThreadId.xy;
uint2 inputCoord = dispatchThreadId.xy;

#if HALF_RES
// Compute the full resolution pixel for the inputs that do not have a pyramid
currentCoord = currentCoord * 2;
inputCoord = inputCoord * 2;
#endif

// Read the depth value as early as possible
float deviceDepth = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x;
float deviceDepth = LOAD_TEXTURE2D_X(_DepthTexture, inputCoord).x;

// Initialize the hitpoint texture to a miss
_IndirectDiffuseHitPointTextureRW[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = float2(99.0, 0.0);
_IndirectDiffuseHitPointTextureRW[COORD_TEXTURE2D_X(currentCoord.xy)] = float2(99.0, 0.0);

// Read the pixel normal
NormalData normalData;
DecodeFromNormalBuffer(currentCoord.xy, normalData);
DecodeFromNormalBuffer(inputCoord.xy, normalData);

// Generete a new direction to follow
float2 newSample;
Expand All @@ -108,7 +109,7 @@ void TRACE_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uin
// If this is a background pixel, we flag the ray as a dead ray (we are also trying to keep the usage of the depth buffer the latest possible)
bool killRay = deviceDepth == UNITY_RAW_FAR_CLIP_VALUE;
// Convert this to a world space position (camera relative)
PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, deviceDepth, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
PositionInputs posInput = GetPositionInput(inputCoord, _ScreenSize.zw, deviceDepth, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);

// Compute the view direction (world space)
float3 viewWS = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
Expand All @@ -129,7 +130,7 @@ void TRACE_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uin
// recompute it using the last value of 't', which would result in an overshoot.
// It also needs to be precisely at the center of the pixel to avoid artifacts.
float2 hitPositionNDC = floor(rayPos.xy) * _ScreenSize.zw + (0.5 * _ScreenSize.zw); // Should we precompute the half-texel bias? We seem to use it a lot.
_IndirectDiffuseHitPointTextureRW[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = hitPositionNDC;
_IndirectDiffuseHitPointTextureRW[COORD_TEXTURE2D_X(currentCoord.xy)] = hitPositionNDC;
}
}

Expand Down
Loading