docs.unity3d.com
    显示 / 隐藏目录

    如何在 XR 中的单通道实例化渲染中执行全屏 blit

    本页上的示例说明如何创建自定义渲染器功能,用于在 XR 中的单通道实例化渲染中执行全屏 blit。

    示例概述

    此示例将实现以下解决方案:

    • 一个自定义渲染器功能调用一个自定义渲染通道。

    • 渲染通道将不透明纹理 blit 到当前渲染器的摄像机颜色目标。渲染通道使用命令缓冲区为双眼绘制全屏网格。

    此示例包括用于执行 GPU 端渲染的着色器。着色器使用 XR 采样器宏对颜色缓冲区进行采样。

    先决条件

    此示例需要满足以下条件:

    • Scriptable Render Pipeline Settings 属性引用一个 URP 资源 (Project Settings > Graphics > Scriptable Render Pipeline Settings)。

    创建示例场景和游戏对象

    要按照此示例中的步骤操作,请创建一个包含以下游戏对象的新场景:

    1. 创建一个立方体。确保可从主摄像机清楚看见该立方体。

    现在准备好了执行此示例中的步骤所需的场景。

    实现示例

    本节假设已按照创建示例场景和游戏对象一节所述创建了一个场景。

    请按照以下步骤创建具有自定义渲染通道的自定义渲染器功能。

    1. 创建新的 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);
          }
      }
      
    2. 创建新的 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);
          }
      }
      
    3. 创建执行 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
              }
          }
      }
      
    4. 将 ColorBlitRendererFeature 添加到通用渲染器资源。

      添加渲染器功能

      有关如何添加渲染器功能的信息,请参阅如何向渲染器添加渲染器功能页面。

      对于此示例,请将 Intensity 属性设置为 1.5。

    5. 要将此示例可视化,请将项目配置为使用 XR SDK。为项目添加 MockHMD XR 插件。将 Render Mode 属性设置为 Single Pass Instanced。

      配置 MockHMD

      Unity 会显示以下视图:

      最终的 Scene 视图和 Game 视图

    6. 进入运行模式。Unity 会显示颜色缓冲区。

      最终的运行模式视图

    此示例已完成。

    返回到顶部
    Copyright © 2023 Unity Technologies — 商标和使用条款
    • 法律条款
    • 隐私政策
    • Cookie
    • 不要出售或分享我的个人信息
    • Your Privacy Choices (Cookie Settings)