using UnityEngine.Rendering; #if URP_7_OR_NEWER using UnityEngine.Rendering.Universal; using UnityEngine.XR.ARSubsystems; using System; #if URP_17_OR_NEWER using UnityEngine.Rendering.RenderGraphModule; #else using UnityEngine.Experimental.Rendering; #endif // URP_17_OR_NEWER #else using ScriptableRendererFeature = UnityEngine.ScriptableObject; #endif // URP_7_OR_NEWER namespace UnityEngine.XR.ARFoundation { /// /// A render feature for rendering the camera background for AR devices. /// public class ARBackgroundRendererFeature : ScriptableRendererFeature { #if URP_7_OR_NEWER /// /// The scriptable render pass to be added to the renderer when the camera background is to be rendered. /// ARCameraBeforeOpaquesRenderPass beforeOpaquesScriptablePass => m_BeforeOpaquesScriptablePass ??= new ARCameraBeforeOpaquesRenderPass(); ARCameraBeforeOpaquesRenderPass m_BeforeOpaquesScriptablePass; /// /// The scriptable render pass to be added to the renderer when the camera background is to be rendered. /// ARCameraAfterOpaquesRenderPass afterOpaquesScriptablePass => m_AfterOpaquesScriptablePass ??= new ARCameraAfterOpaquesRenderPass(); ARCameraAfterOpaquesRenderPass m_AfterOpaquesScriptablePass; /// /// Create the scriptable render pass. /// public override void Create() { } /// /// Add the background rendering pass when rendering a game camera with an enabled AR camera background component. /// /// The scriptable renderer in which to enqueue the render pass. /// Additional rendering data about the current state of rendering. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { var currentCamera = renderingData.cameraData.camera; if (currentCamera != null && currentCamera.cameraType == CameraType.Game) { var cameraBackground = currentCamera.gameObject.GetComponent(); if (cameraBackground != null && cameraBackground.backgroundRenderingEnabled && cameraBackground.material != null && TrySelectRenderPassForBackgroundRenderMode(cameraBackground.currentRenderingMode, out var renderPass)) { var invertCulling = cameraBackground.GetComponent()?.subsystem?.invertCulling ?? false; renderPass.Setup(cameraBackground, invertCulling); renderer.EnqueuePass(renderPass); } } } /// /// Selects the render pass for a given /// /// The /// that indicates which render pass to use. /// /// The that corresponds /// to the given . /// /// /// true if was populated. Otherwise, false. /// bool TrySelectRenderPassForBackgroundRenderMode(XRCameraBackgroundRenderingMode renderingMode, out ARCameraBackgroundRenderPass renderPass) { switch (renderingMode) { case XRCameraBackgroundRenderingMode.AfterOpaques: renderPass = afterOpaquesScriptablePass; return true; case XRCameraBackgroundRenderingMode.BeforeOpaques: renderPass = beforeOpaquesScriptablePass; return true; case XRCameraBackgroundRenderingMode.None: default: renderPass = null; return false; } } /// /// An abstract that provides common utilities for rendering an AR Camera Background. /// abstract class ARCameraBackgroundRenderPass : ScriptableRenderPass { /// /// Data provided for the function. /// class PassData { internal Matrix4x4 worldToCameraMatrix; internal Matrix4x4 projectionMatrix; internal bool invertCulling; internal XRCameraBackgroundRenderingParams cameraBackgroundRenderingParams; internal Material backgroundMaterial; } #if URP_17_OR_NEWER // Name of our RenderGraph render pass. const string k_RenderGraphPassName = "AR Background Render Pass (Render Graph Enabled)"; #endif // URP_17_OR_NEWER /// /// The data that is passed to the render pass execute functions. /// PassData m_RenderPassData = new(); /// /// The material used for rendering the device background using the camera video texture and potentially /// other device-specific properties and textures. /// Material m_BackgroundMaterial; /// /// The geometry and transform of the camera background for a given platform. /// XRCameraBackgroundRenderingParams m_CameraBackgroundRenderingParams; ARDefaultCameraBackgroundRenderingParams m_DefaultCameraBackgroundRenderingParams; /// /// Whether the culling mode should be inverted. /// ([CommandBuffer.SetInvertCulling](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetInvertCulling.html)). /// bool m_InvertCulling; /// /// The default platform geometry and transform for the camera background. /// XRCameraBackgroundRenderingParams defaultCameraBackgroundRenderingParams => m_DefaultCameraBackgroundRenderingParams.SelectDefaultBackgroundRenderParametersForRenderMode(renderingMode); /// /// The rendering mode for the camera background. Options are None, BeforeOpaques, and AfterOpaques. /// protected abstract XRCameraBackgroundRenderingMode renderingMode { get; } /// /// Set up the background render pass. /// /// The ARCameraBackground component that provides the /// and any additional rendering information required by the render pass. /// Whether the culling mode should be inverted. public void Setup(ARCameraBackground cameraBackground, bool invertCulling) { SetupInternal(cameraBackground); m_DefaultCameraBackgroundRenderingParams = cameraBackground.defaultCameraBackgroundRenderingParams; if (!cameraBackground.TryGetRenderingParameters(out m_CameraBackgroundRenderingParams)) m_CameraBackgroundRenderingParams = defaultCameraBackgroundRenderingParams; m_BackgroundMaterial = cameraBackground.material; m_InvertCulling = invertCulling; } /// /// Provides inheritors an opportunity to perform any specialized setup during /// . /// /// The ARCameraBackground component that provides the /// and any additional rendering information required by the render pass. protected virtual void SetupInternal(ARCameraBackground cameraBackground) { if (cameraBackground.occlusionManager != null && cameraBackground.occlusionManager.enabled) { // If an occlusion texture is being provided, rendering will need // to compare it against the depth texture created by the camera. ConfigureInput(ScriptableRenderPassInput.Depth); } } /// /// Execute the commands to render the camera background with RenderGraph disabled. /// /// The render context for executing the render commands. /// Additional rendering data about the current state of rendering. #pragma warning disable CS0672 public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) #pragma warning restore CS0672 { // Populate struct to send to ExecuteRenderPass m_RenderPassData.worldToCameraMatrix = renderingData.cameraData.camera.worldToCameraMatrix; m_RenderPassData.projectionMatrix = renderingData.cameraData.camera.projectionMatrix; m_RenderPassData.invertCulling = m_InvertCulling; m_RenderPassData.cameraBackgroundRenderingParams = m_CameraBackgroundRenderingParams; m_RenderPassData.backgroundMaterial = m_BackgroundMaterial; var cmd = CommandBufferPool.Get("AR Background Render Pass (Render Graph Disabled)"); ExecuteRenderPass(CommandBufferHelpers.GetRasterCommandBuffer(cmd), m_RenderPassData); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); } /// /// Execute the commands to render the camera background. This function is used for both RenderGraph and /// non-RenderGraph paths. /// /// The RasterCommandBuffer object that allows us to enqueue /// rendering instructions to the native for this render pass. /// The data that is passed to the function that executes this render pass. static void ExecuteRenderPass(RasterCommandBuffer rasterCommandBuffer, PassData passData) { ARCameraBackground.AddBeforeBackgroundRenderHandler(rasterCommandBuffer); rasterCommandBuffer.SetInvertCulling(passData.invertCulling); rasterCommandBuffer.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); rasterCommandBuffer.DrawMesh( passData.cameraBackgroundRenderingParams.backgroundGeometry, passData.cameraBackgroundRenderingParams.backgroundTransform, passData.backgroundMaterial); rasterCommandBuffer.SetViewProjectionMatrices( passData.worldToCameraMatrix, passData.projectionMatrix); } #if URP_17_OR_NEWER /// /// This is part of the RenderGraph path. It calls , which is shared by both the /// RenderGraph and non-RenderGraph paths. /// /// The data that is passed to the function that executes this render pass. /// The RasterGraphContext object that allows us to access the /// and native to enqueue rendering instructions /// for this render pass. static void ExecuteRasterRenderGraphPass(PassData passData, RasterGraphContext rasterContext) { ExecuteRenderPass(rasterContext.cmd, passData); } /// /// Create and add the raster pass to RenderGraph, as well as storing all the data needed to execute the pass. /// /// The RenderGraph object that we add the raster render pass to. /// A ContextContainer object that gives us access to the camera and render /// texture data for this RenderGraph raster pass. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) { using (var builder = renderGraph.AddRasterRenderPass( k_RenderGraphPassName, out m_RenderPassData, profilingSampler)) { UniversalCameraData cameraData = frameData.Get(); UniversalResourceData resourceData = frameData.Get(); // Populate struct to send to ExecuteRasterRenderGraphPass m_RenderPassData.worldToCameraMatrix = cameraData.camera.worldToCameraMatrix; m_RenderPassData.projectionMatrix = cameraData.camera.projectionMatrix; m_RenderPassData.invertCulling = m_InvertCulling; m_RenderPassData.cameraBackgroundRenderingParams = m_CameraBackgroundRenderingParams; m_RenderPassData.backgroundMaterial = m_BackgroundMaterial; // Shader keyword changes are considered global state modifications builder.AllowGlobalStateModification(true); builder.AllowPassCulling(false); // The RenderGraph render target is the main camera's active color TextureHandle builder.SetRenderAttachment(resourceData.activeColorTexture, 0); // The RenderGraph depth target is the main camera's active depth TextureHandle builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture); builder.SetRenderFunc(ExecuteRasterRenderGraphPass); } } #endif // URP_17_OR_NEWER /// /// Called upon finish rendering a camera. Releases any resources created by this render pass or /// otherwise executes any cleanup code. /// /// Use this CommandBuffer to cleanup any generated data public override void OnCameraCleanup(CommandBuffer cmd) { if (cmd == null) throw new ArgumentNullException(nameof(cmd)); // If invert culling is true, we must make sure it is only enabled for the minimum amount of time // in code where it is needed, since other systems won't necessarily work when it is enabled. if (m_InvertCulling) cmd.SetInvertCulling(false); } } /// /// The custom render pass to render the camera background before rendering opaques. /// class ARCameraBeforeOpaquesRenderPass : ARCameraBackgroundRenderPass { /// /// Constructs the background render pass. /// public ARCameraBeforeOpaquesRenderPass() { renderPassEvent = RenderPassEvent.BeforeRenderingOpaques; } /// /// Configure the render pass by setting the render target and clear values. /// /// The command buffer for configuration. /// The descriptor of the target render texture. #pragma warning disable CS0672 public override void Configure(CommandBuffer commandBuffer, RenderTextureDescriptor renderTextureDescriptor) #pragma warning restore CS0672 { #pragma warning disable CS0618 ConfigureClear(ClearFlag.Depth, Color.clear); #pragma warning restore CS0618 } protected override XRCameraBackgroundRenderingMode renderingMode => XRCameraBackgroundRenderingMode.BeforeOpaques; } /// /// The custom render pass to render the camera background after rendering opaques. /// class ARCameraAfterOpaquesRenderPass : ARCameraBackgroundRenderPass { /// /// Constructs the background render pass. /// public ARCameraAfterOpaquesRenderPass() { renderPassEvent = RenderPassEvent.AfterRenderingOpaques; } /// /// Configure the render pass by setting the render target and clear values. /// /// The command buffer for configuration. /// The descriptor of the target render texture. #pragma warning disable CS0672 public override void Configure(CommandBuffer commandBuffer, RenderTextureDescriptor renderTextureDescriptor) #pragma warning restore CS0672 { #pragma warning disable CS0618 ConfigureClear(ClearFlag.None, Color.clear); #pragma warning restore CS0618 } protected override XRCameraBackgroundRenderingMode renderingMode => XRCameraBackgroundRenderingMode.AfterOpaques; } #endif // URP_7_OR_NEWER } }