1655 lines
92 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.HighDefinition
{
public partial class HDRenderPipeline
{
class TempPassData {};
// Needed only because of custom pass. See comment at ResolveMSAAColor.
TextureHandle m_NonMSAAColorBuffer;
void ExecuteWithRenderGraph(RenderRequest renderRequest,
AOVRequestData aovRequest,
List<RTHandle> aovBuffers,
List<RTHandle> aovCustomPassBuffers,
ScriptableRenderContext renderContext,
CommandBuffer commandBuffer)
{
var hdCamera = renderRequest.hdCamera;
var camera = hdCamera.camera;
var cullingResults = renderRequest.cullingResults.cullingResults;
var customPassCullingResults = renderRequest.cullingResults.customPassCullingResults ?? cullingResults;
bool msaa = hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA);
var target = renderRequest.target;
var renderGraphParams = new RenderGraphParameters()
{
scriptableRenderContext = renderContext,
commandBuffer = commandBuffer,
currentFrameIndex = m_FrameCount
};
m_RenderGraph.Begin(renderGraphParams);
// We need to initalize the MipChainInfo here, so it will be available to any render graph pass that wants to use it during setup
// Be careful, ComputePackedMipChainInfo needs the render texture size and not the viewport size. Otherwise it would compute the wrong size.
m_DepthBufferMipChainInfo.ComputePackedMipChainInfo(RTHandles.rtHandleProperties.currentRenderTargetSize);
#if UNITY_EDITOR
var showGizmos = camera.cameraType == CameraType.Game
|| camera.cameraType == CameraType.SceneView;
#endif
TextureHandle backBuffer = m_RenderGraph.ImportBackbuffer(target.id);
TextureHandle colorBuffer = CreateColorBuffer(m_RenderGraph, hdCamera, msaa);
m_NonMSAAColorBuffer = CreateColorBuffer(m_RenderGraph, hdCamera, false);
TextureHandle currentColorPyramid = m_RenderGraph.ImportTexture(hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain));
TextureHandle rayCountTexture = RayCountManager.CreateRayCountTexture(m_RenderGraph);
#if ENABLE_VIRTUALTEXTURES
TextureHandle vtFeedbackBuffer = VTBufferManager.CreateVTFeedbackBuffer(m_RenderGraph, msaa);
#else
TextureHandle vtFeedbackBuffer = TextureHandle.nullHandle;
#endif
LightingBuffers lightingBuffers = new LightingBuffers();
lightingBuffers.diffuseLightingBuffer = CreateDiffuseLightingBuffer(m_RenderGraph, msaa);
lightingBuffers.sssBuffer = CreateSSSBuffer(m_RenderGraph, hdCamera, msaa);
var prepassOutput = RenderPrepass(m_RenderGraph, colorBuffer, lightingBuffers.sssBuffer, vtFeedbackBuffer, cullingResults, customPassCullingResults, hdCamera, aovRequest, aovBuffers);
// Need this during debug render at the end outside of the main loop scope.
// Once render graph move is implemented, we can probably remove the branch and this.
ShadowResult shadowResult = new ShadowResult();
BuildGPULightListOutput gpuLightListOutput = new BuildGPULightListOutput();
if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() && m_CurrentDebugDisplaySettings.IsFullScreenDebugPassEnabled())
{
// Stop Single Pass is after post process.
StartXRSinglePass(m_RenderGraph, hdCamera);
RenderFullScreenDebug(m_RenderGraph, colorBuffer, prepassOutput.depthBuffer, cullingResults, hdCamera);
}
else if (m_CurrentDebugDisplaySettings.IsDebugMaterialDisplayEnabled() || m_CurrentDebugDisplaySettings.IsMaterialValidationEnabled() || CoreUtils.IsSceneLightingDisabled(hdCamera.camera))
{
gpuLightListOutput = BuildGPULightList(m_RenderGraph, hdCamera, m_TileAndClusterData, m_TotalLightCount, ref m_ShaderVariablesLightListCB, prepassOutput.depthBuffer, prepassOutput.stencilBuffer, prepassOutput.gbuffer);
// For alpha output in AOVs or debug views, in case we have a shadow matte material, we need to render the shadow maps
if (m_CurrentDebugDisplaySettings.data.materialDebugSettings.debugViewMaterialCommonValue == Attributes.MaterialSharedProperty.Alpha)
RenderShadows(m_RenderGraph, hdCamera, cullingResults, ref shadowResult);
// Stop Single Pass is after post process.
StartXRSinglePass(m_RenderGraph, hdCamera);
colorBuffer = RenderDebugViewMaterial(m_RenderGraph, cullingResults, hdCamera, gpuLightListOutput, prepassOutput.dbuffer, prepassOutput.gbuffer);
colorBuffer = ResolveMSAAColor(m_RenderGraph, hdCamera, colorBuffer);
}
else if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) &&
hdCamera.volumeStack.GetComponent<PathTracing>().enable.value &&
hdCamera.camera.cameraType != CameraType.Preview)
{
//// We only request the light cluster if we are gonna use it for debug mode
//if (FullScreenDebugMode.LightCluster == m_CurrentDebugDisplaySettings.data.fullScreenDebugMode && GetRayTracingClusterState())
//{
// HDRaytracingLightCluster lightCluster = RequestLightCluster();
// lightCluster.EvaluateClusterDebugView(cmd, hdCamera);
//}
if (hdCamera.viewCount == 1)
{
colorBuffer = RenderPathTracing(m_RenderGraph, hdCamera);
}
else
{
Debug.LogWarning("Path Tracing is not supported with XR single-pass rendering.");
}
}
else
{
gpuLightListOutput = BuildGPULightList(m_RenderGraph, hdCamera, m_TileAndClusterData, m_TotalLightCount, ref m_ShaderVariablesLightListCB, prepassOutput.depthBuffer, prepassOutput.stencilBuffer, prepassOutput.gbuffer);
// Evaluate the history validation buffer that may be required by temporal accumulation based effects
TextureHandle historyValidationTexture = EvaluateHistoryValidationBuffer(m_RenderGraph, hdCamera, prepassOutput.depthBuffer, prepassOutput.resolvedNormalBuffer, prepassOutput.resolvedMotionVectorsBuffer);
lightingBuffers.ambientOcclusionBuffer = m_AmbientOcclusionSystem.Render(m_RenderGraph, hdCamera, prepassOutput.depthPyramidTexture, prepassOutput.resolvedNormalBuffer, prepassOutput.resolvedMotionVectorsBuffer, historyValidationTexture, m_DepthBufferMipChainInfo, m_ShaderVariablesRayTracingCB, rayCountTexture);
// Should probably be inside the AO render function but since it's a separate class it's currently not super clean to do.
PushFullScreenDebugTexture(m_RenderGraph, lightingBuffers.ambientOcclusionBuffer, FullScreenDebugMode.ScreenSpaceAmbientOcclusion);
lightingBuffers.contactShadowsBuffer = RenderContactShadows(m_RenderGraph, hdCamera, msaa ? prepassOutput.depthValuesMSAA : prepassOutput.depthPyramidTexture, gpuLightListOutput, GetDepthBufferMipChainInfo().mipLevelOffsets[1].y);
var volumetricDensityBuffer = VolumeVoxelizationPass(m_RenderGraph, hdCamera, m_VisibleVolumeBoundsBuffer, m_VisibleVolumeDataBuffer, gpuLightListOutput.bigTileLightList);
RenderShadows(m_RenderGraph, hdCamera, cullingResults, ref shadowResult);
StartXRSinglePass(m_RenderGraph, hdCamera);
// Evaluate the clear coat mask texture based on the lit shader mode
var clearCoatMask = hdCamera.frameSettings.litShaderMode == LitShaderMode.Deferred ? prepassOutput.gbuffer.mrt[2] : m_RenderGraph.defaultResources.blackTextureXR;
lightingBuffers.ssrLightingBuffer = RenderSSR(m_RenderGraph,
hdCamera,
ref prepassOutput,
clearCoatMask,
rayCountTexture,
m_SkyManager.GetSkyReflection(hdCamera),
transparent: false);
switch (GetIndirectDiffuseMode(hdCamera))
{
case IndirectDiffuseMode.ScreenSpace:
lightingBuffers.ssgiLightingBuffer = RenderSSGI(m_RenderGraph, hdCamera, prepassOutput.depthPyramidTexture, prepassOutput.stencilBuffer, prepassOutput.normalBuffer, prepassOutput.resolvedMotionVectorsBuffer, m_ShaderVariablesRayTracingCB, GetDepthBufferMipChainInfo());
break;
case IndirectDiffuseMode.Raytrace:
lightingBuffers.ssgiLightingBuffer = RenderRayTracedIndirectDiffuse(m_RenderGraph, hdCamera,
prepassOutput.depthBuffer, prepassOutput.stencilBuffer, prepassOutput.normalBuffer, prepassOutput.resolvedMotionVectorsBuffer, historyValidationTexture,
m_SkyManager.GetSkyReflection(hdCamera), rayCountTexture,
m_ShaderVariablesRayTracingCB);
break;
default:
lightingBuffers.ssgiLightingBuffer = m_RenderGraph.defaultResources.blackTextureXR;
break;
}
PushFullScreenDebugTexture(m_RenderGraph, lightingBuffers.ssgiLightingBuffer, FullScreenDebugMode.ScreenSpaceGlobalIllumination);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && GetRayTracingClusterState())
{
HDRaytracingLightCluster lightCluster = RequestLightCluster();
lightCluster.EvaluateClusterDebugView(m_RenderGraph, hdCamera, prepassOutput.depthBuffer, prepassOutput.depthPyramidTexture);
}
lightingBuffers.screenspaceShadowBuffer = RenderScreenSpaceShadows(m_RenderGraph, hdCamera, prepassOutput, prepassOutput.depthBuffer, prepassOutput.normalBuffer, prepassOutput.motionVectorsBuffer, historyValidationTexture, rayCountTexture);
var maxZMask = GenerateMaxZPass(m_RenderGraph, hdCamera, prepassOutput.depthPyramidTexture, m_DepthBufferMipChainInfo);
var volumetricLighting = VolumetricLightingPass(m_RenderGraph, hdCamera, prepassOutput.depthPyramidTexture, volumetricDensityBuffer, maxZMask, gpuLightListOutput.bigTileLightList, shadowResult);
var deferredLightingOutput = RenderDeferredLighting(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.depthPyramidTexture, lightingBuffers, prepassOutput.gbuffer, shadowResult, gpuLightListOutput);
RenderForwardOpaque(m_RenderGraph, hdCamera, colorBuffer, lightingBuffers, gpuLightListOutput, prepassOutput.depthBuffer, vtFeedbackBuffer, shadowResult, prepassOutput.dbuffer, cullingResults);
// TODO RENDERGRAPH : Move this to the end after we do move semantic and graph culling to avoid doing the rest of the frame for nothing
if (aovRequest.isValid)
aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Normals, hdCamera, prepassOutput.resolvedNormalBuffer, aovBuffers);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.SubsurfaceScattering))
{
lightingBuffers.diffuseLightingBuffer = ResolveMSAAColor(m_RenderGraph, hdCamera, lightingBuffers.diffuseLightingBuffer);
lightingBuffers.sssBuffer = ResolveMSAAColor(m_RenderGraph, hdCamera, lightingBuffers.sssBuffer);
}
// If ray tracing is enabled for the camera, if the volume override is active and if the RAS is built, we want to do ray traced SSS
var settings = hdCamera.volumeStack.GetComponent<SubSurfaceScattering>();
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && settings.rayTracing.value && GetRayTracingState() && hdCamera.frameSettings.IsEnabled(FrameSettingsField.SubsurfaceScattering))
{
colorBuffer = RenderSubsurfaceScatteringRT(m_RenderGraph, hdCamera,
prepassOutput.depthBuffer, prepassOutput.normalBuffer, colorBuffer,
lightingBuffers.sssBuffer, lightingBuffers.diffuseLightingBuffer, prepassOutput.motionVectorsBuffer, historyValidationTexture, lightingBuffers.ssgiLightingBuffer);
}
else
RenderSubsurfaceScattering(m_RenderGraph, hdCamera, colorBuffer, lightingBuffers, ref prepassOutput);
RenderForwardEmissive(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, cullingResults);
RenderSky(m_RenderGraph, hdCamera, colorBuffer, volumetricLighting, prepassOutput.depthBuffer, msaa ? prepassOutput.depthAsColor : prepassOutput.depthPyramidTexture);
// Send all the geometry graphics buffer to client systems if required (must be done after the pyramid and before the transparent depth pre-pass)
SendGeometryGraphicsBuffers(m_RenderGraph, prepassOutput.normalBuffer, prepassOutput.depthPyramidTexture, hdCamera);
m_PostProcessSystem.DoUserAfterOpaqueAndSky(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedDepthBuffer, prepassOutput.resolvedNormalBuffer, prepassOutput.resolvedMotionVectorsBuffer);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects)) // If we don't have opaque objects there is no need to clear.
{
// No need for old stencil values here since from transparent on different features are tagged
ClearStencilBuffer(m_RenderGraph, colorBuffer, prepassOutput.depthBuffer);
}
colorBuffer = RenderTransparency(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedNormalBuffer, vtFeedbackBuffer, currentColorPyramid, volumetricLighting, rayCountTexture, m_SkyManager.GetSkyReflection(hdCamera), gpuLightListOutput, ref prepassOutput, shadowResult, cullingResults, customPassCullingResults, aovRequest, aovCustomPassBuffers);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentsWriteMotionVector))
{
prepassOutput.resolvedMotionVectorsBuffer = ResolveMotionVector(m_RenderGraph, hdCamera, prepassOutput.motionVectorsBuffer);
}
// We push the motion vector debug texture here as transparent object can overwrite the motion vector texture content.
if (m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors)
PushFullScreenDebugTexture(m_RenderGraph, prepassOutput.resolvedMotionVectorsBuffer, FullScreenDebugMode.MotionVectors);
// TODO RENDERGRAPH : Move this to the end after we do move semantic and graph culling to avoid doing the rest of the frame for nothing
// Transparent objects may write to the depth and motion vectors buffers.
if (aovRequest.isValid)
{
aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.DepthStencil, hdCamera, prepassOutput.resolvedDepthBuffer, aovBuffers);
if (m_Asset.currentPlatformRenderPipelineSettings.supportMotionVectors)
aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.MotionVectors, hdCamera, prepassOutput.resolvedMotionVectorsBuffer, aovBuffers);
}
// This final Gaussian pyramid can be reused by SSR, so disable it only if there is no distortion
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.Distortion) && hdCamera.frameSettings.IsEnabled(FrameSettingsField.RoughDistortion))
{
TextureHandle distortionColorPyramid = m_RenderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true)
{
colorFormat = GetColorBufferFormat(),
enableRandomWrite = true,
useMipMap = true,
autoGenerateMips = false,
name = "DistortionColorBufferMipChain"
});
GenerateColorPyramid(m_RenderGraph, hdCamera, colorBuffer, distortionColorPyramid, FullScreenDebugMode.PreRefractionColorPyramid);
currentColorPyramid = distortionColorPyramid;
}
using (new RenderGraphProfilingScope(m_RenderGraph, ProfilingSampler.Get(HDProfileId.Distortion)))
{
var distortionBuffer = AccumulateDistortion(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, cullingResults);
RenderDistortion(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.resolvedDepthBuffer, currentColorPyramid, distortionBuffer);
}
PushFullScreenDebugTexture(m_RenderGraph, colorBuffer, FullScreenDebugMode.NanTracker);
PushFullScreenLightingDebugTexture(m_RenderGraph, colorBuffer);
if (m_SubFrameManager.isRecording && m_SubFrameManager.subFrameCount > 1)
{
RenderAccumulation(m_RenderGraph, hdCamera, colorBuffer, colorBuffer, false);
}
// Render gizmos that should be affected by post processes
RenderGizmos(m_RenderGraph, hdCamera, colorBuffer, GizmoSubset.PreImageEffects);
#if ENABLE_VIRTUALTEXTURES
// Note: This pass rely on availability of vtFeedbackBuffer buffer (i.e it need to be write before we read it here)
// We don't write it when doing debug mode, FullScreenDebug mode or path tracer. Thus why this pass is call here.
hdCamera.ResolveVirtualTextureFeedback(m_RenderGraph, vtFeedbackBuffer);
PushFullScreenVTFeedbackDebugTexture(m_RenderGraph, vtFeedbackBuffer, msaa);
#endif
}
// At this point, the color buffer has been filled by either debug views are regular rendering so we can push it here.
var colorPickerTexture = PushColorPickerDebugTexture(m_RenderGraph, colorBuffer);
RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovCustomPassBuffers);
if (aovRequest.isValid)
{
aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Color, hdCamera, colorBuffer, aovBuffers);
}
TextureHandle postProcessDest = RenderPostProcess(m_RenderGraph, prepassOutput, colorBuffer, backBuffer, cullingResults, hdCamera);
// If requested, compute histogram of the very final image
if (m_CurrentDebugDisplaySettings.data.lightingDebugSettings.exposureDebugMode == ExposureDebugMode.FinalImageHistogramView)
{
GenerateDebugImageHistogram(m_RenderGraph, hdCamera, postProcessDest);
}
PushFullScreenExposureDebugTexture(m_RenderGraph, postProcessDest);
ResetCameraSizeForAfterPostProcess(m_RenderGraph, hdCamera, commandBuffer);
RenderCustomPass(m_RenderGraph, hdCamera, postProcessDest, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.AfterPostProcess, aovRequest, aovCustomPassBuffers);
CopyXRDepth(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, backBuffer);
// In developer build, we always render post process in an intermediate buffer at (0,0) in which we will then render debug.
// Because of this, we need another blit here to the final render target at the right viewport.
if (!HDUtils.PostProcessIsFinalPass(hdCamera) || aovRequest.isValid)
{
hdCamera.ExecuteCaptureActions(m_RenderGraph, postProcessDest);
postProcessDest = RenderDebug(m_RenderGraph,
hdCamera,
postProcessDest,
prepassOutput.resolvedDepthBuffer,
prepassOutput.depthPyramidTexture,
colorPickerTexture,
rayCountTexture,
gpuLightListOutput,
shadowResult,
cullingResults);
StopXRSinglePass(m_RenderGraph, hdCamera);
for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex)
{
BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, viewIndex);
}
if (aovRequest.isValid)
aovRequest.PushCameraTexture(m_RenderGraph, AOVBuffers.Output, hdCamera, postProcessDest, aovBuffers);
}
// This code is only for planar reflections. Given that the depth texture cannot be shared currently with the other depth copy that we do
// we need to do this seperately.
for (int viewIndex = 0; viewIndex < hdCamera.viewCount; ++viewIndex)
{
if (target.targetDepth != null)
{
BlitFinalCameraTexture(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, m_RenderGraph.ImportTexture(target.targetDepth), viewIndex);
}
}
// XR mirror view and blit do device
EndCameraXR(m_RenderGraph, hdCamera);
SendColorGraphicsBuffer(m_RenderGraph, hdCamera);
SetFinalTarget(m_RenderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, backBuffer);
RenderWireOverlay(m_RenderGraph, hdCamera, backBuffer);
RenderGizmos(m_RenderGraph, hdCamera, colorBuffer, GizmoSubset.PostImageEffects);
m_RenderGraph.Execute();
if (aovRequest.isValid)
{
// aovRequest.Execute don't go through render graph for now
using (new ProfilingScope(commandBuffer, ProfilingSampler.Get(HDProfileId.AOVExecute)))
{
aovRequest.Execute(commandBuffer, aovBuffers, aovCustomPassBuffers, RenderOutputProperties.From(hdCamera));
}
}
}
class FinalBlitPassData
{
public BlitFinalCameraTextureParameters parameters;
public TextureHandle source;
public TextureHandle destination;
}
void BlitFinalCameraTexture(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle source, TextureHandle destination, int viewIndex)
{
using (var builder = renderGraph.AddRenderPass<FinalBlitPassData>("Final Blit (Dev Build Only)", out var passData))
{
passData.parameters = PrepareFinalBlitParameters(hdCamera, viewIndex); // todo viewIndex
passData.source = builder.ReadTexture(source);
passData.destination = builder.WriteTexture(destination);
builder.SetRenderFunc(
(FinalBlitPassData data, RenderGraphContext context) =>
{
BlitFinalCameraTexture(data.parameters, context.renderGraphPool.GetTempMaterialPropertyBlock(), data.source, data.destination, context.cmd);
});
}
}
class SetFinalTargetPassData
{
public bool copyDepth;
public Material copyDepthMaterial;
public TextureHandle finalTarget;
public Rect finalViewport;
public TextureHandle depthBuffer;
public bool flipY;
}
void SetFinalTarget(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthBuffer, TextureHandle finalTarget)
{
using (var builder = renderGraph.AddRenderPass<SetFinalTargetPassData>("Set Final Target", out var passData))
{
// Due to our RT handle system we don't write into the backbuffer depth buffer (as our depth buffer can be bigger than the one provided)
// So we need to do a copy of the corresponding part of RT depth buffer in the target depth buffer in various situation:
// - RenderTexture (camera.targetTexture != null) has a depth buffer (camera.targetTexture.depth != 0)
// - We are rendering into the main game view (i.e not a RenderTexture camera.cameraType == CameraType.Game && hdCamera.camera.targetTexture == null) in the editor for allowing usage of Debug.DrawLine and Debug.Ray.
// - We draw Gizmo/Icons in the editor (hdCamera.camera.targetTexture != null && camera.targetTexture.depth != 0 - The Scene view has a targetTexture and a depth texture)
// TODO: If at some point we get proper render target aliasing, we will be able to use the provided depth texture directly with our RT handle system
// Note: Debug.DrawLine and Debug.Ray only work in editor, not in player
passData.copyDepth = hdCamera.camera.targetTexture != null && hdCamera.camera.targetTexture.depth != 0;
#if UNITY_EDITOR
passData.copyDepth = passData.copyDepth || hdCamera.isMainGameView; // Specific case of Debug.DrawLine and Debug.Ray
#endif
passData.copyDepth = passData.copyDepth && !hdCamera.xr.enabled;
passData.finalTarget = builder.WriteTexture(finalTarget);
passData.finalViewport = hdCamera.finalViewport;
if (passData.copyDepth)
{
passData.depthBuffer = builder.ReadTexture(depthBuffer);
passData.flipY = hdCamera.isMainGameView;
passData.copyDepthMaterial = m_CopyDepth;
}
builder.SetRenderFunc(
(SetFinalTargetPassData data, RenderGraphContext ctx) =>
{
// We need to make sure the viewport is correctly set for the editor rendering. It might have been changed by debug overlay rendering just before.
ctx.cmd.SetRenderTarget(data.finalTarget);
ctx.cmd.SetViewport(data.finalViewport);
if (data.copyDepth)
{
using (new ProfilingScope(ctx.cmd, ProfilingSampler.Get(HDProfileId.CopyDepthInTargetTexture)))
{
var mpb = ctx.renderGraphPool.GetTempMaterialPropertyBlock();
mpb.SetTexture(HDShaderIDs._InputDepth, data.depthBuffer);
// When we are Main Game View we need to flip the depth buffer ourselves as we are after postprocess / blit that have already flipped the screen
mpb.SetInt("_FlipY", data.flipY ? 1 : 0);
mpb.SetVector(HDShaderIDs._BlitScaleBias, new Vector4(1.0f, 1.0f, 0.0f, 0.0f));
CoreUtils.DrawFullScreen(ctx.cmd, data.copyDepthMaterial, mpb);
}
}
});
}
}
class CopyXRDepthPassData
{
public Material copyDepth;
public Rect viewport;
public TextureHandle depthBuffer;
public TextureHandle output;
public float dynamicResolutionScale;
}
void CopyXRDepth(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthBuffer, TextureHandle output)
{
// Copy and rescale depth buffer for XR devices
if (hdCamera.xr.enabled && hdCamera.xr.copyDepth)
{
using (var builder = renderGraph.AddRenderPass<CopyXRDepthPassData>("Copy XR Depth", out var passData, ProfilingSampler.Get(HDProfileId.XRDepthCopy)))
{
passData.copyDepth = m_CopyDepth;
passData.viewport = hdCamera.finalViewport;
passData.depthBuffer = builder.ReadTexture(depthBuffer);
passData.output = builder.WriteTexture(output);
passData.dynamicResolutionScale = DynamicResolutionHandler.instance.GetCurrentScale();
builder.SetRenderFunc(
(CopyXRDepthPassData data, RenderGraphContext ctx) =>
{
var mpb = ctx.renderGraphPool.GetTempMaterialPropertyBlock();
RTHandle depthRT = data.depthBuffer;
mpb.SetTexture(HDShaderIDs._InputDepth, data.depthBuffer);
mpb.SetVector(HDShaderIDs._BlitScaleBias, new Vector4(data.dynamicResolutionScale, data.dynamicResolutionScale, 0.0f, 0.0f));
mpb.SetInt("_FlipY", 1);
ctx.cmd.SetRenderTarget(data.output, 0, CubemapFace.Unknown, -1);
ctx.cmd.SetViewport(data.viewport);
CoreUtils.DrawFullScreen(ctx.cmd, data.copyDepth, mpb);
});
}
}
}
class ForwardPassData
{
public RendererListHandle rendererList;
public TextureHandle[] renderTarget = new TextureHandle[RenderGraph.kMaxMRTCount];
public int renderTargetCount;
public TextureHandle depthBuffer;
public ComputeBufferHandle lightListBuffer;
public ComputeBufferHandle perVoxelOffset;
public ComputeBufferHandle perTileLogBaseTweak;
public FrameSettings frameSettings;
}
class ForwardOpaquePassData : ForwardPassData
{
public DBufferOutput dbuffer;
public LightingBuffers lightingBuffers;
}
class ForwardTransparentPassData : ForwardPassData
{
public bool decalsEnabled;
public bool renderMotionVecForTransparent;
public TextureHandle transparentSSRLighting;
public TextureHandle volumetricLighting;
public TextureHandle depthPyramidTexture;
public TextureHandle normalBuffer;
}
void PrepareCommonForwardPassData(RenderGraph renderGraph,
RenderGraphBuilder builder,
ForwardPassData data,
bool opaque,
FrameSettings frameSettings,
RendererListDesc rendererListDesc,
in BuildGPULightListOutput lightLists,
TextureHandle depthBuffer,
ShadowResult shadowResult)
{
bool useFptl = frameSettings.IsEnabled(FrameSettingsField.FPTLForForwardOpaque) && opaque;
data.frameSettings = frameSettings;
data.lightListBuffer = builder.ReadComputeBuffer(useFptl ? lightLists.lightList : lightLists.perVoxelLightLists);
if (!useFptl)
{
data.perVoxelOffset = builder.ReadComputeBuffer(lightLists.perVoxelOffset);
if (lightLists.perTileLogBaseTweak.IsValid())
data.perTileLogBaseTweak = builder.ReadComputeBuffer(lightLists.perTileLogBaseTweak);
}
data.depthBuffer = builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite);
data.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(rendererListDesc));
HDShadowManager.ReadShadowResult(shadowResult, builder);
}
static void BindGlobalLightListBuffers(ForwardPassData data, RenderGraphContext ctx)
{
ctx.cmd.SetGlobalBuffer(HDShaderIDs.g_vLightListGlobal, data.lightListBuffer);
// Next two are only for cluster rendering. PerTileLogBaseTweak is only when using depth buffer so can be invalid as well.
if (data.perVoxelOffset.IsValid())
ctx.cmd.SetGlobalBuffer(HDShaderIDs.g_vLayeredOffsetsBuffer, data.perVoxelOffset);
if (data.perTileLogBaseTweak.IsValid())
ctx.cmd.SetGlobalBuffer(HDShaderIDs.g_logBaseBuffer, data.perTileLogBaseTweak);
}
// Guidelines: In deferred by default there is no opaque in forward. However it is possible to force an opaque material to render in forward
// by using the pass "ForwardOnly". In this case the .shader should not have "Forward" but only a "ForwardOnly" pass.
// It must also have a "DepthForwardOnly" and no "DepthOnly" pass as forward material (either deferred or forward only rendering) have always a depth pass.
// The RenderForward pass will render the appropriate pass depends on the engine settings. In case of forward only rendering, both "Forward" pass and "ForwardOnly" pass
// material will be render for both transparent and opaque. In case of deferred, both path are used for transparent but only "ForwardOnly" is use for opaque.
// (Thus why "Forward" and "ForwardOnly" are exclusive, else they will render two times"
void RenderForwardOpaque(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
in LightingBuffers lightingBuffers,
in BuildGPULightListOutput lightLists,
TextureHandle depthBuffer,
TextureHandle vtFeedbackBuffer,
ShadowResult shadowResult,
DBufferOutput dbuffer,
CullingResults cullResults)
{
bool debugDisplay = m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled();
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
return;
using (var builder = renderGraph.AddRenderPass<ForwardOpaquePassData>(debugDisplay ? "Forward Opaque Debug" : "Forward Opaque",
out var passData,
debugDisplay ? ProfilingSampler.Get(HDProfileId.ForwardOpaqueDebug) : ProfilingSampler.Get(HDProfileId.ForwardOpaque)))
{
PrepareCommonForwardPassData(renderGraph, builder, passData, true, hdCamera.frameSettings, PrepareForwardOpaqueRendererList(cullResults, hdCamera), lightLists, depthBuffer, shadowResult);
// In case of forward SSS we will bind all the required target. It is up to the shader to write into it or not.
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.SubsurfaceScattering))
{
int index = 0;
passData.renderTarget[index++] = builder.WriteTexture(colorBuffer); // Store the specular color
#if ENABLE_VIRTUALTEXTURES
passData.renderTarget[index++] = builder.WriteTexture(vtFeedbackBuffer);
#endif
passData.renderTarget[index++] = builder.WriteTexture(lightingBuffers.diffuseLightingBuffer);
passData.renderTarget[index++] = builder.WriteTexture(lightingBuffers.sssBuffer);
passData.renderTargetCount = index;
}
else
{
int index = 0;
passData.renderTarget[index++] = builder.WriteTexture(colorBuffer);
#if ENABLE_VIRTUALTEXTURES
passData.renderTarget[index++] = builder.WriteTexture(vtFeedbackBuffer);
#endif
passData.renderTargetCount = index;
}
passData.dbuffer = ReadDBuffer(dbuffer, builder);
passData.lightingBuffers = ReadLightingBuffers(lightingBuffers, builder);
builder.SetRenderFunc(
(ForwardOpaquePassData data, RenderGraphContext context) =>
{
// TODO RENDERGRAPH: replace with UseColorBuffer when removing old rendering (SetRenderTarget is called inside RenderForwardRendererList because of that).
var mrt = context.renderGraphPool.GetTempArray<RenderTargetIdentifier>(data.renderTargetCount);
for (int i = 0; i < data.renderTargetCount; ++i)
mrt[i] = data.renderTarget[i];
BindGlobalLightListBuffers(data, context);
BindDBufferGlobalData(data.dbuffer, context);
BindGlobalLightingBuffers(data.lightingBuffers, context.cmd);
RenderForwardRendererList(data.frameSettings, data.rendererList, mrt, data.depthBuffer, data.lightListBuffer, true, context.renderContext, context.cmd);
});
}
}
void RenderForwardTransparent(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle normalBuffer,
in PrepassOutput prepassOutput,
TextureHandle vtFeedbackBuffer,
TextureHandle volumetricLighting,
TextureHandle ssrLighting,
TextureHandle? colorPyramid,
in BuildGPULightListOutput lightLists,
in ShadowResult shadowResult,
CullingResults cullResults,
bool preRefractionPass)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentObjects))
return;
// If rough refraction are turned off, we render all transparents in the Transparent pass and we skip the PreRefraction one.
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.Refraction) && preRefractionPass)
return;
string passName;
HDProfileId profilingId;
bool debugDisplay = m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled();
if (debugDisplay)
{
passName = preRefractionPass ? "Forward PreRefraction Debug" : "Forward Transparent Debug";
profilingId = preRefractionPass ? HDProfileId.ForwardPreRefractionDebug : HDProfileId.ForwardTransparentDebug;
}
else
{
passName = preRefractionPass ? "Forward PreRefraction" : "Forward Transparent";
profilingId = preRefractionPass ? HDProfileId.ForwardPreRefraction : HDProfileId.ForwardTransparent;
}
using (var builder = renderGraph.AddRenderPass<ForwardTransparentPassData>(passName, out var passData, ProfilingSampler.Get(profilingId)))
{
PrepareCommonForwardPassData(renderGraph, builder, passData, false, hdCamera.frameSettings, PrepareForwardTransparentRendererList(cullResults, hdCamera, preRefractionPass), lightLists, prepassOutput.depthBuffer, shadowResult);
// enable d-buffer flag value is being interpreted more like enable decals in general now that we have clustered
// decal datas count is 0 if no decals affect transparency
passData.decalsEnabled = (hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals)) && (DecalSystem.m_DecalDatasCount > 0);
passData.renderMotionVecForTransparent = NeedMotionVectorForTransparent(hdCamera.frameSettings);
passData.volumetricLighting = builder.ReadTexture(volumetricLighting);
passData.transparentSSRLighting = builder.ReadTexture(ssrLighting);
passData.depthPyramidTexture = builder.ReadTexture(prepassOutput.depthPyramidTexture); // We need to bind this for transparent materials doing stuff like soft particles etc.
int index = 0;
passData.renderTarget[index++] = builder.WriteTexture(colorBuffer);
#if ENABLE_VIRTUALTEXTURES
passData.renderTarget[index++] = builder.WriteTexture(vtFeedbackBuffer);
#endif
if (passData.renderMotionVecForTransparent)
{
passData.renderTarget[index++] = builder.WriteTexture(prepassOutput.motionVectorsBuffer);
}
else
{
bool msaa = hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA);
// It doesn't really matter what gets bound here since the color mask state set will prevent this from ever being written to. However, we still need to bind something
// to avoid warnings about unbound render targets. The following rendertarget could really be anything if renderVelocitiesForTransparent
// Create a new target here should reuse existing already released one
passData.renderTarget[index++] = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R8G8B8A8_SRGB, bindTextureMS = msaa, enableMSAA = msaa, name = "Transparency Velocity Dummy" });
}
passData.renderTargetCount = index;
if (colorPyramid != null && hdCamera.frameSettings.IsEnabled(FrameSettingsField.Refraction) && !preRefractionPass)
{
builder.ReadTexture(colorPyramid.Value);
}
// TODO RENDERGRAPH
// Since in the old code path we bound this as global, it was available here so we need to bind it as well in order not to break existing projects...
// This is not good because it will extend its lifetime even when it's not actually used by a shader (we can't have that info).
// TODO: Make this explicit?
passData.normalBuffer = builder.ReadTexture(normalBuffer);
builder.SetRenderFunc(
(ForwardTransparentPassData data, RenderGraphContext context) =>
{
// TODO: replace with UseColorBuffer when removing old rendering.
var mrt = context.renderGraphPool.GetTempArray<RenderTargetIdentifier>(data.renderTargetCount);
for (int i = 0; i < data.renderTargetCount; ++i)
mrt[i] = data.renderTarget[i];
// Bind all global data/parameters for transparent forward pass
context.cmd.SetGlobalInt(HDShaderIDs._ColorMaskTransparentVel, data.renderMotionVecForTransparent ? (int)ColorWriteMask.All : 0);
if (data.decalsEnabled)
DecalSystem.instance.SetAtlas(context.cmd); // for clustered decals
BindGlobalLightListBuffers(data, context);
context.cmd.SetGlobalTexture(HDShaderIDs._SsrLightingTexture, data.transparentSSRLighting);
context.cmd.SetGlobalTexture(HDShaderIDs._VBufferLighting, data.volumetricLighting);
context.cmd.SetGlobalTexture(HDShaderIDs._CameraDepthTexture, data.depthPyramidTexture);
context.cmd.SetGlobalTexture(HDShaderIDs._NormalBufferTexture, data.normalBuffer);
RenderForwardRendererList(data.frameSettings, data.rendererList, mrt, data.depthBuffer, data.lightListBuffer, false, context.renderContext, context.cmd);
});
}
}
void RenderTransparentDepthPrepass(RenderGraph renderGraph, HDCamera hdCamera, in PrepassOutput prepassOutput, CullingResults cull)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentPrepass))
return;
using (var builder = renderGraph.AddRenderPass<ForwardPassData>("Transparent Depth Prepass", out var passData, ProfilingSampler.Get(HDProfileId.TransparentDepthPrepass)))
{
passData.frameSettings = hdCamera.frameSettings;
if (hdCamera.IsSSREnabled(transparent: true))
BindPrepassColorBuffers(builder, prepassOutput, hdCamera);
builder.UseDepthBuffer(prepassOutput.depthBuffer, DepthAccess.ReadWrite);
passData.renderTargetCount = 0;
passData.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cull, hdCamera.camera, m_TransparentDepthPrepassNames)));
builder.SetRenderFunc(
(ForwardPassData data, RenderGraphContext context) =>
{
DrawTransparentRendererList(context.renderContext, context.cmd, data.frameSettings, data.rendererList);
});
}
}
void RenderTransparentDepthPostpass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthStencilBuffer, CullingResults cull)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentPostpass))
return;
using (var builder = renderGraph.AddRenderPass<ForwardPassData>("Transparent Depth Postpass", out var passData, ProfilingSampler.Get(HDProfileId.TransparentDepthPostpass)))
{
passData.frameSettings = hdCamera.frameSettings;
passData.depthBuffer = builder.UseDepthBuffer(depthStencilBuffer, DepthAccess.ReadWrite);
passData.renderTargetCount = 0;
passData.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cull, hdCamera.camera, m_TransparentDepthPostpassNames)));
builder.SetRenderFunc(
(ForwardPassData data, RenderGraphContext context) =>
{
DrawTransparentRendererList(context.renderContext, context.cmd, data.frameSettings, data.rendererList);
});
}
}
class RenderLowResTransparentPassData
{
public ShaderVariablesGlobal globalCB;
public FrameSettings frameSettings;
public RendererListHandle rendererList;
public TextureHandle lowResBuffer;
public TextureHandle downsampledDepthBuffer;
}
TextureHandle RenderLowResTransparent(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle downsampledDepth, CullingResults cullingResults)
{
using (var builder = renderGraph.AddRenderPass<RenderLowResTransparentPassData>("Low Res Transparent", out var passData, ProfilingSampler.Get(HDProfileId.LowResTransparent)))
{
var passNames = m_Asset.currentPlatformRenderPipelineSettings.supportTransparentBackface ? m_AllTransparentPassNames : m_TransparentNoBackfaceNames;
passData.globalCB = m_ShaderVariablesGlobalCB;
passData.frameSettings = hdCamera.frameSettings;
passData.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cullingResults, hdCamera.camera, passNames, m_CurrentRendererConfigurationBakedLighting, HDRenderQueue.k_RenderQueue_LowTransparent)));
passData.downsampledDepthBuffer = builder.UseDepthBuffer(downsampledDepth, DepthAccess.ReadWrite);
// We need R16G16B16A16_SFloat as we need a proper alpha channel for compositing.
passData.lowResBuffer = builder.UseColorBuffer(renderGraph.CreateTexture(new TextureDesc(Vector2.one * 0.5f, true, true)
{ colorFormat = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, clearBuffer = true, clearColor = Color.black, name = "Low res transparent" }), 0);
builder.SetRenderFunc(
(RenderLowResTransparentPassData data, RenderGraphContext context) =>
{
UpdateOffscreenRenderingConstants(ref data.globalCB, true, 2u);
ConstantBuffer.PushGlobal(context.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal);
DrawTransparentRendererList(context.renderContext, context.cmd, data.frameSettings, data.rendererList);
UpdateOffscreenRenderingConstants(ref data.globalCB, false, 1u);
ConstantBuffer.PushGlobal(context.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal);
});
return passData.lowResBuffer;
}
}
class UpsampleTransparentPassData
{
public Material upsampleMaterial;
public TextureHandle colorBuffer;
public TextureHandle lowResTransparentBuffer;
public TextureHandle downsampledDepthBuffer;
}
void UpsampleTransparent(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle lowResTransparentBuffer, TextureHandle downsampledDepthBuffer)
{
using (var builder = renderGraph.AddRenderPass<UpsampleTransparentPassData>("Upsample Low Res Transparency", out var passData, ProfilingSampler.Get(HDProfileId.UpsampleLowResTransparent)))
{
var settings = m_Asset.currentPlatformRenderPipelineSettings.lowresTransparentSettings;
if (settings.upsampleType == LowResTransparentUpsample.Bilinear)
{
m_UpsampleTransparency.EnableKeyword("BILINEAR");
}
else if (settings.upsampleType == LowResTransparentUpsample.NearestDepth)
{
m_UpsampleTransparency.EnableKeyword("NEAREST_DEPTH");
}
passData.upsampleMaterial = m_UpsampleTransparency;
passData.colorBuffer = builder.UseColorBuffer(colorBuffer, 0);
passData.lowResTransparentBuffer = builder.ReadTexture(lowResTransparentBuffer);
passData.downsampledDepthBuffer = builder.ReadTexture(downsampledDepthBuffer);
builder.SetRenderFunc(
(UpsampleTransparentPassData data, RenderGraphContext context) =>
{
data.upsampleMaterial.SetTexture(HDShaderIDs._LowResTransparent, data.lowResTransparentBuffer);
data.upsampleMaterial.SetTexture(HDShaderIDs._LowResDepthTexture, data.downsampledDepthBuffer);
context.cmd.DrawProcedural(Matrix4x4.identity, data.upsampleMaterial, 0, MeshTopology.Triangles, 3, 1, null);
});
}
}
class SetGlobalColorPassData
{
public TextureHandle colorBuffer;
}
void SetGlobalColorForCustomPass(RenderGraph renderGraph, TextureHandle colorBuffer)
{
using (var builder = renderGraph.AddRenderPass<SetGlobalColorPassData>("SetGlobalColorForCustomPass", out var passData))
{
passData.colorBuffer = builder.ReadTexture(colorBuffer);
builder.SetRenderFunc((SetGlobalColorPassData data, RenderGraphContext context) =>
{
RTHandle colorPyramid = data.colorBuffer;
if (colorPyramid != null)
context.cmd.SetGlobalTexture(HDShaderIDs._ColorPyramidTexture, data.colorBuffer);
});
}
}
class RecursiveRenderingPrepassPassData
{
public FrameSettings frameSettings;
public TextureHandle depthBuffer;
public TextureHandle flagMask;
public RendererListHandle opaqueRenderList;
public RendererListHandle transparentRenderList;
public bool clear;
}
void RenderRayTracingPrepass(RenderGraph renderGraph, CullingResults cull, HDCamera hdCamera, TextureHandle flagMask, TextureHandle depthBuffer, bool clear)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing))
return;
RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent<RecursiveRendering>();
if (!recursiveSettings.enable.value)
return;
using (var builder = renderGraph.AddRenderPass<RecursiveRenderingPrepassPassData>("Recursive Rendering Prepass", out var passData, ProfilingSampler.Get(HDProfileId.RayTracingPrepass)))
{
passData.frameSettings = hdCamera.frameSettings;
passData.depthBuffer = clear ? builder.UseDepthBuffer(depthBuffer, DepthAccess.Read) : builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite);
passData.flagMask = builder.WriteTexture(flagMask);
passData.clear = clear;
// when clear is required, it mean we are before the recursive rendering call, otherwise it mean we are before the depth prepass
// As the pass before depth prepass write depth, we don't need to write it again during the second one, also the buffer is only clear at this time
// TODO: evaluate the usage of a stencil bit in the stencil buffer to save a rendertarget (But it require various headaches to work correctly).
if (clear)
{
passData.opaqueRenderList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateOpaqueRendererListDesc(cull, hdCamera.camera, m_RayTracingPrepassNames, stateBlock: m_DepthStateNoWrite)));
passData.transparentRenderList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cull, hdCamera.camera, m_RayTracingPrepassNames, renderQueueRange: HDRenderQueue.k_RenderQueue_AllTransparentWithLowRes, stateBlock: m_DepthStateNoWrite)));
}
else
{
passData.opaqueRenderList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateOpaqueRendererListDesc(cull, hdCamera.camera, m_RayTracingPrepassNames)));
passData.transparentRenderList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cull, hdCamera.camera, m_RayTracingPrepassNames)));
}
builder.SetRenderFunc(
(RecursiveRenderingPrepassPassData data, RenderGraphContext context) =>
{
if (data.clear)
CoreUtils.SetRenderTarget(context.cmd, data.flagMask, data.depthBuffer, clearFlag: ClearFlag.Color, Color.black);
else
CoreUtils.SetRenderTarget(context.cmd, data.flagMask, data.depthBuffer);
DrawOpaqueRendererList(context.renderContext, context.cmd, data.frameSettings, data.opaqueRenderList);
DrawTransparentRendererList(context.renderContext, context.cmd, data.frameSettings, data.transparentRenderList);
});
}
}
TextureHandle RenderTransparency(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle normalBuffer,
TextureHandle vtFeedbackBuffer,
TextureHandle currentColorPyramid,
TextureHandle volumetricLighting,
TextureHandle rayCountTexture,
Texture skyTexture,
in BuildGPULightListOutput lightLists,
ref PrepassOutput prepassOutput,
ShadowResult shadowResult,
CullingResults cullingResults,
CullingResults customPassCullingResults,
AOVRequestData aovRequest,
List<RTHandle> aovCustomPassBuffers)
{
// Transparent (non recursive) objects that are rendered in front of transparent (recursive) require the recursive rendering to be executed for that pixel.
// This means our flagging process needs to happen before the transparent depth prepass as we use the depth to discriminate pixels that do not need recursive rendering.
RenderRayTracingPrepass(renderGraph, cullingResults, hdCamera, prepassOutput.flagMaskBuffer, prepassOutput.depthBuffer, true);
RenderTransparentDepthPrepass(renderGraph, hdCamera, prepassOutput, cullingResults);
var ssrLightingBuffer = RenderSSR(renderGraph, hdCamera, ref prepassOutput, renderGraph.defaultResources.blackTextureXR, rayCountTexture, skyTexture, transparent: true);
colorBuffer = RaytracingRecursiveRender(renderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.flagMaskBuffer, rayCountTexture);
// TODO RENDERGRAPH: Remove this when we properly convert custom passes to full render graph with explicit color buffer reads.
// To allow users to fetch the current color buffer, we temporarily bind the camera color buffer
SetGlobalColorForCustomPass(renderGraph, colorBuffer);
RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.BeforePreRefraction, aovRequest, aovCustomPassBuffers);
SetGlobalColorForCustomPass(renderGraph, currentColorPyramid);
// Render pre-refraction objects
RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, normalBuffer, prepassOutput, vtFeedbackBuffer, volumetricLighting, ssrLightingBuffer, null, lightLists, shadowResult, cullingResults, true);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.Refraction) || hdCamera.IsSSREnabled())
{
var resolvedColorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer);
GenerateColorPyramid(renderGraph, hdCamera, resolvedColorBuffer, currentColorPyramid, FullScreenDebugMode.FinalColorPyramid);
}
// We don't have access to the color pyramid with transparent if rough refraction is disabled
RenderCustomPass(m_RenderGraph, hdCamera, colorBuffer, prepassOutput, customPassCullingResults, cullingResults, CustomPassInjectionPoint.BeforeTransparent, aovRequest, aovCustomPassBuffers);
// Render all type of transparent forward (unlit, lit, complex (hair...)) to keep the sorting between transparent objects.
RenderForwardTransparent(renderGraph, hdCamera, colorBuffer, normalBuffer, prepassOutput, vtFeedbackBuffer, volumetricLighting, ssrLightingBuffer, currentColorPyramid, lightLists, shadowResult, cullingResults, false);
colorBuffer = ResolveMSAAColor(renderGraph, hdCamera, colorBuffer, m_NonMSAAColorBuffer);
// Render All forward error
RenderForwardError(renderGraph, hdCamera, colorBuffer, prepassOutput.resolvedDepthBuffer, cullingResults);
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.LowResTransparent))
{
var lowResTransparentBuffer = RenderLowResTransparent(renderGraph, hdCamera, prepassOutput.downsampledDepthBuffer, cullingResults);
UpsampleTransparent(renderGraph, hdCamera, colorBuffer, lowResTransparentBuffer, prepassOutput.downsampledDepthBuffer);
}
// Fill depth buffer to reduce artifact for transparent object during postprocess
RenderTransparentDepthPostpass(renderGraph, hdCamera, prepassOutput.resolvedDepthBuffer, cullingResults);
return colorBuffer;
}
class RenderForwardEmissivePassData
{
public bool enableDecals;
public RendererListHandle rendererList;
}
void RenderForwardEmissive(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle depthStencilBuffer,
CullingResults cullingResults)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentObjects) &&
!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
{
return;
}
using (var builder = renderGraph.AddRenderPass<RenderForwardEmissivePassData>("ForwardEmissive", out var passData, ProfilingSampler.Get(HDProfileId.ForwardEmissive)))
{
builder.UseColorBuffer(colorBuffer, 0);
builder.UseDepthBuffer(depthStencilBuffer, DepthAccess.ReadWrite);
passData.enableDecals = hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals);
passData.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(PrepareForwardEmissiveRendererList(cullingResults, hdCamera)));
builder.SetRenderFunc(
(RenderForwardEmissivePassData data, RenderGraphContext context) =>
{
CoreUtils.DrawRendererList(context.renderContext, context.cmd, data.rendererList);
if (data.enableDecals)
DecalSystem.instance.RenderForwardEmissive(context.cmd);
});
}
}
// This is use to Display legacy shader with an error shader
[System.Diagnostics.Conditional("DEVELOPMENT_BUILD"), System.Diagnostics.Conditional("UNITY_EDITOR")]
void RenderForwardError(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle depthStencilBuffer,
CullingResults cullResults)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.TransparentObjects) &&
!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
{
return;
}
using (var builder = renderGraph.AddRenderPass<ForwardPassData>("Forward Error", out var passData, ProfilingSampler.Get(HDProfileId.RenderForwardError)))
{
builder.UseColorBuffer(colorBuffer, 0);
builder.UseDepthBuffer(depthStencilBuffer, DepthAccess.ReadWrite);
passData.rendererList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateOpaqueRendererListDesc(cullResults, hdCamera.camera, m_ForwardErrorPassNames, renderQueueRange: RenderQueueRange.all, overrideMaterial: m_ErrorMaterial)));
builder.SetRenderFunc(
(ForwardPassData data, RenderGraphContext context) =>
{
CoreUtils.DrawRendererList(context.renderContext, context.cmd, data.rendererList);
});
}
}
class SendGeometryBuffersPassData
{
public SendGeometryGraphcisBuffersParameters parameters;
public TextureHandle normalBuffer;
public TextureHandle depthBuffer;
}
void SendGeometryGraphicsBuffers(RenderGraph renderGraph, TextureHandle normalBuffer, TextureHandle depthBuffer, HDCamera hdCamera)
{
var parameters = PrepareSendGeometryBuffersParameters(hdCamera, m_DepthBufferMipChainInfo);
if (!parameters.NeedSendBuffers())
return;
using (var builder = renderGraph.AddRenderPass<SendGeometryBuffersPassData>("Send Geometry Buffers", out var passData))
{
builder.AllowPassCulling(false);
passData.parameters = parameters;
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
{
passData.normalBuffer = renderGraph.defaultResources.blackTextureXR;
passData.depthBuffer = renderGraph.defaultResources.blackTextureXR;
}
else
{
passData.normalBuffer = builder.ReadTexture(normalBuffer);
passData.depthBuffer = builder.ReadTexture(depthBuffer);
}
builder.SetRenderFunc(
(SendGeometryBuffersPassData data, RenderGraphContext ctx) =>
{
SendGeometryGraphicsBuffers(data.parameters, data.normalBuffer, data.depthBuffer, ctx.cmd);
});
}
}
class SendColorGraphicsBufferPassData
{
public HDCamera hdCamera;
}
void SendColorGraphicsBuffer(RenderGraph renderGraph, HDCamera hdCamera)
{
using (var builder = renderGraph.AddRenderPass<SendColorGraphicsBufferPassData>("Send Color Buffers", out var passData))
{
builder.AllowPassCulling(false);
passData.hdCamera = hdCamera;
builder.SetRenderFunc(
(SendColorGraphicsBufferPassData data, RenderGraphContext ctx) =>
{
SendColorGraphicsBuffer(ctx.cmd, data.hdCamera);
});
}
}
class ClearStencilPassData
{
public Material clearStencilMaterial;
public TextureHandle colorBuffer;
public TextureHandle depthBuffer;
}
void ClearStencilBuffer(RenderGraph renderGraph, TextureHandle colorBuffer, TextureHandle depthBuffer)
{
using (var builder = renderGraph.AddRenderPass<ClearStencilPassData>("Clear Stencil Buffer", out var passData, ProfilingSampler.Get(HDProfileId.ClearStencil)))
{
passData.clearStencilMaterial = m_ClearStencilBufferMaterial;
passData.colorBuffer = builder.ReadTexture(colorBuffer);
passData.depthBuffer = builder.WriteTexture(depthBuffer);
builder.SetRenderFunc(
(ClearStencilPassData data, RenderGraphContext ctx) =>
{
data.clearStencilMaterial.SetInt(HDShaderIDs._StencilMask, (int)StencilUsage.HDRPReservedBits);
HDUtils.DrawFullScreen(ctx.cmd, data.clearStencilMaterial, data.colorBuffer, data.depthBuffer);
});
}
}
class PreRenderSkyPassData
{
public Light sunLight;
public HDCamera hdCamera;
public TextureHandle colorBuffer;
public TextureHandle depthStencilBuffer;
public TextureHandle normalBuffer;
public DebugDisplaySettings debugDisplaySettings;
public SkyManager skyManager;
}
void PreRenderSky(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle depthStencilBuffer, TextureHandle normalbuffer)
{
if (m_CurrentDebugDisplaySettings.DebugHideSky(hdCamera) ||
!m_SkyManager.RequiresPreRenderSky(hdCamera))
{
return;
}
using (var builder = renderGraph.AddRenderPass<PreRenderSkyPassData>("Pre Render Sky", out var passData))
{
passData.sunLight = GetCurrentSunLight();
passData.hdCamera = hdCamera;
passData.colorBuffer = builder.WriteTexture(colorBuffer);
passData.depthStencilBuffer = builder.WriteTexture(depthStencilBuffer);
passData.normalBuffer = builder.WriteTexture(normalbuffer);
passData.debugDisplaySettings = m_CurrentDebugDisplaySettings;
passData.skyManager = m_SkyManager;
builder.SetRenderFunc(
(PreRenderSkyPassData data, RenderGraphContext context) =>
{
data.skyManager.PreRenderSky(data.hdCamera, data.sunLight, data.colorBuffer, data.normalBuffer, data.depthStencilBuffer, data.debugDisplaySettings, context.cmd);
});
}
}
class RenderSkyPassData
{
public VisualEnvironment visualEnvironment;
public Light sunLight;
public HDCamera hdCamera;
public TextureHandle volumetricLighting;
public TextureHandle colorBuffer;
public TextureHandle depthTexture;
public TextureHandle depthStencilBuffer;
public TextureHandle intermediateBuffer;
public DebugDisplaySettings debugDisplaySettings;
public SkyManager skyManager;
}
void RenderSky(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle volumetricLighting, TextureHandle depthStencilBuffer, TextureHandle depthTexture)
{
if (m_CurrentDebugDisplaySettings.DebugHideSky(hdCamera))
{
return;
}
using (var builder = renderGraph.AddRenderPass<RenderSkyPassData>("Render Sky And Fog", out var passData))
{
passData.visualEnvironment = hdCamera.volumeStack.GetComponent<VisualEnvironment>();
passData.sunLight = GetCurrentSunLight();
passData.hdCamera = hdCamera;
passData.volumetricLighting = builder.ReadTexture(volumetricLighting);
passData.colorBuffer = builder.WriteTexture(colorBuffer);
passData.depthTexture = builder.WriteTexture(depthTexture);
passData.depthStencilBuffer = builder.WriteTexture(depthStencilBuffer);
passData.intermediateBuffer = builder.CreateTransientTexture(colorBuffer);
passData.debugDisplaySettings = m_CurrentDebugDisplaySettings;
passData.skyManager = m_SkyManager;
builder.SetRenderFunc(
(RenderSkyPassData data, RenderGraphContext context) =>
{
// Necessary to perform dual-source (polychromatic alpha) blending which is not supported by Unity.
// We load from the color buffer, perform blending manually, and store to the atmospheric scattering buffer.
// Then we perform a copy from the atmospheric scattering buffer back to the color buffer.
data.skyManager.RenderSky(data.hdCamera, data.sunLight, data.colorBuffer, data.depthStencilBuffer, data.debugDisplaySettings, context.cmd);
if (Fog.IsFogEnabled(data.hdCamera) || Fog.IsPBRFogEnabled(data.hdCamera))
{
var pixelCoordToViewDirWS = data.hdCamera.mainViewConstants.pixelCoordToViewDirWS;
data.skyManager.RenderOpaqueAtmosphericScattering(context.cmd, data.hdCamera, data.colorBuffer, data.depthTexture, data.volumetricLighting, data.intermediateBuffer, data.depthStencilBuffer, pixelCoordToViewDirWS, data.hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA));
}
});
}
}
class GenerateColorPyramidData
{
public TextureHandle colorPyramid;
public TextureHandle inputColor;
public MipGenerator mipGenerator;
public HDCamera hdCamera;
}
void GenerateColorPyramid(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle inputColor, TextureHandle output, FullScreenDebugMode fsDebugMode)
{
using (var builder = renderGraph.AddRenderPass<GenerateColorPyramidData>("Color Gaussian MIP Chain", out var passData, ProfilingSampler.Get(HDProfileId.ColorPyramid)))
{
passData.colorPyramid = builder.WriteTexture(output);
passData.inputColor = builder.ReadTexture(inputColor);
passData.hdCamera = hdCamera;
passData.mipGenerator = m_MipGenerator;
builder.SetRenderFunc(
(GenerateColorPyramidData data, RenderGraphContext context) =>
{
Vector2Int pyramidSize = new Vector2Int(data.hdCamera.actualWidth, data.hdCamera.actualHeight);
data.hdCamera.colorPyramidHistoryMipCount = data.mipGenerator.RenderColorGaussianPyramid(context.cmd, pyramidSize, data.inputColor, data.colorPyramid);
// TODO RENDERGRAPH: We'd like to avoid SetGlobals like this but it's required by custom passes currently.
// We will probably be able to remove those once we push custom passes fully to render graph.
context.cmd.SetGlobalTexture(HDShaderIDs._ColorPyramidTexture, data.colorPyramid);
});
}
// Note: hdCamera.colorPyramidHistoryMipCount is going to be one frame late here (rendering, which is done later, is updating it)
// In practice this should not be a big problem as it's only for debug purpose here.
var scale = new Vector4(RTHandles.rtHandleProperties.rtHandleScale.x, RTHandles.rtHandleProperties.rtHandleScale.y, 0f, 0f);
PushFullScreenDebugTextureMip(renderGraph, output, hdCamera.colorPyramidHistoryMipCount, scale, fsDebugMode);
}
class AccumulateDistortionPassData
{
public TextureHandle distortionBuffer;
public TextureHandle depthStencilBuffer;
public RendererListHandle distortionRendererList;
public FrameSettings frameSettings;
}
TextureHandle AccumulateDistortion(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle depthStencilBuffer,
CullingResults cullResults)
{
using (var builder = renderGraph.AddRenderPass<AccumulateDistortionPassData>("Accumulate Distortion", out var passData, ProfilingSampler.Get(HDProfileId.AccumulateDistortion)))
{
passData.frameSettings = hdCamera.frameSettings;
passData.distortionBuffer = builder.UseColorBuffer(renderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true) { colorFormat = Builtin.GetDistortionBufferFormat(), clearBuffer = true, clearColor = Color.clear, name = "Distortion" }), 0);
passData.depthStencilBuffer = builder.UseDepthBuffer(depthStencilBuffer, DepthAccess.Read);
passData.distortionRendererList = builder.UseRendererList(renderGraph.CreateRendererList(
CreateTransparentRendererListDesc(cullResults, hdCamera.camera, HDShaderPassNames.s_DistortionVectorsName)));
builder.SetRenderFunc(
(AccumulateDistortionPassData data, RenderGraphContext context) =>
{
DrawTransparentRendererList(context.renderContext, context.cmd, data.frameSettings, data.distortionRendererList);
});
return passData.distortionBuffer;
}
}
class RenderDistortionPassData
{
public Material applyDistortionMaterial;
public TextureHandle sourceColorBuffer;
public TextureHandle distortionBuffer;
public TextureHandle colorBuffer;
public TextureHandle depthStencilBuffer;
public Vector4 size;
public bool roughDistortion;
}
void RenderDistortion(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle depthStencilBuffer,
TextureHandle colorPyramidBuffer,
TextureHandle distortionBuffer)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.Distortion))
return;
using (var builder = renderGraph.AddRenderPass<RenderDistortionPassData>("Apply Distortion", out var passData, ProfilingSampler.Get(HDProfileId.ApplyDistortion)))
{
passData.applyDistortionMaterial = m_ApplyDistortionMaterial;
passData.roughDistortion = hdCamera.frameSettings.IsEnabled(FrameSettingsField.RoughDistortion);
passData.sourceColorBuffer = passData.roughDistortion ? builder.ReadTexture(colorPyramidBuffer) : builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GetColorBufferFormat(), name = "DistortionIntermediateBuffer" });
passData.distortionBuffer = builder.ReadTexture(distortionBuffer);
passData.colorBuffer = builder.UseColorBuffer(colorBuffer, 0);
passData.depthStencilBuffer = builder.UseDepthBuffer(depthStencilBuffer, DepthAccess.Read);
passData.size = new Vector4(hdCamera.actualWidth, hdCamera.actualHeight, 1f / hdCamera.actualWidth, 1f / hdCamera.actualHeight);
builder.SetRenderFunc(
(RenderDistortionPassData data, RenderGraphContext context) =>
{
if (!data.roughDistortion)
HDUtils.BlitCameraTexture(context.cmd, data.colorBuffer, data.sourceColorBuffer);
// TODO: Set stencil stuff via parameters rather than hard-coding it in shader.
data.applyDistortionMaterial.SetTexture(HDShaderIDs._DistortionTexture, data.distortionBuffer);
data.applyDistortionMaterial.SetTexture(HDShaderIDs._ColorPyramidTexture, data.sourceColorBuffer);
data.applyDistortionMaterial.SetVector(HDShaderIDs._Size, data.size);
data.applyDistortionMaterial.SetInt(HDShaderIDs._StencilMask, (int)StencilUsage.DistortionVectors);
data.applyDistortionMaterial.SetInt(HDShaderIDs._StencilRef, (int)StencilUsage.DistortionVectors);
data.applyDistortionMaterial.SetInt(HDShaderIDs._RoughDistortion, data.roughDistortion ? 1 : 0);
HDUtils.DrawFullScreen(context.cmd, data.applyDistortionMaterial, data.colorBuffer, data.depthStencilBuffer, null, 0);
});
}
}
TextureHandle CreateColorBuffer(RenderGraph renderGraph, HDCamera hdCamera, bool msaa)
{
#if UNITY_2020_2_OR_NEWER
FastMemoryDesc colorFastMemDesc;
colorFastMemDesc.inFastMemory = true;
colorFastMemDesc.residencyFraction = 1.0f;
colorFastMemDesc.flags = FastMemoryFlags.SpillTop;
#endif
return renderGraph.CreateTexture(
new TextureDesc(Vector2.one, true, true)
{
colorFormat = GetColorBufferFormat(),
enableRandomWrite = !msaa,
bindTextureMS = msaa,
enableMSAA = msaa,
clearBuffer = NeedClearColorBuffer(hdCamera),
clearColor = GetColorBufferClearColor(hdCamera),
name = msaa ? "CameraColorMSAA" : "CameraColor"
#if UNITY_2020_2_OR_NEWER
, fastMemoryDesc = colorFastMemDesc
#endif
});
}
class ResolveColorData
{
public TextureHandle input;
public TextureHandle output;
public Material resolveMaterial;
public int passIndex;
}
TextureHandle ResolveMSAAColor(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input)
{
var outputDesc = renderGraph.GetTextureDesc(input);
outputDesc.enableMSAA = false;
outputDesc.enableRandomWrite = true;
outputDesc.bindTextureMS = false;
// Can't do that because there is NO way to concatenate strings without allocating.
// We're stuck with subpar debug name in the meantime...
//outputDesc.name = string.Format("{0}Resolved", outputDesc.name);
var output = renderGraph.CreateTexture(outputDesc);
return ResolveMSAAColor(renderGraph, hdCamera, input, output);
}
// TODO RENDERGRAPH:
// In theory we should never need to specify the output. The function can create the output texture on its own (see function above).
// This way when doing an msaa resolve, we can return the right texture regardless of msaa being enabled or not (either the new texture or the input directly).
// This allows client code to not have to worry about managing the texture at all.
// Now, because Custom Passes allow to do an MSAA resolve for the main color buffer but are implemented outside of render graph, we need an explicit msaa/nonMsaa separation for the main color buffer.
// Having this function here allows us to do that by having the main color non msaa texture created outside and passed to both ResolveMSAAColor and the custom passes.
// When Custom Pass correctly use render graph we'll be able to remove that.
TextureHandle ResolveMSAAColor(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input, TextureHandle output)
{
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA))
{
using (var builder = renderGraph.AddRenderPass<ResolveColorData>("ResolveColor", out var passData))
{
passData.input = builder.ReadTexture(input);
passData.output = builder.UseColorBuffer(output, 0);
passData.resolveMaterial = m_ColorResolveMaterial;
passData.passIndex = SampleCountToPassIndex(m_MSAASamples);
builder.SetRenderFunc(
(ResolveColorData data, RenderGraphContext context) =>
{
var mpb = context.renderGraphPool.GetTempMaterialPropertyBlock();
mpb.SetTexture(HDShaderIDs._ColorTextureMS, data.input);
context.cmd.DrawProcedural(Matrix4x4.identity, data.resolveMaterial, data.passIndex, MeshTopology.Triangles, 3, 1, mpb);
});
return passData.output;
}
}
else
{
return input;
}
}
class ResolveMotionVectorData
{
public TextureHandle input;
public TextureHandle output;
public Material resolveMaterial;
public int passIndex;
}
TextureHandle ResolveMotionVector(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle input)
{
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA))
{
using (var builder = renderGraph.AddRenderPass<ResolveMotionVectorData>("ResolveMotionVector", out var passData))
{
passData.input = builder.ReadTexture(input);
passData.output = builder.UseColorBuffer(CreateMotionVectorBuffer(renderGraph, false, false), 0);
passData.resolveMaterial = m_MotionVectorResolve;
passData.passIndex = SampleCountToPassIndex(m_MSAASamples);
builder.SetRenderFunc(
(ResolveMotionVectorData data, RenderGraphContext context) =>
{
var mpb = context.renderGraphPool.GetTempMaterialPropertyBlock();
mpb.SetTexture(HDShaderIDs._MotionVectorTextureMS, data.input);
context.cmd.DrawProcedural(Matrix4x4.identity, data.resolveMaterial, data.passIndex, MeshTopology.Triangles, 3, 1, mpb);
});
return passData.output;
}
}
else
{
return input;
}
}
class RenderAccumulationPassData
{
public RenderAccumulationParameters parameters;
public TextureHandle input;
public TextureHandle output;
public TextureHandle history;
}
void RenderAccumulation(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle inputTexture, TextureHandle outputTexture, bool needExposure)
{
using (var builder = renderGraph.AddRenderPass<RenderAccumulationPassData>("Render Accumulation", out var passData))
{
// Grab the history buffer
TextureHandle history = renderGraph.ImportTexture(hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.PathTracing)
?? hdCamera.AllocHistoryFrameRT((int)HDCameraFrameHistoryType.PathTracing, PathTracingHistoryBufferAllocatorFunction, 1));
bool inputFromRadianceTexture = !inputTexture.Equals(outputTexture);
passData.parameters = PrepareRenderAccumulationParameters(hdCamera, needExposure, inputFromRadianceTexture);
passData.input = builder.ReadTexture(inputTexture);
passData.output = builder.WriteTexture(outputTexture);
passData.history = builder.WriteTexture(history);
builder.SetRenderFunc(
(RenderAccumulationPassData data, RenderGraphContext ctx) =>
{
RenderAccumulation(data.parameters, data.input, data.output, data.history, ctx.cmd);
});
}
}
#if UNITY_EDITOR
class RenderGizmosPassData
{
public GizmoSubset gizmoSubset;
public Camera camera;
public Texture exposureTexture;
}
#endif
void RenderGizmos(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, GizmoSubset gizmoSubset)
{
#if UNITY_EDITOR
if (UnityEditor.Handles.ShouldRenderGizmos() &&
(hdCamera.camera.cameraType == CameraType.Game || hdCamera.camera.cameraType == CameraType.SceneView))
{
bool renderPrePostprocessGizmos = (gizmoSubset == GizmoSubset.PreImageEffects);
using (var builder = renderGraph.AddRenderPass<RenderGizmosPassData>(renderPrePostprocessGizmos ? "PrePostprocessGizmos" : "Gizmos", out var passData))
{
bool isMatCapView = m_CurrentDebugDisplaySettings.GetDebugLightingMode() == DebugLightingMode.MatcapView;
builder.WriteTexture(colorBuffer);
passData.gizmoSubset = gizmoSubset;
passData.camera = hdCamera.camera;
passData.exposureTexture = isMatCapView ? (Texture)Texture2D.blackTexture : m_PostProcessSystem.GetExposureTexture(hdCamera).rt;
builder.SetRenderFunc(
(RenderGizmosPassData data, RenderGraphContext ctx) =>
{
Gizmos.exposure = data.exposureTexture;
ctx.renderContext.ExecuteCommandBuffer(ctx.cmd);
ctx.cmd.Clear();
ctx.renderContext.DrawGizmos(data.camera, data.gizmoSubset);
});
}
}
#endif
}
bool RenderCustomPass(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
in PrepassOutput prepassOutput,
CullingResults cullingResults,
CullingResults cameraCullingResults,
CustomPassInjectionPoint injectionPoint,
AOVRequestData aovRequest,
List<RTHandle> aovCustomPassBuffers)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass))
return false;
bool executed = false;
CustomPassVolume.GetActivePassVolumes(injectionPoint, m_ActivePassVolumes);
foreach (var customPass in m_ActivePassVolumes)
{
if (customPass == null)
return false;
var customPassTargets = new CustomPass.RenderTargets
{
// TODO RENDERGRAPH: we can't replace the Lazy<RTHandle> buffers with RenderGraph resource because they are part of the current public API.
// To replace them correctly we need users to actually write render graph passes and explicit whether or not they want to use those buffers.
// We'll do it when we switch fully to render graph for custom passes.
customColorBuffer = m_CustomPassColorBuffer,
customDepthBuffer = m_CustomPassDepthBuffer,
// Render Graph Specific textures
colorBufferRG = colorBuffer,
nonMSAAColorBufferRG = m_NonMSAAColorBuffer,
depthBufferRG = prepassOutput.depthBuffer,
normalBufferRG = prepassOutput.resolvedNormalBuffer,
motionVectorBufferRG = prepassOutput.resolvedMotionVectorsBuffer
};
executed |= customPass.Execute(renderGraph, hdCamera, cullingResults, cameraCullingResults, customPassTargets);
}
// Push the custom pass buffer, in case it was requested in the AOVs
aovRequest.PushCustomPassTexture(renderGraph, injectionPoint, colorBuffer, m_CustomPassColorBuffer, aovCustomPassBuffers);
return executed;
}
class ResetCameraSizeForAfterPostProcessPassData
{
public HDCamera hdCamera;
public ShaderVariablesGlobal shaderVariablesGlobal;
}
void ResetCameraSizeForAfterPostProcess(RenderGraph renderGraph, HDCamera hdCamera, CommandBuffer commandBuffer)
{
if (DynamicResolutionHandler.instance.DynamicResolutionEnabled())
{
using (var builder = renderGraph.AddRenderPass("Reset Camera Size After Post Process", out ResetCameraSizeForAfterPostProcessPassData passData))
{
passData.hdCamera = hdCamera;
passData.shaderVariablesGlobal = m_ShaderVariablesGlobalCB;
builder.AllowPassCulling(false);
builder.SetRenderFunc(
(ResetCameraSizeForAfterPostProcessPassData data, RenderGraphContext ctx) =>
{
data.shaderVariablesGlobal._ScreenSize = new Vector4(data.hdCamera.finalViewport.width, data.hdCamera.finalViewport.height, 1.0f / data.hdCamera.finalViewport.width, 1.0f / data.hdCamera.finalViewport.height);
data.shaderVariablesGlobal._RTHandleScale = RTHandles.rtHandleProperties.rtHandleScale;
ConstantBuffer.PushGlobal(ctx.cmd, data.shaderVariablesGlobal, HDShaderIDs._ShaderVariablesGlobal);
RTHandles.SetReferenceSize((int)data.hdCamera.finalViewport.width, (int)data.hdCamera.finalViewport.height, data.hdCamera.msaaSamples);
});
}
}
}
class BindCustomPassBuffersPassData
{
public Lazy<RTHandle> customColorTexture;
public Lazy<RTHandle> customDepthTexture;
}
void BindCustomPassBuffers(RenderGraph renderGraph, HDCamera hdCamera)
{
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass))
{
using (var builder = renderGraph.AddRenderPass("Bind Custom Pass Buffers", out BindCustomPassBuffersPassData passData))
{
passData.customColorTexture = m_CustomPassColorBuffer;
passData.customDepthTexture = m_CustomPassDepthBuffer;
builder.SetRenderFunc(
(BindCustomPassBuffersPassData data, RenderGraphContext ctx) =>
{
if (data.customColorTexture.IsValueCreated)
ctx.cmd.SetGlobalTexture(HDShaderIDs._CustomColorTexture, data.customColorTexture.Value);
if (data.customDepthTexture.IsValueCreated)
ctx.cmd.SetGlobalTexture(HDShaderIDs._CustomDepthTexture, data.customDepthTexture.Value);
});
}
}
}
#if UNITY_EDITOR
class RenderWireOverlayPassData
{
public HDCamera hdCamera;
}
#endif
void RenderWireOverlay(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer)
{
#if UNITY_EDITOR
if (hdCamera.camera.cameraType == CameraType.SceneView)
{
using (var builder = renderGraph.AddRenderPass<RenderWireOverlayPassData>("Wire Overlay", out var passData))
{
builder.WriteTexture(colorBuffer);
passData.hdCamera = hdCamera;
builder.SetRenderFunc(
(RenderWireOverlayPassData data, RenderGraphContext ctx) =>
{
ctx.renderContext.ExecuteCommandBuffer(ctx.cmd);
ctx.cmd.Clear();
ctx.renderContext.DrawWireOverlay(data.hdCamera.camera);
});
}
}
#endif
}
}
}