Skip to content
Merged
2 changes: 2 additions & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added support for specular AA from geometric curvature in AxF
- Added support for baked AO (no input for now) in AxF
- Added an info box to warn about depth test artifacts when rendering object twice in custom passes with MSAA.
- Added a frame setting for alpha to mask.
- Added support for custom passes in the AOV API

### Fixed
- Fix when rescale probe all direction below zero (1219246)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1903,8 +1903,9 @@ AOVRequestData aovRequest
}

using (ListPool<RTHandle>.Get(out var aovBuffers))
using (ListPool<RTHandle>.Get(out var aovCustomPassBuffers))
{
aovRequest.AllocateTargetTexturesIfRequired(ref aovBuffers);
aovRequest.AllocateTargetTexturesIfRequired(ref aovBuffers, ref aovCustomPassBuffers);

// If we render a reflection view or a preview we should not display any debug information
// This need to be call before ApplyDebugDisplaySettings()
Expand Down Expand Up @@ -2044,7 +2045,7 @@ AOVRequestData aovRequest
cmd.SetGlobalTexture(HDShaderIDs._CustomDepthTexture, m_CustomPassDepthBuffer.Value);
}

RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeRendering);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeRendering, aovRequest, aovCustomPassBuffers);

RenderRayTracingPrepass(cullingResults, hdCamera, renderContext, cmd, false);

Expand Down Expand Up @@ -2138,7 +2139,7 @@ void Callback(CommandBuffer c, HDCamera cam)
m_SharedRTManager.BindNormalBuffer(cmd);

// After Depth and Normals/roughness including decals
bool depthBufferModified = RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterOpaqueDepthAndNormal);
bool depthBufferModified = RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterOpaqueDepthAndNormal, aovRequest, aovCustomPassBuffers);

// If the depth was already copied in RenderDBuffer, we force the copy again because the custom pass modified the depth.
if (depthBufferModified)
Expand Down Expand Up @@ -2370,7 +2371,7 @@ void Callback(CommandBuffer c, HDCamera cam)

// To allow users to fetch the current color buffer, we temporarily bind the camera color buffer
cmd.SetGlobalTexture(HDShaderIDs._ColorPyramidTexture, m_CameraColorBuffer);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePreRefraction);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePreRefraction, aovRequest, aovCustomPassBuffers);

// Render pre refraction objects
RenderForwardTransparent(cullingResults, hdCamera, true, renderContext, cmd);
Expand All @@ -2391,7 +2392,7 @@ void Callback(CommandBuffer c, HDCamera cam)
}

// We don't have access to the color pyramid with transparent if rough refraction is disabled
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeTransparent);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforeTransparent, aovRequest, aovCustomPassBuffers);

// Render all type of transparent forward (unlit, lit, complex (hair...)) to keep the sorting between transparent objects.
RenderForwardTransparent(cullingResults, hdCamera, false, renderContext, cmd);
Expand Down Expand Up @@ -2450,14 +2451,14 @@ void Callback(CommandBuffer c, HDCamera cam)
// At this point, m_CameraColorBuffer has been filled by either debug views are regular rendering so we can push it here.
PushColorPickerDebugTexture(cmd, hdCamera, m_CameraColorBuffer);

RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePostProcess);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.BeforePostProcess, aovRequest, aovCustomPassBuffers);

aovRequest.PushCameraTexture(cmd, AOVBuffers.Color, hdCamera, m_CameraColorBuffer, aovBuffers);

RenderTargetIdentifier postProcessDest = HDUtils.PostProcessIsFinalPass(hdCamera) ? target.id : m_IntermediateAfterPostProcessBuffer;
RenderPostProcess(cullingResults, hdCamera, postProcessDest, renderContext, cmd);

RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterPostProcess);
RenderCustomPass(renderContext, cmd, hdCamera, customPassCullingResults, CustomPassInjectionPoint.AfterPostProcess, aovRequest, aovCustomPassBuffers);

// Copy and rescale depth buffer for XR devices
if (hdCamera.xr.enabled && hdCamera.xr.copyDepth)
Expand Down Expand Up @@ -2543,7 +2544,7 @@ void Callback(CommandBuffer c, HDCamera cam)
RenderGizmos(cmd, camera, renderContext, GizmoSubset.PostImageEffects);
#endif

aovRequest.Execute(cmd, aovBuffers, RenderOutputProperties.From(hdCamera));
aovRequest.Execute(cmd, aovBuffers, aovCustomPassBuffers, RenderOutputProperties.From(hdCamera));
}

// This is required so that all commands up to here are executed before EndCameraRendering is called for the user.
Expand Down Expand Up @@ -3679,7 +3680,7 @@ void RenderForwardError(CullingResults cullResults, HDCamera hdCamera, Scriptabl
}
}

bool RenderCustomPass(ScriptableRenderContext context, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults, CustomPassInjectionPoint injectionPoint)
bool RenderCustomPass(ScriptableRenderContext context, CommandBuffer cmd, HDCamera hdCamera, CullingResults cullingResults, CustomPassInjectionPoint injectionPoint, AOVRequestData aovRequest, List<RTHandle> aovCustomPassBuffers)
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass))
return false;
Expand All @@ -3701,6 +3702,9 @@ bool RenderCustomPass(ScriptableRenderContext context, CommandBuffer cmd, HDCame
executed |= customPass.Execute(context, cmd, hdCamera, cullingResults, m_SharedRTManager, customPassTargets);
}

// Push the custom pass buffer, in case it was requested in the AOVs
aovRequest.PushCustomPassTexture(cmd, injectionPoint, m_CameraColorBuffer, m_CustomPassColorBuffer, aovCustomPassBuffers);

return executed;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,35 @@ public enum AOVBuffers
/// <summary>Motion vectors buffer at the end of the frame.</summary>
MotionVectors
}

/// <summary>
/// Describes the type of custom pass buffer that will be exported with the AOV API.
/// </summary>
public class CustomPassAOVBuffers
{
/// <summary> Specifies which output type to export.</summary>
public enum OutputType
{
/// <summary> The custom pass buffer will be exported.</summary>
CustomPassBuffer,
/// <summary> The color buffer of the camera will be exported.</summary>
Camera
}

/// <summary> The injection point of the custom passes that will be exported. </summary>
public CustomPassInjectionPoint injectionPoint = CustomPassInjectionPoint.BeforeRendering;
/// <summary> Specifies which output type to export.</summary>
public OutputType outputType = OutputType.CustomPassBuffer;

/// <summary>
/// Constructor for CustomPassAOVBuffers
/// </summary>
/// <param name="injectionPoint"> The injection point of the custom passes that will be exported. </param>
/// <param name="outputType"> The buffer type to export at the scpecified injection point. </param>
public CustomPassAOVBuffers(CustomPassInjectionPoint injectionPoint, OutputType outputType)
{
this.injectionPoint = injectionPoint;
this.outputType = outputType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ FramePassCallback callback
return this;
}

/// <summary>Add a AOV request.</summary>
/// <param name="settings">Settings to use for this frame pass.</param>
/// <param name="bufferAllocator">An allocator for each buffer.</param>
/// <param name="includedLightList">If non null, only these lights will be rendered, if none, all lights will be rendered.</param>
/// <param name="aovBuffers">A list of buffers to use.</param>
/// <param name="customPassAovBuffers">A list of custom passes to captured.</param>
/// <param name="customPassbufferAllocator">An allocator for each custom pass buffer.</param>
/// <param name="callback">A callback that can use the requested buffers once the rendering has completed.</param>
/// <returns></returns>
public AOVRequestBuilder Add(
AOVRequest settings,
AOVRequestBufferAllocator bufferAllocator,
List<GameObject> includedLightList,
AOVBuffers[] aovBuffers,
CustomPassAOVBuffers[] customPassAovBuffers,
AOVRequestCustomPassBufferAllocator customPassbufferAllocator,
FramePassCallbackEx callback
)
{
(m_AOVRequestDataData ?? (m_AOVRequestDataData = ListPool<AOVRequestData>.Get())).Add(
new AOVRequestData(settings, bufferAllocator, includedLightList, aovBuffers, customPassAovBuffers, customPassbufferAllocator, callback));
return this;
}

/// <summary>Build the frame passes. Allocated resources will be transferred to the returned value.</summary>
/// <returns>The built collection.</returns>
public AOVRequestDataCollection Build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ namespace UnityEngine.Rendering.HighDefinition
/// <param name="aovBufferId">The AOVBuffer to allocatE.</param>
public delegate RTHandle AOVRequestBufferAllocator(AOVBuffers aovBufferId);

/// <summary>Called when the rendering has completed.</summary>
/// <param name="cmd">A command buffer that can be used.</param>
/// <param name="buffers">The buffers that has been requested.</param>
/// <param name="outputProperties">Several properties that were computed for this frame.</param>
public delegate void FramePassCallbackEx(CommandBuffer cmd, List<RTHandle> buffers, List<RTHandle> customPassbuffers, RenderOutputProperties outputProperties);
/// <summary>
/// Called to allocate a RTHandle for a specific custom pass AOVBuffer.
/// </summary>
/// <param name="aovBufferId">The AOVBuffer to allocatE.</param>
public delegate RTHandle AOVRequestCustomPassBufferAllocator(CustomPassAOVBuffers aovBufferId);

/// <summary>Describes a frame pass.</summary>
public struct AOVRequestData
{
Expand All @@ -41,12 +52,15 @@ public struct AOVRequestData

private AOVRequest m_Settings;
private AOVBuffers[] m_RequestedAOVBuffers;
private CustomPassAOVBuffers[] m_CustomPassAOVBuffers;
private FramePassCallback m_Callback;
private FramePassCallbackEx m_CallbackEx;
private readonly AOVRequestBufferAllocator m_BufferAllocator;
private readonly AOVRequestCustomPassBufferAllocator m_CustomPassBufferAllocator;
private List<GameObject> m_LightFilter;

/// <summary>Whether this frame pass is valid.</summary>
public bool isValid => m_RequestedAOVBuffers != null && m_Callback != null;
public bool isValid => (m_RequestedAOVBuffers != null || m_CustomPassAOVBuffers != null) && (m_Callback != null || m_CallbackEx != null);

/// <summary>Create a new frame pass.</summary>
/// <param name="settings">Settings to use.</param>
Expand All @@ -67,6 +81,38 @@ FramePassCallback callback
m_RequestedAOVBuffers = requestedAOVBuffers;
m_LightFilter = lightFilter;
m_Callback = callback;

m_CallbackEx = null;
m_CustomPassAOVBuffers = null;
m_CustomPassBufferAllocator = null;
}

/// <summary>Create a new frame pass.</summary>
/// <param name="settings">Settings to use.</param>
/// <param name="bufferAllocator">Buffer allocators to use.</param>
/// <param name="lightFilter">If null, all light will be rendered, if not, only those light will be rendered.</param>
/// <param name="requestedAOVBuffers">The requested buffers for the callback.</param>
/// <param name="customPassAOVBuffers">The custom pass buffers that will be captured.</param>
/// <param name="customPassBufferAllocator">Buffer allocators to use for custom passes.</param>
/// <param name="callback">The callback to execute.</param>
public AOVRequestData(
AOVRequest settings,
AOVRequestBufferAllocator bufferAllocator,
List<GameObject> lightFilter,
AOVBuffers[] requestedAOVBuffers,
CustomPassAOVBuffers[] customPassAOVBuffers,
AOVRequestCustomPassBufferAllocator customPassBufferAllocator,
FramePassCallbackEx callback
)
{
m_Settings = settings;
m_BufferAllocator = bufferAllocator;
m_RequestedAOVBuffers = requestedAOVBuffers;
m_CustomPassAOVBuffers = customPassAOVBuffers;
m_CustomPassBufferAllocator = customPassBufferAllocator;
m_LightFilter = lightFilter;
m_Callback = null;
m_CallbackEx = callback;
}

/// <summary>Allocate texture if required.</summary>
Expand All @@ -76,12 +122,36 @@ public void AllocateTargetTexturesIfRequired(ref List<RTHandle> textures)
if (!isValid || textures == null)
return;

Assert.IsNotNull(m_RequestedAOVBuffers);
textures.Clear();

if (m_RequestedAOVBuffers != null)
{
foreach (var bufferId in m_RequestedAOVBuffers)
textures.Add(m_BufferAllocator(bufferId));
}
}

/// <summary>Allocate texture if required.</summary>
/// <param name="textures">A buffer of texture ready to use.</param>
public void AllocateTargetTexturesIfRequired(ref List<RTHandle> textures, ref List<RTHandle> customPassTextures)
{
if (!isValid || textures == null)
return;

textures.Clear();
customPassTextures.Clear();

foreach (var bufferId in m_RequestedAOVBuffers)
textures.Add(m_BufferAllocator(bufferId));
if (m_RequestedAOVBuffers != null)
{
foreach (var bufferId in m_RequestedAOVBuffers)
textures.Add(m_BufferAllocator(bufferId));
}

if (m_CustomPassAOVBuffers != null)
{
foreach (var aovBufferId in m_CustomPassAOVBuffers)
customPassTextures.Add(m_CustomPassBufferAllocator(aovBufferId));
}
}

/// <summary>Copy a camera sized texture into the texture buffers.</summary>
Expand All @@ -98,7 +168,7 @@ internal void PushCameraTexture(
List<RTHandle> targets
)
{
if (!isValid)
if (!isValid || m_RequestedAOVBuffers == null)
return;

Assert.IsNotNull(m_RequestedAOVBuffers);
Expand All @@ -111,6 +181,45 @@ List<RTHandle> targets
HDUtils.BlitCameraTexture(cmd, source, targets[index]);
}

internal void PushCustomPassTexture(
CommandBuffer cmd,
CustomPassInjectionPoint injectionPoint,
RTHandle cameraSource,
Lazy<RTHandle> customPassSource,
List<RTHandle> targets
)
{
if (!isValid || m_CustomPassAOVBuffers == null)
return;

Assert.IsNotNull(targets);

int index = -1;
for (int i = 0; i < m_CustomPassAOVBuffers.Length; ++i)
{
if (m_CustomPassAOVBuffers[i].injectionPoint == injectionPoint)
{
index = i;
break;
}
}

if (index == -1)
return;

if (m_CustomPassAOVBuffers[index].outputType == CustomPassAOVBuffers.OutputType.Camera)
{
HDUtils.BlitCameraTexture(cmd, cameraSource, targets[index]);
}
else
{
if (customPassSource.IsValueCreated)
{
HDUtils.BlitCameraTexture(cmd, customPassSource.Value, targets[index]);
}
}
}

class PushCameraTexturePassData
{
public int requestIndex;
Expand All @@ -127,7 +236,7 @@ internal void PushCameraTexture(
List<RTHandle> targets
)
{
if (!isValid)
if (!isValid || m_RequestedAOVBuffers == null)
return;

Assert.IsNotNull(m_RequestedAOVBuffers);
Expand Down Expand Up @@ -163,6 +272,25 @@ public void Execute(CommandBuffer cmd, List<RTHandle> framePassTextures, RenderO
m_Callback(cmd, framePassTextures, outputProperties);
}

/// <summary>Execute the frame pass callback. It assumes that the textures are properly initialized and filled.</summary>
/// <param name="cmd">The command buffer to use.</param>
/// <param name="framePassTextures">The textures to use.</param>
/// <param name="outputProperties">The properties computed for this frame.</param>
public void Execute(CommandBuffer cmd, List<RTHandle> framePassTextures, List<RTHandle> customPassTextures, RenderOutputProperties outputProperties)
{
if (!isValid)
return;

if (m_CallbackEx != null)
{
m_CallbackEx(cmd, framePassTextures, customPassTextures, outputProperties);
}
else
{
m_Callback(cmd, framePassTextures, outputProperties);
}
}

/// <summary>Setup the display manager if necessary.</summary>
/// <param name="debugDisplaySettings"></param>
public void SetupDebugData(ref DebugDisplaySettings debugDisplaySettings)
Expand Down