版本:Unity 6 (6000.0)
语言:英语
在 URP 中将相机的输出渲染到渲染纹理
URP 中的相机渲染顺序

在 URP 中创建渲染请求

要触发 相机一个组件,它会创建场景中特定视点的图像。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
查看 术语表
渲染到 渲染纹理一种特殊类型的纹理,它是在运行时创建和更新的。要使用它们,首先创建一个新的渲染纹理,并将其中一个相机指定为渲染到该纹理中。然后,你可以在材质中像使用普通纹理一样使用渲染纹理。更多信息
查看 术语表
在通用 渲染管线一系列操作,它将场景的内容获取并显示在屏幕上。Unity 允许你从预构建的渲染管线中选择,或编写你自己的渲染管线。更多信息
查看 术语表
(URP) 渲染循环之外,请在 C# 脚本中使用 SubmitRenderRequest API。

此示例演示如何使用渲染请求和回调来监控这些请求的进度。你可以在 示例代码 部分看到完整的代码示例。

从相机堆栈中渲染单个相机

要渲染单个相机而不考虑完整的相机堆栈,请使用 UniversalRenderPipeline.SingleCameraRequest API。请按照以下步骤操作

  1. 创建一个名为 SingleCameraRenderRequestExample 的 C# 脚本,并添加下面所示的 using 语句。

    using System.Collections;
    using UnityEngine;
    using UnityEngine.Rendering;
    using UnityEngine.Rendering.Universal;
    
    public class SingleCameraRenderRequestExample : MonoBehaviour
    {
    
    }
    
  2. 创建数组以存储你想要从其渲染和渲染到的相机和渲染纹理。

    public class SingleCameraRenderRequestExample : MonoBehaviour
    {
        public Camera[] cameras;
        public RenderTexture[] renderTextures;
    }
    
  3. Start 方法中,添加一个检查以确保 camerasrenderTextures 数组有效,并且包含正确的数据,然后再继续运行脚本。

    void Start()
    {
        // Make sure all data is valid before you start the component
        if (cameras == null || cameras.Length == 0 || renderTextures == null || cameras.Length != renderTextures.Length)
        {
            Debug.LogError("Invalid setup");
            return;
        }
    }
    
  4. SingleCameraRenderRequest 类中创建一个名为 SendSingleRenderRequests 的方法,其返回类型为 void

  5. SendSingleRenderRequests 方法中,添加一个 for 循环,它会像下面所示那样迭代 cameras 数组。

    void SendSingleRenderRequests()
    {
        for (int i = 0; i < cameras.Length; i++)
        {
    
        }
    }
    
  6. for 循环中,使用 UniversalRenderPipeline.SingleCameraRequest 类型创建一个名为 request 的变量中的渲染请求。然后,使用 RenderPipeline.SupportsRenderRequest 检查活动渲染管线是否支持此渲染请求类型。

  7. 如果活动渲染管线支持渲染请求,则将相机输出的目标设置为 renderTextures 数组中匹配的渲染纹理。然后,使用 RenderPipeline.SubmitRenderRequest 提交渲染请求。

    void SendSingleRenderRequests()
    {
        for (int i = 0; i < cameras.Length; i++)
        {
            UniversalRenderPipeline.SingleCameraRequest request =
                new UniversalRenderPipeline.SingleCameraRequest();
    
            // Check if the active render pipeline supports the render request
            if (RenderPipeline.SupportsRenderRequest(cameras[i], request))
            {
                // Set the destination of the camera output to the matching RenderTexture
                request.destination = renderTextures[i];
                    
                // Render the camera output to the RenderTexture synchronously
                // When this is complete, the RenderTexture in renderTextures[i] contains the scene rendered from the point
                // of view of the Camera in cameras[i]
                RenderPipeline.SubmitRenderRequest(cameras[i], request);
            }
        }
    }
    
  8. SendSingleRenderRequest 方法上方,创建一个名为 RenderSingleRequestNextFrameIEnumerator 接口。

  9. RenderSingleRequestNextFrame 中,等待主相机完成渲染,然后调用 SendSingleRenderRequest。等待帧结束,然后使用 StartCoroutine 在协程中重新启动 RenderSingleRequestNextFrame

    IEnumerator RenderSingleRequestNextFrame()
    {
        // Wait for the main camera to finish rendering
        yield return new WaitForEndOfFrame();
    
        // Enqueue one render request for each camera
        SendSingleRenderRequests();
    
        // Wait for the end of the frame
        yield return new WaitForEndOfFrame();
    
        // Restart the coroutine
        StartCoroutine(RenderSingleRequestNextFrame());
    }
    
  10. Start 方法中,使用 StartCoroutine 在协程中调用 RenderSingleRequestNextFrame

    void Start()
    {
        // Make sure all data is valid before you start the component
        if (cameras == null || cameras.Length == 0 || renderTextures == null || cameras.Length != renderTextures.Length)
        {
            Debug.LogError("Invalid setup");
            return;
        }
    
        // Start the asynchronous coroutine
        StartCoroutine(RenderSingleRequestNextFrame());
    }
    
  11. 在编辑器中,在你的 场景场景包含游戏环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你可以放置环境、障碍物和装饰,从本质上讲,你是在设计和构建游戏的各个部分。更多信息
    查看 术语表
    中创建一个空的 游戏对象Unity 场景中的基本对象,它可以表示角色、道具、场景、相机、航点等等。游戏对象的功能由附加到它的组件定义。更多信息
    查看 术语表
    ,并将 SingleCameraRenderRequestExample.cs 添加为一个 组件游戏对象的功能部件。游戏对象可以包含任意数量的组件。Unity 有许多内置的组件,你也可以通过编写从 MonoBehaviour 继承的脚本来自行创建组件。更多信息
    查看 术语表

  12. 检查器一个 Unity 窗口,用于显示有关当前选定游戏对象、资产或项目设置的信息,允许你检查和编辑这些值。更多信息
    查看 术语表
    窗口中,将你想要从中渲染的相机添加到 cameras 列表中,并将你想要渲染到的渲染纹理添加到 renderTextures 列表中。

注意:cameras 列表中的相机数量和 renderTextures 列表中的渲染纹理数量必须相同。

现在,当你进入播放模式时,你添加的相机将渲染到你添加的渲染纹理中。

检查相机何时完成渲染

要检查相机何时完成渲染,请使用 RenderPipelineManager API 中的任何回调。

以下示例使用 RenderPipelineManager.endContextRendering 回调。

  1. using System.Collections.Generic 添加到 SingleCameraRenderRequestExample.cs 文件的顶部。

  2. Start 方法的末尾,订阅 endContextRendering 回调。

    void Start()
    {
        // Make sure all data is valid before you start the component
        if (cameras == null || cameras.Length == 0 || renderTextures == null || cameras.Length != renderTextures.Length)
        {
            Debug.LogError("Invalid setup");
            return;
        }
    
        // Start the asynchronous coroutine
        StartCoroutine(RenderSingleRequestNextFrame());
            
        // Call a method called OnEndContextRendering when a camera finishes rendering
        RenderPipelineManager.endContextRendering += OnEndContextRendering;
    }
    
  3. 创建一个名为 OnEndContextRendering 的方法。当 endContextRendering 回调触发时,Unity 会运行此方法。

    void OnEndContextRendering(ScriptableRenderContext context, List<Camera> cameras)
    {
        // Create a log to show cameras have finished rendering
        Debug.Log("All cameras have finished rendering.");
    }
    
  4. 要取消 OnEndContextRendering 方法对 endContextRendering 回调的订阅,请向 SingleCameraRenderRequestExample 类添加一个 OnDestroy 方法。

    void OnDestroy()
    {
        // End the subscription to the callback
        RenderPipelineManager.endContextRendering -= OnEndContextRendering;
    }
    

此脚本现在与之前一样工作,但会向 控制台窗口一个 Unity 编辑器窗口,用于显示 Unity 或你的脚本生成的错误、警告和其他消息。更多信息
查看 术语表
记录一条消息,说明哪些相机已完成渲染。

示例代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class SingleCameraRenderRequest : MonoBehaviour
{
    public Camera[] cameras;
    public RenderTexture[] renderTextures;

    void Start()
    {
        // Make sure all data is valid before you start the component
        if (cameras == null || cameras.Length == 0 || renderTextures == null || cameras.Length != renderTextures.Length)
        {
            Debug.LogError("Invalid setup");
            return;
        }

        // Start the asynchronous coroutine
        StartCoroutine(RenderSingleRequestNextFrame());
        
        // Call a method called OnEndContextRendering when a camera finishes rendering
        RenderPipelineManager.endContextRendering += OnEndContextRendering;
    }

    void OnEndContextRendering(ScriptableRenderContext context, List<Camera> cameras)
    {
        // Create a log to show cameras have finished rendering
        Debug.Log("All cameras have finished rendering.");
    }

    void OnDestroy()
    {
        // End the subscription to the callback
        RenderPipelineManager.endContextRendering -= OnEndContextRendering;
    }

    IEnumerator RenderSingleRequestNextFrame()
    {
        // Wait for the main camera to finish rendering
        yield return new WaitForEndOfFrame();

        // Enqueue one render request for each camera
        SendSingleRenderRequests();

        // Wait for the end of the frame
        yield return new WaitForEndOfFrame();

        // Restart the coroutine
        StartCoroutine(RenderSingleRequestNextFrame());
    }

    void SendSingleRenderRequests()
    {
        for (int i = 0; i < cameras.Length; i++)
        {
            UniversalRenderPipeline.SingleCameraRequest request =
                new UniversalRenderPipeline.SingleCameraRequest();

            // Check if the active render pipeline supports the render request
            if (RenderPipeline.SupportsRenderRequest(cameras[i], request))
            {
                // Set the destination of the camera output to the matching RenderTexture
                request.destination = renderTextures[i];
                
                // Render the camera output to the RenderTexture synchronously
                RenderPipeline.SubmitRenderRequest(cameras[i], request);

                // At this point, the RenderTexture in renderTextures[i] contains the scene rendered from the point
                // of view of the Camera in cameras[i]
            }
        }
    }
}
在 URP 中将相机的输出渲染到渲染纹理
URP 中的相机渲染顺序