Unity 6.3
0 онлайн 96 гостей 3 в системе
Вход
Конвейеры отображения Шаг 89 из 129

Добавить текстуру к данным кадра в URP

Чтобы передать текстуру от одного рендеринга к другому в рамках одного и того же графика рендеринга, можно добавить текстуру в кадровые данные.

Выполните следующие действия:

  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. Установите ручку текстуры на текстуру. Дополнительные сведения см. в Чтение или запись текстуры в проходе рендеринга в URP.

  5. В последующем проходе рендеринга, в вашем методе RecordRenderGraph, вы можете получить свои пользовательские данные и извлечь текстуру:

Например:

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

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

Дополнительные сведения о данных кадра см. в Использование данных кадра.

Пример

В следующем примере добавляется CustomData класс с текстурой. Первый проход рендеринга очищает текстуру в жёлтый цвет, а второй берёт эту жёлтую текстуру и рисует на ней треугольник. Чтобы увидеть проходы рендеринга, откройте Frame Debugger.

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
                UniversalResourceData frameData = frameContext.Get<UniversalResourceData>();
                TextureDesc textureDesc = frameData.activeColorTexture.GetDescriptor(renderGraph);
                textureDesc.msaaSamples = MSAASamples.None;
                TextureHandle texture = renderGraph.CreateTexture(textureDesc);
                CustomData customData = frameContext.Create<CustomData>();
                customData.newTextureForFrameData = texture;
                builder.SetRenderAttachment(texture, 0, AccessFlags.Write);
    
                // Make sure the render graph system keeps the render pass, even if it's not used in the final frame.
                // Don't use this in production code, because it prevents the render graph system from removing the render pass if it's not needed.
                builder.AllowPassCulling(false);

                builder.SetRenderFunc(static (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);

                // Make sure the render graph system keeps the render pass, even if it's not used in the final frame.
                // Don't use this in production code, because it prevents the render graph system from removing the render pass if it's not needed.
                builder.AllowPassCulling(false);

                builder.SetRenderFunc(static (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")));
        }
    }
}