using System;
using UnityEngine;
using UnityEngine.Rendering;
#if MODULE_URP_ENABLED
using UnityEngine.Rendering.Universal;
#elif MODULE_LWRP_ENABLED
using UnityEngine.Rendering.LWRP;
#else
using ScriptableRendererFeature = UnityEngine.ScriptableObject;
#endif
namespace UnityEngine.XR.ARFoundation
{
///
/// A render feature for rendering the camera background for AR devies.
///
public class ARBackgroundRendererFeature : ScriptableRendererFeature
{
#if MODULE_URP_ENABLED || MODULE_LWRP_ENABLED
///
/// The scriptable render pass to be added to the renderer when the camera background is to be rendered.
///
CustomRenderPass m_ScriptablePass;
///
/// The mesh for rendering the background shader.
///
Mesh m_BackgroundMesh;
///
/// Create the scriptable render pass.
///
public override void Create()
{
#if !UNITY_EDITOR
m_ScriptablePass = new CustomRenderPass(RenderPassEvent.BeforeRenderingOpaques);
m_BackgroundMesh = new Mesh();
m_BackgroundMesh.vertices = new Vector3[]
{
new Vector3(0f, 0f, 0.1f),
new Vector3(0f, 1f, 0.1f),
new Vector3(1f, 1f, 0.1f),
new Vector3(1f, 0f, 0.1f),
};
m_BackgroundMesh.uv = new Vector2[]
{
new Vector2(0f, 0f),
new Vector2(0f, 1f),
new Vector2(1f, 1f),
new Vector2(1f, 0f),
};
m_BackgroundMesh.triangles = new int[] {0, 1, 2, 0, 2, 3};
#endif // !UNITY_EDITOR
}
///
/// 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)
{
#if !UNITY_EDITOR
Camera currentCamera = renderingData.cameraData.camera;
if ((currentCamera != null) && (currentCamera.cameraType == CameraType.Game))
{
ARCameraBackground cameraBackground = currentCamera.gameObject.GetComponent();
if ((cameraBackground != null) && cameraBackground.backgroundRenderingEnabled
&& (cameraBackground.material != null))
{
bool invertCulling = cameraBackground.GetComponent()?.subsystem?.invertCulling ?? false;
m_ScriptablePass.Setup(m_BackgroundMesh, cameraBackground.material, invertCulling);
renderer.EnqueuePass(m_ScriptablePass);
}
}
#endif // !UNITY_EDITOR
}
///
/// The custom render pass to render the camera background.
///
class CustomRenderPass : ScriptableRenderPass
{
///
/// The name for the custom render pass which will display in graphics debugging tools.
///
const string k_CustomRenderPassName = "AR Background Pass (URP)";
///
/// The orthogonal projection matrix for the background rendering.
///
static readonly Matrix4x4 k_BackgroundOrthoProjection = Matrix4x4.Ortho(0f, 1f, 0f, 1f, -0.1f, 9.9f);
///
/// The mesh for rendering the background material.
///
Mesh m_BackgroundMesh;
///
/// The material used for rendering the device background using the camera video texture and potentially
/// other device-specific properties and textures.
///
Material m_BackgroundMaterial;
///
/// Whether the culling mode should be inverted.
/// ([CommandBuffer.SetInvertCulling](https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetInvertCulling.html)).
///
bool m_InvertCulling;
///
/// Constructs the background render pass.
///
/// The render pass event when this pass should be rendered.
public CustomRenderPass(RenderPassEvent renderPassEvent)
{
this.renderPassEvent = renderPassEvent;
}
///
/// Set up the background render pass.
///
/// The mesh used for rendering the device background.
/// The material used for rendering the device background.
/// Whether the culling mode should be inverted.
public void Setup(Mesh backgroundMesh, Material backgroundMaterial, bool invertCulling)
{
m_BackgroundMesh = backgroundMesh;
m_BackgroundMaterial = backgroundMaterial;
m_InvertCulling = invertCulling;
}
///
/// Configure the render pass by configuring the render target and clear values.
///
/// The command buffer for configuration.
/// The descriptor of the target render texture.
public override void Configure(CommandBuffer commandBuffer, RenderTextureDescriptor renderTextureDescriptor)
{
ConfigureClear(ClearFlag.Depth, Color.clear);
}
///
/// Execute the commands to render the camera background.
///
/// The render context for executing the render commands.
/// Additional rendering data about the current state of rendering.
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get(k_CustomRenderPassName);
cmd.BeginSample(k_CustomRenderPassName);
ARCameraBackground.AddBeforeBackgroundRenderHandler(cmd);
cmd.SetInvertCulling(m_InvertCulling);
cmd.SetViewProjectionMatrices(Matrix4x4.identity, k_BackgroundOrthoProjection);
cmd.DrawMesh(m_BackgroundMesh, Matrix4x4.identity, m_BackgroundMaterial);
cmd.SetViewProjectionMatrices(renderingData.cameraData.camera.worldToCameraMatrix,
renderingData.cameraData.camera.projectionMatrix);
cmd.EndSample(k_CustomRenderPassName);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
///
/// Clean up any resources for the render pass.
///
/// The command buffer for frame cleanup.
public override void FrameCleanup(CommandBuffer commandBuffer)
{
}
}
#endif // MODULE_URP_ENABLED || MODULE_LWRP_ENABLED
}
}