暫無描述
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.

TextureRefRendererFeature.cs 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using UnityEngine;
  2. using UnityEngine.Rendering.RenderGraphModule;
  3. using UnityEngine.Rendering;
  4. using UnityEngine.Rendering.Universal;
  5. // In this example we will create a texture reference ContextItem in frameData to hold a reference
  6. // used by furture passes. This is usefull to avoid additional blit operations copying back and forth
  7. // to the cameras color attachment. Instead of copying it back after the blit operation we can instead
  8. // update the reference to the blit destination and use that for future passes.
  9. public class TextureRefRendererFeature : ScriptableRendererFeature
  10. {
  11. // The ContextItem used to store the texture reference at.
  12. public class TexRefData : ContextItem
  13. {
  14. // The texture reference variable.
  15. public TextureHandle texture = TextureHandle.nullHandle;
  16. // Reset function required by ContextItem. It should reset all variables not carried
  17. // over to next frame.
  18. public override void Reset()
  19. {
  20. // We should always reset texture handles since they are only vaild for the current frame.
  21. texture = TextureHandle.nullHandle;
  22. }
  23. }
  24. // This pass updates the reference when making a blit operation using a material and the camera's color attachment.
  25. class UpdateRefPass : ScriptableRenderPass
  26. {
  27. // The data we want to transfer to the render function after recording.
  28. class PassData
  29. {
  30. // For the blit operation we will need the source and destination of the color attachments.
  31. public TextureHandle source;
  32. public TextureHandle destination;
  33. // We will also need a material to transform the color attachment when making a blit operation.
  34. public Material material;
  35. }
  36. // Scale bias is used to blit from source to distination given a 2d scale in the x and y parameters
  37. // and an offset in the z and w parameters.
  38. static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f);
  39. // Material used in the blit operation.
  40. Material[] m_DisplayMaterials;
  41. // Function used to transfer the material from the renderer feature to the render pass.
  42. public void Setup(Material[] materials)
  43. {
  44. m_DisplayMaterials = materials;
  45. }
  46. // This function blits the whole screen for a given material.
  47. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  48. {
  49. foreach (var mat in m_DisplayMaterials)
  50. {
  51. // Skip material if it is null.
  52. if (mat == null)
  53. {
  54. Debug.LogWarning($"Skipping render pass for unassigned material.");
  55. continue;
  56. }
  57. // Starts the recording of the render graph pass given the name of the pass
  58. // and outputting the data used to pass data to the execution of the render function.
  59. using (var builder = renderGraph.AddRasterRenderPass<PassData>($"UpdateRefPass_{mat.name}", out var passData))
  60. {
  61. var texRefExist = frameData.Contains<TexRefData>();
  62. var texRef = frameData.GetOrCreate<TexRefData>();
  63. // First time running this pass. Fetch ref from active color buffer.
  64. if (!texRefExist)
  65. {
  66. var resourceData = frameData.Get<UniversalResourceData>();
  67. // For this first occurence we would like
  68. texRef.texture = resourceData.activeColorTexture;
  69. }
  70. // Setup the descriptor we use for BlitData. We should use the camera target's descriptor as a start.
  71. var cameraData = frameData.Get<UniversalCameraData>();
  72. var descriptor = cameraData.cameraTargetDescriptor;
  73. // We disable MSAA for the blit operations.
  74. descriptor.msaaSamples = 1;
  75. // We disable the depth buffer, since we are only makeing transformations to the color buffer.
  76. descriptor.depthBufferBits = 0;
  77. // Fill in the pass data using by the render function.
  78. // Use the old reference from TexRefData.
  79. passData.source = texRef.texture;
  80. // Create a new temporary texture to keep the blit result.
  81. passData.destination = UniversalRenderer.CreateRenderGraphTexture(renderGraph, descriptor, $"BlitMaterialRefTex_{mat.name}", false);
  82. // Material used in the blit operation.
  83. passData.material = mat;
  84. // Update the texture reference to the blit destination.
  85. texRef.texture = passData.destination;
  86. // Sets input attachment.
  87. builder.UseTexture(passData.source);
  88. // Sets color attachment 0.
  89. builder.SetRenderAttachment(passData.destination, 0);
  90. // Sets the render function.
  91. builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext));
  92. }
  93. }
  94. }
  95. // ExecutePass is the render function for each of the blit render graph recordings.
  96. // This is good practice to avoid using variables outside of the lambda it is called from.
  97. // It is static to avoid using member variables which could cause unintended behaviour.
  98. static void ExecutePass(PassData data, RasterGraphContext rgContext)
  99. {
  100. Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, data.material, 0);
  101. }
  102. }
  103. // After updating the reference we will need to use the result copying it back to camera's
  104. // color attachment.
  105. class CopyBackRefPass : ScriptableRenderPass
  106. {
  107. // Scale bias is used to blit from source to distination given a 2d scale in the x and y parameters
  108. // and an offset in the z and w parameters.
  109. static Vector4 scaleBias = new Vector4(1f, 1f, 0f, 0f);
  110. // The data we want to transfer to the render function after recording.
  111. class PassData
  112. {
  113. // For the blit operation we will need the source and destination of the color attachments.
  114. // We don't need a material for the blit operation since we only want to copy it back
  115. // without any transformations to the color attachment.
  116. public TextureHandle source;
  117. public TextureHandle destination;
  118. }
  119. // This function blits the reference back to the camera's color attachment.
  120. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  121. {
  122. // Early exit if TexRefData doesn't exist within frameData since where is nothing to copy back.
  123. if (!frameData.Contains<TexRefData>()) return;
  124. // Starts the recording of the render graph pass given the name of the pass
  125. // and outputting the data used to pass data to the execution of the render function.
  126. using (var builder = renderGraph.AddRasterRenderPass<PassData>("Copy Back Pass", out var passData))
  127. {
  128. // Fetch UniversalResourceData to retrive the camera's active color texture.
  129. var resourceData = frameData.Get<UniversalResourceData>();
  130. // Fetch TexRefData to retrive the texture reference.
  131. var texRef = frameData.Get<TexRefData>();
  132. // Update the pass data.
  133. passData.source = texRef.texture;
  134. passData.destination = resourceData.activeColorTexture;
  135. // Sets input attachment.
  136. builder.UseTexture(passData.source);
  137. // Sets color attachment 0.
  138. builder.SetRenderAttachment(passData.destination, 0);
  139. // Sets the render function.
  140. builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) => ExecutePass(data, rgContext));
  141. }
  142. }
  143. // ExecutePass is the render function for each of the blit render graph recordings.
  144. // This is good practice to avoid using variables outside of the lambda it is called from.
  145. // It is static to avoid using member variables which could cause unintended behaviour.
  146. static void ExecutePass(PassData data, RasterGraphContext rgContext)
  147. {
  148. // Calling blit without a material will copy without any additional tranformations.
  149. Blitter.BlitTexture(rgContext.cmd, data.source, scaleBias, 0, false);
  150. }
  151. }
  152. [Tooltip("The material used when making the blit operation.")]
  153. public Material[] displayMaterials = new Material[1];
  154. UpdateRefPass m_UpdateRefPass;
  155. CopyBackRefPass m_CopyBackRefPass;
  156. // Here you can create passes and do the initialization of them. This is called everytime serialization happens.
  157. public override void Create()
  158. {
  159. m_UpdateRefPass = new UpdateRefPass();
  160. m_CopyBackRefPass = new CopyBackRefPass();
  161. // Configures where the render pass should be injected.
  162. m_UpdateRefPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
  163. m_CopyBackRefPass.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
  164. }
  165. // Here you can inject one or multiple render passes in the renderer.
  166. // This method is called when setting up the renderer once per-camera.
  167. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  168. {
  169. // Since they have the same RenderPassEvent the order matters when enqueueing them.
  170. // Early exit if there are no materials.
  171. if (displayMaterials == null)
  172. {
  173. Debug.LogWarning("TexterRefRendererFeature materials is null and will be skipped.");
  174. return;
  175. }
  176. m_UpdateRefPass.Setup(displayMaterials);
  177. renderer.EnqueuePass(m_UpdateRefPass);
  178. renderer.EnqueuePass(m_CopyBackRefPass);
  179. }
  180. }