diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 6a6818f871a..f6b67b27719 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -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) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 8b594bc7c3f..196b69cb5be 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -1903,8 +1903,9 @@ AOVRequestData aovRequest } using (ListPool.Get(out var aovBuffers)) + using (ListPool.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() @@ -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); @@ -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) @@ -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); @@ -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); @@ -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) @@ -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. @@ -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 aovCustomPassBuffers) { if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.CustomPass)) return false; @@ -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; } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVBuffers.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVBuffers.cs index 85182c54125..f30acd39acb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVBuffers.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVBuffers.cs @@ -14,4 +14,35 @@ public enum AOVBuffers /// Motion vectors buffer at the end of the frame. MotionVectors } + + /// + /// Describes the type of custom pass buffer that will be exported with the AOV API. + /// + public class CustomPassAOVBuffers + { + /// Specifies which output type to export. + public enum OutputType + { + /// The custom pass buffer will be exported. + CustomPassBuffer, + /// The color buffer of the camera will be exported. + Camera + } + + /// The injection point of the custom passes that will be exported. + public CustomPassInjectionPoint injectionPoint = CustomPassInjectionPoint.BeforeRendering; + /// Specifies which output type to export. + public OutputType outputType = OutputType.CustomPassBuffer; + + /// + /// Constructor for CustomPassAOVBuffers + /// + /// The injection point of the custom passes that will be exported. + /// The buffer type to export at the scpecified injection point. + public CustomPassAOVBuffers(CustomPassInjectionPoint injectionPoint, OutputType outputType) + { + this.injectionPoint = injectionPoint; + this.outputType = outputType; + } + } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestBuilder.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestBuilder.cs index 251ebd0d33c..d7c9ca9f358 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestBuilder.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestBuilder.cs @@ -29,6 +29,30 @@ FramePassCallback callback return this; } + /// Add a AOV request. + /// Settings to use for this frame pass. + /// An allocator for each buffer. + /// If non null, only these lights will be rendered, if none, all lights will be rendered. + /// A list of buffers to use. + /// A list of custom passes to captured. + /// An allocator for each custom pass buffer. + /// A callback that can use the requested buffers once the rendering has completed. + /// + public AOVRequestBuilder Add( + AOVRequest settings, + AOVRequestBufferAllocator bufferAllocator, + List includedLightList, + AOVBuffers[] aovBuffers, + CustomPassAOVBuffers[] customPassAovBuffers, + AOVRequestCustomPassBufferAllocator customPassbufferAllocator, + FramePassCallbackEx callback + ) + { + (m_AOVRequestDataData ?? (m_AOVRequestDataData = ListPool.Get())).Add( + new AOVRequestData(settings, bufferAllocator, includedLightList, aovBuffers, customPassAovBuffers, customPassbufferAllocator, callback)); + return this; + } + /// Build the frame passes. Allocated resources will be transferred to the returned value. /// The built collection. public AOVRequestDataCollection Build() diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs index 3598d05c20b..ae9bf328baa 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/AOV/AOVRequestData.cs @@ -16,6 +16,17 @@ namespace UnityEngine.Rendering.HighDefinition /// The AOVBuffer to allocatE. public delegate RTHandle AOVRequestBufferAllocator(AOVBuffers aovBufferId); + /// Called when the rendering has completed. + /// A command buffer that can be used. + /// The buffers that has been requested. + /// Several properties that were computed for this frame. + public delegate void FramePassCallbackEx(CommandBuffer cmd, List buffers, List customPassbuffers, RenderOutputProperties outputProperties); + /// + /// Called to allocate a RTHandle for a specific custom pass AOVBuffer. + /// + /// The AOVBuffer to allocatE. + public delegate RTHandle AOVRequestCustomPassBufferAllocator(CustomPassAOVBuffers aovBufferId); + /// Describes a frame pass. public struct AOVRequestData { @@ -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 m_LightFilter; /// Whether this frame pass is valid. - public bool isValid => m_RequestedAOVBuffers != null && m_Callback != null; + public bool isValid => (m_RequestedAOVBuffers != null || m_CustomPassAOVBuffers != null) && (m_Callback != null || m_CallbackEx != null); /// Create a new frame pass. /// Settings to use. @@ -67,6 +81,38 @@ FramePassCallback callback m_RequestedAOVBuffers = requestedAOVBuffers; m_LightFilter = lightFilter; m_Callback = callback; + + m_CallbackEx = null; + m_CustomPassAOVBuffers = null; + m_CustomPassBufferAllocator = null; + } + + /// Create a new frame pass. + /// Settings to use. + /// Buffer allocators to use. + /// If null, all light will be rendered, if not, only those light will be rendered. + /// The requested buffers for the callback. + /// The custom pass buffers that will be captured. + /// Buffer allocators to use for custom passes. + /// The callback to execute. + public AOVRequestData( + AOVRequest settings, + AOVRequestBufferAllocator bufferAllocator, + List 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; } /// Allocate texture if required. @@ -76,12 +122,36 @@ public void AllocateTargetTexturesIfRequired(ref List 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)); + } + } + + /// Allocate texture if required. + /// A buffer of texture ready to use. + public void AllocateTargetTexturesIfRequired(ref List textures, ref List 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)); + } } /// Copy a camera sized texture into the texture buffers. @@ -98,7 +168,7 @@ internal void PushCameraTexture( List targets ) { - if (!isValid) + if (!isValid || m_RequestedAOVBuffers == null) return; Assert.IsNotNull(m_RequestedAOVBuffers); @@ -111,6 +181,45 @@ List targets HDUtils.BlitCameraTexture(cmd, source, targets[index]); } + internal void PushCustomPassTexture( + CommandBuffer cmd, + CustomPassInjectionPoint injectionPoint, + RTHandle cameraSource, + Lazy customPassSource, + List 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; @@ -127,7 +236,7 @@ internal void PushCameraTexture( List targets ) { - if (!isValid) + if (!isValid || m_RequestedAOVBuffers == null) return; Assert.IsNotNull(m_RequestedAOVBuffers); @@ -163,6 +272,25 @@ public void Execute(CommandBuffer cmd, List framePassTextures, RenderO m_Callback(cmd, framePassTextures, outputProperties); } + /// Execute the frame pass callback. It assumes that the textures are properly initialized and filled. + /// The command buffer to use. + /// The textures to use. + /// The properties computed for this frame. + public void Execute(CommandBuffer cmd, List framePassTextures, List customPassTextures, RenderOutputProperties outputProperties) + { + if (!isValid) + return; + + if (m_CallbackEx != null) + { + m_CallbackEx(cmd, framePassTextures, customPassTextures, outputProperties); + } + else + { + m_Callback(cmd, framePassTextures, outputProperties); + } + } + /// Setup the display manager if necessary. /// public void SetupDebugData(ref DebugDisplaySettings debugDisplaySettings)