Version: 6000.3
语言: 中文
在 URP 中获取前一帧的数据
在 URP 中从 GPU 内存中获取当前帧缓冲区

将纹理添加到相机历史记录中

要将您自己的纹理添加到相机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
请参阅术语表
历史记录并读取后续帧中的数据,创建摄像机历史记录类型以存储帧之间的纹理。

创建相机历史记录类型

按着这些次序:

  1. 创建一个继承自CameraHistoryItem.例如:

    public class ExampleHistoryType : CameraHistoryItem {
        ...
    }
    
  2. 在类中,添加相机历史记录系统的 id。例如:

        private int uniqueId;
    

    id 表示一个纹理的完整历史记录,包括当前和前一帧。

    您还可以添加所需的任何其他数据,例如需要在帧之间存储的纹理描述符。

  3. 覆盖OnCreate方法。在该方法中,调用OnCreate方法,并生成唯一 ID。例如:

    public override void OnCreate(BufferedRTHandleSystem owner, uint typeId)
    {
        // Call the OnCreate method of the parent class
        base.OnCreate(owner, typeId);
    
        // Generate the unique id
        uniqueId = MakeId(0);
    }
    
  4. 为当前和以前的纹理创建公共属性,以便渲染通道可以访问它们。例如:

    public RTHandle currentTexture => GetCurrentFrameRT(uniqueId);
    public RTHandle previousTexture => GetPreviousFrameRT(uniqueId);
    
  5. 为纹理分配内存。例如:

    // Allocate 2 textures using a texture descriptor, assign them to the uniqueId, and give them a name.
    AllocHistoryFrameRT(uniqueId, 2, ref textureDescriptor, "ExampleHistoryTexture");
    
  6. 实现Reset方法,以便在摄像机历史系统重置类型时释放历史纹理。例如:

    public override void Reset()
    {
        ReleaseHistoryFrameRT(uniqueId);
    }
    

如果渲染通道写入具有不同大小或格式的纹理,您可能还需要在每一帧重新分配内存。

写入纹理

要写入您创建的纹理,请按照下列步骤作:

  1. 请求访问ScriptableRenderPass类,请使用RequestAccessAPI 与相机历史记录类型。例如:

    cameraData.historyManager.RequestAccess<ExampleHistoryType>();
    
  2. 获取当前帧的纹理以进行写入,并将其转换为渲染图系统可以使用的句柄。例如:

    // Get the textures 
    ExampleHistoryType history = cameraData.historyManager.GetHistoryForWrite<ExampleHistoryType>();
    
    // Get the texture for the current frame
    RTHandle historyTexture = history?.currentTexture;
    
    // Convert the texture into a handle the render graph system can use
    historyTexture = renderGraph.ImportTexture(historyTexture);
    

然后,你可以写入渲染通道中的纹理。有关更多信息,请参阅使用纹理

从纹理中读取

要从纹理中读取,请使用RequestAccessAPI 与您创建的相机历史记录类型。

在读取纹理之前,必须先写入纹理。

有关更多信息,请参阅从前一帧获取数据

例子

以下是相机历史记录类型的示例。

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleHistoryType : CameraHistoryItem
{
    private int m_Id;

    // Add a descriptor for the size and format of the texture.
    private RenderTextureDescriptor m_Descriptor;

    // Add a hash key to track changes to the descriptor.
    private Hash128 m_DescKey;

    public override void OnCreate(BufferedRTHandleSystem owner, uint typeId)
    {
        base.OnCreate(owner, typeId);
        m_Id = MakeId(0);
    }

    // Release the history GPU resources (textures) when the camera history system resets the type.
    public override void Reset()
    {
        ReleaseHistoryFrameRT(m_Id);
    }

    public RTHandle currentTexture => GetCurrentFrameRT(m_Id);
    public RTHandle previousTexture => GetPreviousFrameRT(m_Id);

    // The render pass calls the Update method every frame, to initialize, update, or dispose of the textures.
    public void Update(RenderTextureDescriptor textureDescriptor)
    {
        // Dispose of the textures if the memory needs to be reallocated.
        if (m_DescKey != Hash128.Compute(ref textureDescriptor))
            ReleaseHistoryFrameRT(m_Id);

        // Allocate the memory for the textures if it's not already allocated.
        if (currentTexture == null)
        {
            AllocHistoryFrameRT(m_Id, 2, ref textureDescriptor, "HistoryTexture");

            // Store the descriptor and hash key for future changes.
            m_Descriptor = textureDescriptor;
            m_DescKey = Hash128.Compute(ref textureDescriptor);
        }
    }
}

下面是写入纹理的渲染通道示例。你可以将URP材质用作material,以及一个可编写脚本的渲染器功能,用于将渲染通道注入到渲染管线 获取场景内容并将其显示在屏幕上的一系列作。Unity 允许您从预构建的渲染管道中进行选择,或编写自己的渲染管道。更多信息
请参阅术语表
.

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;

class WriteToHistoryTexture : ScriptableRenderPass
{
    // Property for the custom material that writes to the history texture.
    public Material m_Material;

    private class PassData
    {
        internal Material material;
    }

    public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
    {
        var cameraData = frameData.Get<UniversalCameraData>();

        // Request access to the history texture.
        cameraData.historyManager.RequestAccess<ExampleHistoryType>();
        var history = cameraData.historyManager.GetHistoryForWrite<ExampleHistoryType>();

        if (history != null)
        {
            // Make the history a color-only texture to match the camera target.
            var historyDesc = cameraData.cameraTargetDescriptor;
            historyDesc.depthBufferBits = 0;
            historyDesc.msaaSamples = 1;
            
            // Call the Update method of the camera history type.
            history.Update(historyDesc);

            using (var builder = renderGraph.AddRasterRenderPass<PassData>("Write to history texture", out var passData))
            {
                UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
                RTHandle historyTexture = history?.currentTexture;

                // Set the render graph to render to the history texture.
                builder.SetRenderAttachment(renderGraph.ImportTexture(historyTexture), 0, AccessFlags.Write);

                passData.material = m_Material;

                builder.SetRenderFunc(static (PassData data, RasterGraphContext context) =>
                {
                    // Draw a triangle to the history texture
                    context.cmd.DrawProcedural(Matrix4x4.identity, data.material, 0, MeshTopology.Triangles, 3, 1);
                });
            }
        }
    }
}

其他资源

在 URP 中获取前一帧的数据
在 URP 中从 GPU 内存中获取当前帧缓冲区