2021-09-09 20:42:29 -04:00

372 lines
19 KiB
C#

using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.HighDefinition
{
[GenerateHLSL]
// Define if we use SSGI, RTGI or none
enum IndirectDiffuseMode
{
Off,
ScreenSpace,
Raytrace
}
public partial class HDRenderPipeline
{
// The set of kernels that we shall be using
int m_TraceGlobalIlluminationKernel;
int m_TraceGlobalIlluminationHalfKernel;
int m_ReprojectGlobalIlluminationKernel;
int m_ReprojectGlobalIlluminationHalfKernel;
int m_BilateralUpSampleColorKernel;
int m_ConvertYCoCgToRGBKernel;
int m_ConvertYCoCgToRGBHalfKernel;
void InitScreenSpaceGlobalIllumination()
{
if (m_Asset.currentPlatformRenderPipelineSettings.supportSSGI)
{
// Grab the sets of shaders that we'll be using
ComputeShader ssGICS = m_Asset.renderPipelineResources.shaders.screenSpaceGlobalIlluminationCS;
ComputeShader bilateralUpsampleCS = m_Asset.renderPipelineResources.shaders.bilateralUpsampleCS;
// Grab the set of kernels that we shall be using
m_TraceGlobalIlluminationKernel = ssGICS.FindKernel("TraceGlobalIllumination");
m_TraceGlobalIlluminationHalfKernel = ssGICS.FindKernel("TraceGlobalIlluminationHalf");
m_ReprojectGlobalIlluminationKernel = ssGICS.FindKernel("ReprojectGlobalIllumination");
m_ReprojectGlobalIlluminationHalfKernel = ssGICS.FindKernel("ReprojectGlobalIlluminationHalf");
m_BilateralUpSampleColorKernel = bilateralUpsampleCS.FindKernel("BilateralUpSampleColor");
m_ConvertYCoCgToRGBKernel = ssGICS.FindKernel("ConvertYCoCgToRGB");
m_ConvertYCoCgToRGBHalfKernel = ssGICS.FindKernel("ConvertYCoCgToRGBHalf");
}
}
// This is shared between SSGI and RTGI
IndirectDiffuseMode GetIndirectDiffuseMode(HDCamera hdCamera)
{
IndirectDiffuseMode mode = IndirectDiffuseMode.Off;
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.SSGI))
{
var settings = hdCamera.volumeStack.GetComponent<GlobalIllumination>();
if (settings.enable.value)
{
// RTGI is only valid if raytracing is enabled
bool raytracing = hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && settings.rayTracing.value;
mode = raytracing ? IndirectDiffuseMode.Raytrace : IndirectDiffuseMode.ScreenSpace;
}
}
return mode;
}
struct SSGITraceParameters
{
// Camera parameters
public int texWidth;
public int texHeight;
public int viewCount;
public Vector4 halfScreenSize;
// Generation parameters
public float nearClipPlane;
public float farClipPlane;
public bool fullResolutionSS;
public float thickness;
public int raySteps;
public Vector4 colorPyramidUvScaleAndLimitPrevFrame;
// Compute Shader
public ComputeShader ssGICS;
public int traceKernel;
public int projectKernel;
// Other parameters
public BlueNoise.DitheredTextureSet ditheredTextureSet;
public ShaderVariablesRaytracing shaderVariablesRayTracingCB;
public ComputeBuffer offsetBuffer;
}
SSGITraceParameters PrepareSSGITraceParameters(HDCamera hdCamera, GlobalIllumination settings)
{
SSGITraceParameters parameters = new SSGITraceParameters();
// Set the camera parameters
if (settings.fullResolutionSS)
{
parameters.texWidth = hdCamera.actualWidth;
parameters.texHeight = hdCamera.actualHeight;
parameters.halfScreenSize.Set(parameters.texWidth * 0.5f, parameters.texHeight * 0.5f, 2.0f / parameters.texWidth, 2.0f / parameters.texHeight);
}
else
{
parameters.texWidth = hdCamera.actualWidth / 2;
parameters.texHeight = hdCamera.actualHeight / 2;
parameters.halfScreenSize.Set(parameters.texWidth, parameters.texHeight, 1.0f / parameters.texWidth, 1.0f / parameters.texHeight);
}
parameters.viewCount = hdCamera.viewCount;
// Set the generation parameters
parameters.nearClipPlane = hdCamera.camera.nearClipPlane;
parameters.farClipPlane = hdCamera.camera.farClipPlane;
parameters.fullResolutionSS = settings.fullResolutionSS;
parameters.thickness = settings.depthBufferThickness.value;
parameters.raySteps = settings.raySteps;
parameters.colorPyramidUvScaleAndLimitPrevFrame = HDUtils.ComputeViewportScaleAndLimit(hdCamera.historyRTHandleProperties.previousViewportSize, hdCamera.historyRTHandleProperties.previousRenderTargetSize);
// Grab the right kernel
parameters.ssGICS = m_Asset.renderPipelineResources.shaders.screenSpaceGlobalIlluminationCS;
parameters.traceKernel = settings.fullResolutionSS ? m_TraceGlobalIlluminationKernel : m_TraceGlobalIlluminationHalfKernel;
parameters.projectKernel = settings.fullResolutionSS ? m_ReprojectGlobalIlluminationKernel : m_ReprojectGlobalIlluminationHalfKernel;
BlueNoise blueNoise = GetBlueNoiseManager();
parameters.ditheredTextureSet = blueNoise.DitheredTextureSet8SPP();
parameters.shaderVariablesRayTracingCB = m_ShaderVariablesRayTracingCB;
parameters.offsetBuffer = m_DepthBufferMipChainInfo.GetOffsetBufferData(m_DepthPyramidMipLevelOffsetsBuffer);
return parameters;
}
struct SSGITraceResources
{
// Input buffers
public RTHandle depthTexture;
public RTHandle normalBuffer;
public RTHandle motionVectorsBuffer;
public RTHandle colorPyramid;
public RTHandle historyDepth;
// Intermediate buffers
public RTHandle hitPointBuffer;
// Output buffers
public RTHandle outputBuffer0;
public RTHandle outputBuffer1;
}
static void ExecuteSSGITrace(CommandBuffer cmd, SSGITraceParameters parameters, SSGITraceResources resources)
{
int ssgiTileSize = 8;
int numTilesXHR = (parameters.texWidth + (ssgiTileSize - 1)) / ssgiTileSize;
int numTilesYHR = (parameters.texHeight + (ssgiTileSize - 1)) / ssgiTileSize;
// Inject all the input scalars
float n = parameters.nearClipPlane;
float f = parameters.farClipPlane;
float thicknessScale = 1.0f / (1.0f + parameters.thickness);
float thicknessBias = -n / (f - n) * (parameters.thickness * thicknessScale);
cmd.SetComputeFloatParam(parameters.ssGICS, HDShaderIDs._IndirectDiffuseThicknessScale, thicknessScale);
cmd.SetComputeFloatParam(parameters.ssGICS, HDShaderIDs._IndirectDiffuseThicknessBias, thicknessBias);
cmd.SetComputeIntParam(parameters.ssGICS, HDShaderIDs._IndirectDiffuseSteps, parameters.raySteps);
// Inject half screen size if required
if (!parameters.fullResolutionSS)
cmd.SetComputeVectorParam(parameters.ssGICS, HDShaderIDs._HalfScreenSize, parameters.halfScreenSize);
// Inject the ray-tracing sampling data
BlueNoise.BindDitheredTextureSet(cmd, parameters.ditheredTextureSet);
// Inject all the input textures/buffers
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.traceKernel, HDShaderIDs._DepthTexture, resources.depthTexture);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.traceKernel, HDShaderIDs._NormalBufferTexture, resources.normalBuffer);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.traceKernel, HDShaderIDs._IndirectDiffuseHitPointTextureRW, resources.hitPointBuffer);
cmd.SetComputeBufferParam(parameters.ssGICS, parameters.traceKernel, HDShaderIDs._DepthPyramidMipLevelOffsets, parameters.offsetBuffer);
// Do the ray marching
cmd.DispatchCompute(parameters.ssGICS, parameters.traceKernel, numTilesXHR, numTilesYHR, parameters.viewCount);
// Update global constant buffer.
// This should probably be a shader specific uniform instead of reusing the global constant buffer one since it's the only one updated here.
ConstantBuffer.PushGlobal(cmd, parameters.shaderVariablesRayTracingCB, HDShaderIDs._ShaderVariablesRaytracing);
// Inject all the input scalars
cmd.SetComputeVectorParam(parameters.ssGICS, HDShaderIDs._ColorPyramidUvScaleAndLimitPrevFrame, parameters.colorPyramidUvScaleAndLimitPrevFrame);
// Bind all the input buffers
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._DepthTexture, resources.depthTexture);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._NormalBufferTexture, resources.normalBuffer);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._CameraMotionVectorsTexture, resources.motionVectorsBuffer);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._IndirectDiffuseHitPointTexture, resources.hitPointBuffer);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._ColorPyramidTexture, resources.colorPyramid);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._HistoryDepthTexture, resources.historyDepth);
cmd.SetComputeBufferParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._DepthPyramidMipLevelOffsets, parameters.offsetBuffer);
// Bind the output texture
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._IndirectDiffuseTexture0RW, resources.outputBuffer0);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.projectKernel, HDShaderIDs._IndirectDiffuseTexture1RW, resources.outputBuffer1);
// Do the reprojection
cmd.DispatchCompute(parameters.ssGICS, parameters.projectKernel, numTilesXHR, numTilesYHR, parameters.viewCount);
}
struct SSGIConvertParameters
{
// Camera parameters
public int texWidth;
public int texHeight;
public int viewCount;
// Compute Shader
public ComputeShader ssGICS;
public int convertKernel;
public ComputeBuffer offsetBuffer;
}
SSGIConvertParameters PrepareSSGIConvertParameters(HDCamera hdCamera, bool halfResolution)
{
SSGIConvertParameters parameters = new SSGIConvertParameters();
// Set the camera parameters
if (!halfResolution)
{
parameters.texWidth = hdCamera.actualWidth;
parameters.texHeight = hdCamera.actualHeight;
}
else
{
parameters.texWidth = hdCamera.actualWidth / 2;
parameters.texHeight = hdCamera.actualHeight / 2;
}
parameters.viewCount = hdCamera.viewCount;
// Grab the right kernel
parameters.ssGICS = m_Asset.renderPipelineResources.shaders.screenSpaceGlobalIlluminationCS;
parameters.convertKernel = halfResolution ? m_ConvertYCoCgToRGBHalfKernel : m_ConvertYCoCgToRGBKernel;
parameters.offsetBuffer = m_DepthBufferMipChainInfo.GetOffsetBufferData(m_DepthPyramidMipLevelOffsetsBuffer);
return parameters;
}
struct SSGIConvertResources
{
public RTHandle depthTexture;
public RTHandle stencilBuffer;
public RTHandle normalBuffer;
public RTHandle inoutBuffer0;
public RTHandle inputBufer1;
}
static void ExecuteSSGIConversion(CommandBuffer cmd, SSGIConvertParameters parameters, SSGIConvertResources resources)
{
// Re-evaluate the dispatch parameters (we are evaluating the upsample in full resolution)
int ssgiTileSize = 8;
int numTilesXHR = (parameters.texWidth + (ssgiTileSize - 1)) / ssgiTileSize;
int numTilesYHR = (parameters.texHeight + (ssgiTileSize - 1)) / ssgiTileSize;
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._DepthTexture, resources.depthTexture);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._NormalBufferTexture, resources.normalBuffer);
cmd.SetComputeBufferParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._DepthPyramidMipLevelOffsets, parameters.offsetBuffer);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._IndirectDiffuseTexture0RW, resources.inoutBuffer0);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._IndirectDiffuseTexture1, resources.inputBufer1);
cmd.SetComputeTextureParam(parameters.ssGICS, parameters.convertKernel, HDShaderIDs._StencilTexture, resources.stencilBuffer, 0, RenderTextureSubElement.Stencil);
cmd.SetComputeIntParams(parameters.ssGICS, HDShaderIDs._SsrStencilBit, (int)StencilUsage.TraceReflectionRay);
cmd.DispatchCompute(parameters.ssGICS, parameters.convertKernel, numTilesXHR, numTilesYHR, parameters.viewCount);
}
struct SSGIUpscaleParameters
{
// Camera parameters
public int texWidth;
public int texHeight;
public int viewCount;
public Vector4 halfScreenSize;
// Generation parameters
public Vector2 firstMipOffset;
// Compute Shader
public ComputeShader bilateralUpsampleCS;
public int upscaleKernel;
}
SSGIUpscaleParameters PrepareSSGIUpscaleParameters(HDCamera hdCamera, GlobalIllumination settings, HDUtils.PackedMipChainInfo info)
{
SSGIUpscaleParameters parameters = new SSGIUpscaleParameters();
// Set the camera parameters
parameters.texWidth = hdCamera.actualWidth;
parameters.texHeight = hdCamera.actualHeight;
parameters.viewCount = hdCamera.viewCount;
parameters.halfScreenSize.Set(parameters.texWidth / 2, parameters.texHeight / 2, 1.0f / (parameters.texWidth * 0.5f), 1.0f / (parameters.texHeight * 0.5f));
// Set the generation parameters
parameters.firstMipOffset.Set(HDShadowUtils.Asfloat((uint)info.mipLevelOffsets[1].x), HDShadowUtils.Asfloat((uint)info.mipLevelOffsets[1].y));
// Grab the right kernel
parameters.bilateralUpsampleCS = m_Asset.renderPipelineResources.shaders.bilateralUpsampleCS;
parameters.upscaleKernel = m_BilateralUpSampleColorKernel;
return parameters;
}
struct SSGIUpscaleResources
{
// Input buffers
public RTHandle depthTexture;
public RTHandle inputBuffer;
// Output buffers
public RTHandle outputBuffer;
}
static void ExecuteSSGIUpscale(CommandBuffer cmd, SSGIUpscaleParameters parameters, SSGIUpscaleResources resources)
{
// Re-evaluate the dispatch parameters (we are evaluating the upsample in full resolution)
int ssgiTileSize = 8;
int numTilesXHR = (parameters.texWidth + (ssgiTileSize - 1)) / ssgiTileSize;
int numTilesYHR = (parameters.texHeight + (ssgiTileSize - 1)) / ssgiTileSize;
// Inject the input scalars
cmd.SetComputeVectorParam(parameters.bilateralUpsampleCS, HDShaderIDs._HalfScreenSize, parameters.halfScreenSize);
cmd.SetComputeVectorParam(parameters.bilateralUpsampleCS, HDShaderIDs._DepthPyramidFirstMipLevelOffset, parameters.firstMipOffset);
// Inject all the input buffers
cmd.SetComputeTextureParam(parameters.bilateralUpsampleCS, parameters.upscaleKernel, HDShaderIDs._DepthTexture, resources.depthTexture);
cmd.SetComputeTextureParam(parameters.bilateralUpsampleCS, parameters.upscaleKernel, HDShaderIDs._LowResolutionTexture, resources.inputBuffer);
// Inject the output textures
cmd.SetComputeTextureParam(parameters.bilateralUpsampleCS, parameters.upscaleKernel, HDShaderIDs._OutputUpscaledTexture, resources.outputBuffer);
// Upscale the buffer to full resolution
cmd.DispatchCompute(parameters.bilateralUpsampleCS, parameters.upscaleKernel, numTilesXHR, numTilesYHR, parameters.viewCount);
}
private float EvaluateIndirectDiffuseHistoryValidityCombined(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
// Evaluate the history validity
float effectHistoryValidity = hdCamera.EffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination0, fullResolution, rayTraced)
&& hdCamera.EffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination1, fullResolution, rayTraced) ? 1.0f : 0.0f;
return EvaluateHistoryValidity(hdCamera) * effectHistoryValidity;
}
private float EvaluateIndirectDiffuseHistoryValidity0(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
// Evaluate the history validity
float effectHistoryValidity = hdCamera.EffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination0, fullResolution, rayTraced) ? 1.0f : 0.0f;
return EvaluateHistoryValidity(hdCamera) * effectHistoryValidity;
}
private float EvaluateIndirectDiffuseHistoryValidity1(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
// Evaluate the history validity
float effectHistoryValidity = hdCamera.EffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination1, fullResolution, rayTraced) ? 1.0f : 0.0f;
return EvaluateHistoryValidity(hdCamera) * effectHistoryValidity;
}
private void PropagateIndirectDiffuseHistoryValidityCombined(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
hdCamera.PropagateEffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination0, fullResolution, rayTraced);
hdCamera.PropagateEffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination1, fullResolution, rayTraced);
}
private void PropagateIndirectDiffuseHistoryValidity0(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
hdCamera.PropagateEffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination0, fullResolution, rayTraced);
}
private void PropagateIndirectDiffuseHistoryValidity1(HDCamera hdCamera, bool fullResolution, bool rayTraced)
{
hdCamera.PropagateEffectHistoryValidity(HDCamera.HistoryEffectSlot.GlobalIllumination1, fullResolution, rayTraced);
}
}
}