렌더 패스 간에 텍스처를 전송할 수 있습니다. 하나의 렌더 패스에서 텍스처를 생성하고 이후의 렌더 패스에서 해당 텍스처를 읽어야 하는 경우가 이에 해당합니다.
렌더 패스 간에 텍스처를 전송하는 방법은 다음과 같습니다.
렌더 패스 외부에도 텍스처를 저장할 수 있습니다(예: 스크립터블 렌더러 기능의 TextureHandle).
하나의 텍스처를 여러 프레임에서 사용할 수 있는지 또는 여러 카메라가 해당 텍스처에 액세스할 수 있는지 확인해야 하는 경우, 텍스처를 렌더 그래프 시스템에 임포트를 참조하십시오.
이후의 렌더 패스에서 텍스처를 가져올 수 있도록 프레임 데이터에 텍스처를 추가할 수 있습니다.
방법은 다음과 같습니다.
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))
{
UniversalResourceData resourceData = frameContext.Get<UniversalResourceData>();
var customData = contextData.Create<MyCustomData>();
}
}
텍스처의 텍스처 핸들을 설정합니다.
예시:
// 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 fetchedData = 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")));
}
}
}
텍스처를 게임 오브젝트의 셰이더에 대한 입력으로 사용해야 하는 경우, 텍스처를 전역 텍스처로 설정할 수 있습니다. 전역 텍스처는 모든 셰이더와 렌더 패스에서 사용할 수 있습니다.
텍스처를 전역 텍스처로 설정하면 렌더링 속도가 느려질 수 있습니다. 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() API를 사용하여 다른 렌더 패스에서 텍스처에 액세스합니다.