Version: 6000.3
语言: 中文
在 URP 的渲染通道中使用纹理
URP 中渲染图系统中的帧数据

在 URP 中的渲染通道之间传输纹理

您可以在渲染通道之间传输纹理,例如,如果您需要在一个渲染通道中创建纹理并在以后的渲染通道中读取该纹理。

使用以下方法在渲染通道之间传输纹理:

您还可以将纹理存储在渲染通道之外,例如作为TextureHandle可编写脚本的渲染器功能中。

如果需要使用,请确保纹理在多个帧中可用,或者多个相机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
请参阅术语表
可以访问它,请参阅将纹理导入渲染图系统。

向帧数据添加纹理

您可以向帧数据添加纹理,以便在以后的渲染通道中获取纹理。

按着这些次序:

  1. 创建一个继承ContextItem并包含纹理句柄字段。

    例如:

    public class MyCustomData : ContextItem {
        public TextureHandle textureToTransfer;
    }
    
  2. 您必须实现Reset()方法,以便在帧重置时重置纹理。

    例如:

    public class MyCustomData : ContextItem {
        public TextureHandle textureToTransfer;
    
        public override void Reset()
        {
            textureToTransfer = TextureHandle.nullHandle;
        }
    }    
    
  3. 在您的RecordRenderGraph方法,将类的实例添加到帧数据中。

    例如:

    public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
    {
        using (var builder = renderGraph.AddRasterRenderPass<PassData>("Get frame data", out var passData))
        {
            var customData = frameContext.Create<MyCustomData>();
        }
    }
    
  4. 将纹理手柄设置为纹理。

    例如:

    // Create texture properties that match the screen
    RenderTextureDescriptor textureProperties = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
    
    // Create the texture
    TextureHandle texture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "My texture", false);
    
    // Set the texture in the custom data instance
    customData.textureToTransfer = texture;
    

在以后的渲染通道中,在RecordRenderGraph方法,您可以获取自定义数据并获取纹理:

例如:

// Get the custom data
MyCustomData customData = frameData.Get<MyCustomData>();

// Get the texture
TextureHandle customTexture = customData.textureToTransfer;

有关帧数据的详细信息,请参阅使用帧数据

以下示例将CustomData包含纹理的类。第一个渲染通道将纹理清除为黄色,第二个渲染通道获取黄色纹理并在其上绘制三角形。要查看渲染通道,请打开帧调试器

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

public class AddOwnTextureToFrameData : ScriptableRendererFeature
{
    AddOwnTexturePass customPass1;
    DrawTrianglePass customPass2;

    public override void Create()
    {
        customPass1 = new AddOwnTexturePass();
        customPass2 = new DrawTrianglePass();

        customPass1.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
        customPass2.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(customPass1);
        renderer.EnqueuePass(customPass2);
    }
    
    // Create the first render pass, which creates a texture and adds it to the frame data
    class AddOwnTexturePass : ScriptableRenderPass
    {

        class PassData
        {
            internal TextureHandle copySourceTexture;
        }

        // Create the custom data class that contains the new texture
        public class CustomData : ContextItem {
            public TextureHandle newTextureForFrameData;

            public override void Reset()
            {
                newTextureForFrameData = TextureHandle.nullHandle;
            }
        }

        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
        {
            using (var builder = renderGraph.AddRasterRenderPass<PassData>("Create new texture", out var passData))
            {
                // Create a texture and set it as the render target
                RenderTextureDescriptor textureProperties = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
                TextureHandle texture = UniversalRenderer.CreateRenderGraphTexture(renderGraph, textureProperties, "My texture", false);
                CustomData customData = frameContext.Create<CustomData>();
                customData.newTextureForFrameData = texture;
                builder.SetRenderAttachment(texture, 0, AccessFlags.Write);
    
                builder.AllowPassCulling(false);

                builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
            }
        }

        static void ExecutePass(PassData data, RasterGraphContext context)
        {          
            // Clear the render target (the texture) to yellow
            context.cmd.ClearRenderTarget(true, true, Color.yellow);
        }
 
    }

    // Create the second render pass, which fetches the texture and writes to it
    class DrawTrianglePass : ScriptableRenderPass
    {

        class PassData
        {
            // No local pass data needed
        }      

        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
        {
            using (var builder = renderGraph.AddRasterRenderPass<PassData>("Fetch texture and draw triangle", out var passData))
            {                                
                // Fetch the yellow texture from the frame data and set it as the render target
                var customData = frameContext.Get<AddOwnTexturePass.CustomData>();
                var customTexture = customData.newTextureForFrameData;
                builder.SetRenderAttachment(customTexture, 0, AccessFlags.Write);

                builder.AllowPassCulling(false);

                builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
            }
        }

        static void ExecutePass(PassData data, RasterGraphContext context)
        {          
            // Generate a triangle mesh
            Mesh mesh = new Mesh();
            mesh.vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(0, 1, 0) };
            mesh.triangles = new int[] { 0, 1, 2 };
            
            // Draw a triangle to the render target (the yellow texture)
            context.cmd.DrawMesh(mesh, Matrix4x4.identity, new Material(Shader.Find("Universal Render Pipeline/Unlit")));
        }
    }
}

将纹理设置为全局纹理

如果您需要使用纹理作为着色器在 GPU 上运行的程序。更多信息
请参阅术语表
游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表
,您可以将纹理设置为全局纹理。全局纹理可用于所有着色器和渲染通道。

将纹理设置为全局纹理会使渲染速度变慢。请参阅 SetGlobalTexture

不要使用不安全的渲染通道,并且CommandBuffer.SetGlobal将纹理设置为全局纹理,因为它可能会导致错误。

要设置全局纹理,请在RecordRenderGraph方法,使用SetGlobalTextureAfterPass方法。

例如:

// Allocate a global shader texture called _GlobalTexture
private int globalTextureID = Shader.PropertyToID("_GlobalTexture")

using (var builder = renderGraph.AddRasterRenderPass<PassData>("MyPass", out var passData)){

    // Set a texture to the global texture
    builder.SetGlobalTextureAfterPass(texture, globalTextureID);
}

如果您尚未致电SetRenderFunc,您还必须添加一个空渲染函数。例如:

    builder.SetRenderFunc((PassData data, RasterGraphContext context) => { });

您现在可以:

  • 使用UseGlobalTexture()UseAllGlobalTextures()应用程序接口。
  • 在您中的任何材质上使用纹理场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
    请参阅术语表
    通过引用其nameID.

访问全局纹理

使用nameID纹理的(使用Shader.PropertyToId).确保根据通道使用全局纹理的方式设置适当的访问标志。

例如:

    class AccessGlobalTexturePass : ScriptableRenderPass
    {

        // The nameID of the globalTexture you want to use - which you have set in a previous pass
        private int globalTextureID = Shader.PropertyToID("_GlobalTexture")

        class PassData
        {
            // No local pass data needed
        }       

        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
        {
            using (var builder = renderGraph.AddRasterRenderPass<PassData>("Fetch texture and draw triangle", out var passData))
            {
                
                // Set the inputs and outputs of your pass
                // builder.SetRenderAttachment(/*...*/);
                // builder.UseTexture(/*...*/);

                // Use the global texture in this pass
                builder.UseGlobalTexture(globalTextureID, AccessFlags.Read);

                builder.SetRenderFunc((PassData data, RasterGraphContext context) => ExecutePass(data, context));
            }
        }

        static void ExecutePass(PassData data, RasterGraphContext context)
        {
            // ...
        }
    }

注意:你还可以将通道中的所有全局纹理与builder.UseAllGlobalTextures(true);而不是一个。然而,这会带来潜在的性能成本。

在 URP 的渲染通道中使用纹理
URP 中渲染图系统中的帧数据