暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

KeepFrameFeature.cs 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using UnityEditor;
  3. using UnityEngine;
  4. using UnityEngine.Experimental.Rendering;
  5. using UnityEngine.Rendering.RenderGraphModule;
  6. using UnityEngine.Rendering;
  7. using UnityEngine.Rendering.Universal;
  8. // This renderer feature will replicate a "don't clear" behaviour by injecting two passes into the pipeline:
  9. // One pass that copies color at the end of a frame
  10. // Another pass that draws the content of the copied texture at the beginning of a new frame
  11. // In this version of the sample we provide implementations for both RenderGraph and non-RenderGraph pipelines.
  12. // This way you can easily see what changed and how to manage code bases with backwards compatibility
  13. public class KeepFrameFeature : ScriptableRendererFeature
  14. {
  15. // This pass is responsible for copying color to a specified destination
  16. class CopyFramePass : ScriptableRenderPass
  17. {
  18. class PassData
  19. {
  20. public TextureHandle source;
  21. }
  22. RTHandle m_Destination;
  23. public void Setup(RTHandle destination)
  24. {
  25. m_Destination = destination;
  26. }
  27. #pragma warning disable 618, 672 // Type or member is obsolete, Member overrides obsolete member
  28. // Unity calls the Execute method in the Compatibility mode
  29. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  30. {
  31. if (renderingData.cameraData.camera.cameraType != CameraType.Game)
  32. return;
  33. var source = renderingData.cameraData.renderer.cameraColorTargetHandle;
  34. CommandBuffer cmd = CommandBufferPool.Get("CopyFramePass");
  35. Blit(cmd, source, m_Destination);
  36. context.ExecuteCommandBuffer(cmd);
  37. CommandBufferPool.Release(cmd);
  38. }
  39. #pragma warning restore 618, 672
  40. // RecordRenderGraph is called for the RenderGraph path.
  41. // Because RenderGraph has to calculate internally how resources are used we must be aware of 2
  42. // distinct timelines inside this method: one for recording resource usage and one for recording draw commands.
  43. // It is important to scope resources correctly as global state may change between the execution times of each.
  44. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  45. {
  46. UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
  47. UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
  48. if (cameraData.camera.cameraType != CameraType.Game)
  49. return;
  50. using (var builder = renderGraph.AddRasterRenderPass<PassData>("Copy Frame Pass", out var passData))
  51. {
  52. TextureHandle source = resourceData.activeColorTexture;
  53. // When using the RenderGraph API the lifetime and ownership of resources is managed by the render graph system itself.
  54. // This allows for optimal resource usage and other optimizations to be done automatically for the user.
  55. // In the cases where resources must persist across frames, between different cameras or when users want
  56. // to manage their lifetimes themselves, the resources must be imported when recording the render pass.
  57. TextureHandle destination = renderGraph.ImportTexture(m_Destination);
  58. if (!source.IsValid() || !destination.IsValid())
  59. return;
  60. passData.source = source;
  61. builder.UseTexture(source, AccessFlags.Read);
  62. builder.SetRenderAttachment(destination, 0, AccessFlags.Write);
  63. builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
  64. {
  65. Blitter.BlitTexture(context.cmd, data.source, new Vector4(1, 1, 0, 0), 0, true);
  66. });
  67. }
  68. }
  69. }
  70. // This pass is responsible for drawing the old color to a full screen quad
  71. class DrawOldFramePass : ScriptableRenderPass
  72. {
  73. class PassData
  74. {
  75. public TextureHandle source;
  76. public Material material;
  77. public string name;
  78. }
  79. Material m_DrawOldFrameMaterial;
  80. RTHandle m_Handle;
  81. string m_TextureName;
  82. public void Setup(Material drawOldFrameMaterial, RTHandle handle, string textureName)
  83. {
  84. m_DrawOldFrameMaterial = drawOldFrameMaterial;
  85. m_TextureName = textureName;
  86. m_Handle = handle;
  87. }
  88. // This is an example of how to share code between RenderGraph and older non-RenderGraph setups.
  89. // The common draw commands are extracted in a private static method that gets called from both
  90. // Execute and render graph builder's SetRenderFunc.
  91. static void ExecutePass(RasterCommandBuffer cmd, RTHandle source, Material material)
  92. {
  93. if (material == null)
  94. return;
  95. Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
  96. Blitter.BlitTexture(cmd, source, viewportScale, material, 0);
  97. }
  98. #pragma warning disable 618, 672 // Type or member is obsolete, Member overrides obsolete member
  99. // Unity calls the Execute method in the Compatibility mode
  100. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  101. {
  102. CommandBuffer cmd = CommandBufferPool.Get(nameof(DrawOldFramePass));
  103. cmd.SetGlobalTexture(m_TextureName, m_Handle);
  104. var source = renderingData.cameraData.renderer.cameraColorTargetHandle;
  105. ExecutePass(CommandBufferHelpers.GetRasterCommandBuffer(cmd), source, m_DrawOldFrameMaterial);
  106. context.ExecuteCommandBuffer(cmd);
  107. CommandBufferPool.Release(cmd);
  108. }
  109. #pragma warning restore 618, 672
  110. public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
  111. {
  112. UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
  113. UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
  114. TextureHandle oldFrameTextureHandle = renderGraph.ImportTexture(m_Handle);
  115. using (var builder = renderGraph.AddRasterRenderPass<PassData>("Draw Old Frame Pass", out var passData))
  116. {
  117. TextureHandle destination = resourceData.activeColorTexture;
  118. if (!oldFrameTextureHandle.IsValid() || !destination.IsValid())
  119. return;
  120. passData.material = m_DrawOldFrameMaterial;
  121. passData.source = oldFrameTextureHandle;
  122. passData.name = m_TextureName;
  123. builder.UseTexture(oldFrameTextureHandle, AccessFlags.Read);
  124. builder.SetRenderAttachment(destination, 0, AccessFlags.Write);
  125. // Normally global state modifications are not allowed when using RenderGraph and will result in errors.
  126. // In the exceptional cases where this is intentional we must let the RenderGraph API know by calling
  127. // AllowGlobalStateModification(true). Use this only where necessary as it will introduce a sync point
  128. // in the frame which may have a negative impact on performance.
  129. builder.AllowGlobalStateModification(true);
  130. builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
  131. {
  132. context.cmd.SetGlobalTexture(data.name, data.source);
  133. ExecutePass(context.cmd, data.source, data.material);
  134. });
  135. }
  136. }
  137. }
  138. [Serializable]
  139. public class Settings
  140. {
  141. [Tooltip("The material that is used when the old frame is redrawn at the start of the new frame (before opaques).")]
  142. public Material displayMaterial;
  143. [Tooltip("The name of the texture used for referencing the copied frame. (Defaults to _FrameCopyTex if empty)")]
  144. public string textureName;
  145. }
  146. CopyFramePass m_CopyFrame;
  147. DrawOldFramePass m_DrawOldFrame;
  148. RTHandle m_OldFrameHandle;
  149. public Settings settings = new Settings();
  150. // In this function the passes are created and their point of injection is set
  151. public override void Create()
  152. {
  153. m_CopyFrame = new CopyFramePass();
  154. m_CopyFrame.renderPassEvent = RenderPassEvent.AfterRenderingTransparents; // Frame color is copied late in the frame
  155. m_DrawOldFrame = new DrawOldFramePass();
  156. m_DrawOldFrame.renderPassEvent = RenderPassEvent.BeforeRenderingOpaques; // Old frame is drawn early in the frame
  157. }
  158. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  159. {
  160. var descriptor = renderingData.cameraData.cameraTargetDescriptor;
  161. descriptor.msaaSamples = 1;
  162. descriptor.depthBufferBits = 0;
  163. descriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_SRGB;
  164. var textureName = String.IsNullOrEmpty(settings.textureName) ? "_FrameCopyTex" : settings.textureName;
  165. RenderingUtils.ReAllocateHandleIfNeeded(ref m_OldFrameHandle, descriptor, FilterMode.Bilinear, TextureWrapMode.Clamp, name: textureName);
  166. m_CopyFrame.Setup(m_OldFrameHandle);
  167. m_DrawOldFrame.Setup(settings.displayMaterial, m_OldFrameHandle, textureName);
  168. renderer.EnqueuePass(m_CopyFrame);
  169. renderer.EnqueuePass(m_DrawOldFrame);
  170. }
  171. public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
  172. {
  173. // This path is not taken when using render graph.
  174. // The code to reallocate m_OldFrameHandle has been moved to AddRenderPasses in order to avoid duplication.
  175. }
  176. protected override void Dispose(bool disposing)
  177. {
  178. m_OldFrameHandle?.Release();
  179. }
  180. }