123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- using System;
- using UnityEngine;
- using UnityEngine.Rendering.RenderGraphModule;
- using UnityEngine.Rendering;
- using UnityEngine.Rendering.Universal;
-
- // In this example it is shown how to use Multiple Render Targets (MRT) in RenderGraph using URP. This is useful when more than 4 channels of data (a single RGBA texture) needs to be written by a pass.
- public class MrtRendererFeature : ScriptableRendererFeature
- {
- // This pass is using MRT and will output to 3 different Render Targets.
- class MrtPass : ScriptableRenderPass
- {
- // The data we want to transfer to the render function after recording.
- class PassData
- {
- // Texture handle for the color input.
- public TextureHandle color;
- // Input texture name for the material.
- public string texName;
- // Material used for the MRT Pass.
- public Material material;
- }
-
- // Input texture name for the material.
- string m_texName;
- // Material used for the MRT Pass.
- Material m_Material;
- // RTHandle outputs for the MRT destinations.
- RTHandle[] m_RTs = new RTHandle[3];
- RenderTargetInfo[] m_RTInfos = new RenderTargetInfo[3];
-
- // Function used to transfer the material from the renderer feature to the render pass.
- public void Setup(string texName, Material material, RenderTexture[] renderTextures)
- {
- m_Material = material;
- m_texName = String.IsNullOrEmpty(texName) ? "_ColorTexture" : texName;
-
-
- //Create RTHandles from the RenderTextures if they have changed.
- for (int i = 0; i < 3; i++)
- {
- if (m_RTs[i] == null || m_RTs[i].rt != renderTextures[i])
- {
- m_RTs[i]?.Release();
- m_RTs[i] = RTHandles.Alloc(renderTextures[i], $"ChannelTexture[{i}]");
- m_RTInfos[i] = new RenderTargetInfo()
- {
- format = renderTextures[i].graphicsFormat,
- height = renderTextures[i].height,
- width = renderTextures[i].width,
- bindMS = renderTextures[i].bindTextureMS,
- msaaSamples = 1,
- volumeDepth = renderTextures[i].volumeDepth,
- };
- }
- }
- }
-
- // This function blits the whole screen for a given material.
- public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
- {
- var handles = new TextureHandle[3];
- // Imports the texture handles them in RenderGraph.
- for (int i = 0; i < 3; i++)
- {
- handles[i] = renderGraph.ImportTexture(m_RTs[i], m_RTInfos[i]);
- }
- // Starts the recording of the render graph pass given the name of the pass
- // and outputting the data used to pass data to the execution of the render function.
- using (var builder = renderGraph.AddRasterRenderPass<PassData>("MRT Pass", out var passData))
- {
- // Fetch the universal resource data to exstract the camera's color attachment.
- var resourceData = frameData.Get<UniversalResourceData>();
-
- // Fill in the pass data using by the render function.
- // Use the camera's color attachment as input.
- passData.color = resourceData.activeColorTexture;
- // Input Texture name for the material.
- passData.texName = m_texName;
- // Material used in the pass.
- passData.material = m_Material;
-
-
- // Sets input attachment.
- builder.UseTexture(passData.color);
- // Sets color attachments.
- for (int i = 0; i < 3; i++)
- {
- builder.SetRenderAttachment(handles[i], i);
- }
-
- // Sets the render function.
- builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext));
- }
- }
-
- // ExecutePass is the render function for each of the blit render graph recordings.
- // This is good practice to avoid using variables outside of the lambda it is called from.
- // It is static to avoid using member variables which could cause unintended behaviour.
- static void ExecutePass(PassData data, RasterGraphContext rgContext)
- {
- // Sets the input color texture to the name used in the MRTPass
- data.material.SetTexture(data.texName, data.color);
- // Draw the fullscreen triangle with the MRT shader.
- rgContext.cmd.DrawProcedural(Matrix4x4.identity, data.material, 0, MeshTopology.Triangles, 3);
- }
- }
-
- [Tooltip("The material used when making the MRT pass.")]
- public Material mrtMaterial;
- [Tooltip("Name to apply the camera's color attachment to for the given material.")]
- public string textureName = "_ColorTexture";
- [Tooltip("Render Textures to output the result to. Is has to have the size of 3.")]
- public RenderTexture[] renderTextures = new RenderTexture[3];
-
- MrtPass m_MrtPass;
-
- // Here you can create passes and do the initialization of them. This is called everytime serialization happens.
- public override void Create()
- {
- m_MrtPass = new MrtPass();
-
- // Configures where the render pass should be injected.
- m_MrtPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
- }
-
- // Here you can inject one or multiple render passes in the renderer.
- // This method is called when setting up the renderer once per-camera.
- public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
- {
- // Since they have the same RenderPassEvent the order matters when enqueueing them.
-
- // Early exit if there are no materials.
- if (mrtMaterial == null || renderTextures.Length != 3)
- {
- Debug.LogWarning("Skipping MRTPass because the material is null or render textures doesn't have a size of 3.");
- return;
- }
-
- foreach (var rt in renderTextures)
- {
- if (rt == null)
- {
- Debug.LogWarning("Skipping MRTPass because one of the render textures is null.");
- return;
- }
- }
-
- // Call the pass Setup function to transfer the RendererFeature settings to the RenderPass.
- m_MrtPass.Setup(textureName, mrtMaterial, renderTextures);
- renderer.EnqueuePass(m_MrtPass);
- }
- }
-
|