如何在 XR 中的单通道实例化渲染中执行全屏 blit
本页上的示例说明如何创建自定义渲染器功能,用于在 XR 中的单通道实例化渲染中执行全屏 blit。
示例概述
此示例将实现以下解决方案:
此示例包括用于执行 GPU 端渲染的着色器。着色器使用 XR 采样器宏对颜色缓冲区进行采样。
先决条件
此示例需要满足以下条件:
- Scriptable Render Pipeline Settings 属性引用一个 URP 资源 (Project Settings > Graphics > Scriptable Render Pipeline Settings)。
创建示例场景和游戏对象
要按照此示例中的步骤操作,请创建一个包含以下游戏对象的新场景:
创建一个立方体。确保可从主摄像机清楚看见该立方体。
现在准备好了执行此示例中的步骤所需的场景。
实现示例
本节假设已按照创建示例场景和游戏对象一节所述创建了一个场景。
创建新的 C# 脚本,将其命名为
ColorBlitRendererFeature.cs
。此脚本实现自定义渲染器功能。using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; internal class ColorBlitRendererFeature : ScriptableRendererFeature { public Shader m_Shader; public float m_Intensity; Material m_Material; ColorBlitPass m_RenderPass = null; public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (renderingData.cameraData.cameraType == CameraType.Game) { //使用 ScriptableRenderPassInput.Color 参数调用 ConfigureInput 将确保不透明纹理可供渲染通道使用 m_RenderPass.ConfigureInput(ScriptableRenderPassInput.Color); m_RenderPass.SetTarget(renderer.cameraColorTarget, m_Intensity); renderer.EnqueuePass(m_RenderPass); } } public override void Create() { if (m_Shader != null) m_Material = new Material(m_Shader); m_RenderPass = new ColorBlitPass(m_Material); } protected override void Dispose(bool disposing) { CoreUtils.Destroy(m_Material); } }
创建新的 C# 脚本,将其命名为
ColorBlitPass.cs
。此脚本实现自定义渲染通道以执行自定义 blit 绘制调用。该渲染通道使用
cmd.DrawMesh
方法来绘制全屏四边形并执行 blit 操作。注意:不要在 URP XR 项目中使用
cmd.Blit
方法,因为该方法与 URP XR 集成功能存在兼容性问题。使用cmd.Blit
可能会隐式启用或禁用 XR 着色器关键字,而这会破坏 XR SPI 渲染。using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; internal class ColorBlitPass : ScriptableRenderPass { ProfilingSampler m_ProfilingSampler = new ProfilingSampler("ColorBlit"); Material m_Material; RenderTargetIdentifier m_CameraColorTarget; float m_Intensity; public ColorBlitPass(Material material) { m_Material = material; renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; } public void SetTarget(RenderTargetIdentifier colorHandle, float intensity) { m_CameraColorTarget = colorHandle; m_Intensity = intensity; } public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { ConfigureTarget(new RenderTargetIdentifier(m_CameraColorTarget, 0, CubemapFace.Unknown, -1)); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { var camera = renderingData.cameraData.camera; if (camera.cameraType != CameraType.Game) return; if (m_Material == null) return; CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, m_ProfilingSampler)) { m_Material.SetFloat("_Intensity", m_Intensity); cmd.SetRenderTarget(new RenderTargetIdentifier(m_CameraColorTarget, 0, CubemapFace.Unknown, -1)); //RenderingUtils.fullscreenMesh 参数指定要绘制的网格是四边形。 cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_Material); } context.ExecuteCommandBuffer(cmd); cmd.Clear(); CommandBufferPool.Release(cmd); } }
创建执行 blit 操作的着色器。将着色器文件命名为
ColorBlit.shader
。顶点函数将输出全屏四边形位置。片元函数对颜色缓冲区进行采样,并将color * float4(0, _Intensity, 0, 1)
值返回给渲染目标。Shader "ColorBlit" { SubShader { Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"} LOD 100 ZWrite Off Cull Off Pass { Name "ColorBlitPass" HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionHCS : POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_OUTPUT_STEREO }; Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); // 注意:该通道已经在裁剪空间中设置了 // 一个网格,这就是为什么只输出顶点位置 // 就足够了 output.positionCS = float4(input.positionHCS.xyz, 1.0); #if UNITY_UV_STARTS_AT_TOP output.positionCS.y *= -1; #endif output.uv = input.uv; return output; } TEXTURE2D_X(_CameraOpaqueTexture); SAMPLER(sampler_CameraOpaqueTexture); float _Intensity; half4 frag (Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float4 color = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, input.uv); return color * float4(0, _Intensity, 0, 1); } ENDHLSL } } }
将
ColorBlitRendererFeature
添加到通用渲染器资源。有关如何添加渲染器功能的信息,请参阅如何向渲染器添加渲染器功能页面。
对于此示例,请将 Intensity 属性设置为 1.5。
要将此示例可视化,请将项目配置为使用 XR SDK。为项目添加 MockHMD XR 插件。将 Render Mode 属性设置为 Single Pass Instanced。
Unity 会显示以下视图:
进入运行模式。Unity 会显示颜色缓冲区。
此示例已完成。