Ingen beskrivning
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnsafePassRenderFeature.cs 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using UnityEngine;
  2. using UnityEngine.Rendering.RenderGraphModule;
  3. using UnityEngine.Rendering;
  4. using UnityEngine.Rendering.Universal;
  5. // This example copies the active color texture to a new texture, it then downsamples the source texture twice. This example is for API demonstrative purposes,
  6. // so the new textures are not used anywhere else in the frame, you can use the frame debugger to verify their contents.
  7. // The key concept of this example, is the UnsafePass usage: these type of passes are unsafe and allow using command like SetRenderTarget() which are
  8. // not compatible with RasterRenderPasses. Using UnsafePasses means that the RenderGraph won't try to optimize the pass by merging it inside a NativeRenderPass.
  9. // In some cases using UnsafePasses makes sense, if for example we know that a set of adjacent passes are not mergeable, so this can optimize the RenderGraph
  10. // compiling times, on top of simplifying the multiple passes setup.
  11. public class UnsafePassRenderFeature : ScriptableRendererFeature
  12. {
  13. class UnsafePass : ScriptableRenderPass
  14. {
  15. // This class stores the data needed by the pass, passed as parameter to the delegate function that executes the pass
  16. private class PassData
  17. {
  18. internal TextureHandle src;
  19. internal TextureHandle dest;
  20. internal TextureHandle destHalf;
  21. internal TextureHandle destQuarter;
  22. }
  23. // This static method is used to execute the pass and passed as the RenderFunc delegate to the RenderGraph render pass
  24. static void ExecutePass(PassData data, UnsafeGraphContext context)
  25. {
  26. // Set manually the RenderTarget for each blit. Each SetRenderTarget call would require a separate RasterCommandPass if we wanted
  27. // to setup RenderGraph for merging passes when possible.
  28. // In this case we know that these 3 subpasses are not compatible for merging, because RenderTargets have different dimensions,
  29. // so we simplify our code to use an unsafe pass, also saving RenderGraph processing time.
  30. // copy the current scene color
  31. CommandBuffer unsafeCmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
  32. context.cmd.SetRenderTarget(data.dest);
  33. Blitter.BlitTexture(unsafeCmd, data.src, new Vector4(1, 1, 0, 0), 0, false);
  34. // downscale x2
  35. context.cmd.SetRenderTarget(data.destHalf);
  36. Blitter.BlitTexture(unsafeCmd, data.dest, new Vector4(1, 1, 0, 0), 0, false);
  37. context.cmd.SetRenderTarget(data.destQuarter);
  38. Blitter.BlitTexture(unsafeCmd, data.destHalf, new Vector4(1, 1, 0, 0), 0, false);
  39. // upscale x2
  40. context.cmd.SetRenderTarget(data.destHalf);
  41. Blitter.BlitTexture(unsafeCmd, data.destQuarter, new Vector4(1, 1, 0, 0), 0, false);
  42. context.cmd.SetRenderTarget(data.dest);
  43. Blitter.BlitTexture(unsafeCmd, data.destHalf, new Vector4(1, 1, 0, 0), 0, false);
  44. }
  45. // This is where the renderGraph handle can be accessed.
  46. // Each ScriptableRenderPass can use the RenderGraph handle to add multiple render passes to the render graph
  47. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  48. {
  49. string passName = "Unsafe Pass";
  50. // add a raster render pass to the render graph, specifying the name and the data type that will be passed to the ExecutePass function
  51. using (var builder = renderGraph.AddUnsafePass<PassData>(passName, out var passData))
  52. {
  53. // UniversalResourceData contains all the texture handles used by the renderer, including the active color and depth textures
  54. // The active color and depth textures are the main color and depth buffers that the camera renders into
  55. UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
  56. // Fill up the passData with the data needed by the pass
  57. // Get the active color texture through the frame data, and set it as the source texture for the blit
  58. passData.src = resourceData.activeColorTexture;
  59. // The destination textures are created here,
  60. // the texture is created with the same dimensions as the active color texture, but with no depth buffer, being a copy of the color texture
  61. // we also disable MSAA as we don't need multisampled textures for this sample
  62. // the other two textures halve the resolution of the previous one
  63. UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
  64. RenderTextureDescriptor desc = cameraData.cameraTargetDescriptor;
  65. desc.msaaSamples = 1;
  66. desc.depthBufferBits = 0;
  67. TextureHandle destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "UnsafeTexture", false);
  68. desc.width /= 2;
  69. desc.height /= 2;
  70. TextureHandle destinationHalf = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "UnsafeTexture2", false);
  71. desc.width /= 2;
  72. desc.height /= 2;
  73. TextureHandle destinationQuarter = UniversalRenderer.CreateRenderGraphTexture(renderGraph, desc, "UnsafeTexture3", false);
  74. passData.dest = destination;
  75. passData.destHalf = destinationHalf;
  76. passData.destQuarter = destinationQuarter;
  77. // We declare the src texture as an input dependency to this pass, via UseTexture()
  78. builder.UseTexture(passData.src);
  79. // UnsafePasses don't setup the outputs using UseTextureFragment/UseTextureFragmentDepth, you should specify your writes with UseTexture instead
  80. builder.UseTexture(passData.dest, AccessFlags.Write);
  81. builder.UseTexture(passData.destHalf, AccessFlags.Write);
  82. builder.UseTexture(passData.destQuarter, AccessFlags.Write);
  83. // We disable culling for this pass for the demonstrative purpose of this sample, as normally this pass would be culled,
  84. // since the destination texture is not used anywhere else
  85. builder.AllowPassCulling(false);
  86. // Assign the ExecutePass function to the render pass delegate, which will be called by the render graph when executing the pass
  87. builder.SetRenderFunc((PassData data, UnsafeGraphContext context) => ExecutePass(data, context));
  88. }
  89. }
  90. }
  91. UnsafePass m_UnsafePass;
  92. /// <inheritdoc/>
  93. public override void Create()
  94. {
  95. m_UnsafePass = new UnsafePass();
  96. // Configures where the render pass should be injected.
  97. m_UnsafePass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
  98. }
  99. // Here you can inject one or multiple render passes in the renderer.
  100. // This method is called when setting up the renderer once per-camera.
  101. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  102. {
  103. renderer.EnqueuePass(m_UnsafePass);
  104. }
  105. }