Добавить текстуру к данным кадра в URP
Чтобы передать текстуру от одного рендеринга к другому в рамках одного и того же графика рендеринга, можно добавить текстуру в кадровые данные.
Выполните следующие действия:
-
Создайте класс, который наследует
ContextItemи содержит поле текстурной ручки.Например:
public class MyCustomData : ContextItem { public TextureHandle textureToTransfer; } -
Вы должны выполнить
Reset()метод в своём классе, чтобы сбрасывать текстуру при сбросе кадра.Например:
public class MyCustomData : ContextItem { public TextureHandle textureToTransfer; public override void Reset() { textureToTransfer = TextureHandle.nullHandle; } } -
В вашем
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>(); } } Установите ручку текстуры на текстуру. Дополнительные сведения см. в Чтение или запись текстуры в проходе рендеринга в URP.
В последующем проходе рендеринга, в вашем методе
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")));
}
}
}