Skip to content

Custom Pass AOV API #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added API to enable proper recording of path traced scenes (with the Unity recorder or other tools).
- Added support for fog in Recursive rendering, ray traced reflections and ray traced indirect diffuse.
- Added an alpha blend option for recursive rendering
- 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 @@ -1886,8 +1886,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 @@ -2017,7 +2018,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 @@ -2052,7 +2053,7 @@ AOVRequestData aovRequest
m_SharedRTManager.BindNormalBuffer(cmd);

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

// In both forward and deferred, everything opaque should have been rendered at this point so we can safely copy the depth buffer for later processing.
GenerateDepthPyramid(hdCamera, cmd, FullScreenDebugMode.DepthPyramid);
Expand Down Expand Up @@ -2292,7 +2293,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 @@ -2313,7 +2314,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 @@ -2372,14 +2373,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 @@ -2465,7 +2466,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 @@ -3589,7 +3590,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 @@ -3611,6 +3612,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,36 @@ 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);

var index = Array.FindIndex(m_CustomPassAOVBuffers, x => x.injectionPoint == injectionPoint);
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 +227,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 +263,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