URPOutlineFeature.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. using EPOOutline;
  5. using System;
  6. using System.Reflection;
  7. #if URP_OUTLINE && UNITY_2019_1_OR_NEWER
  8. #if UNITY_2019_3_OR_NEWER
  9. using UnityEngine.Rendering.Universal;
  10. #else
  11. using UnityEngine.Rendering.LWRP;
  12. #endif
  13. public class URPOutlineFeature : ScriptableRendererFeature
  14. {
  15. private class SRPOutline : ScriptableRenderPass
  16. {
  17. private static List<Outlinable> temporaryOutlinables = new List<Outlinable>();
  18. public ScriptableRenderer Renderer;
  19. public bool UseColorTargetForDepth;
  20. public Outliner Outliner;
  21. public OutlineParameters Parameters = new OutlineParameters();
  22. private List<Outliner> outliners = new List<Outliner>();
  23. public SRPOutline()
  24. {
  25. Parameters.CheckInitialization();
  26. }
  27. private FieldInfo nameId = typeof(RenderTargetIdentifier).GetField("m_NameID", BindingFlags.NonPublic | BindingFlags.Instance);
  28. private bool IsDepthTextureAvailable(ScriptableRenderer renderer)
  29. {
  30. #if UNITY_2022_1_OR_NEWER
  31. return renderer.cameraDepthTargetHandle.rt != null;
  32. #else
  33. return (int)nameId.GetValue(GetDepthTarget(renderer)) != -1;
  34. #endif
  35. }
  36. private RenderTargetIdentifier GetDepthTarget(ScriptableRenderer renderer)
  37. {
  38. return
  39. #if UNITY_2022_1_OR_NEWER
  40. Renderer.cameraDepthTargetHandle;
  41. #elif UNITY_2020_2_OR_NEWER
  42. Renderer.cameraDepthTarget;
  43. #else
  44. Renderer.cameraDepth;
  45. #endif
  46. }
  47. private RenderTargetIdentifier GetColorTarget(ScriptableRenderer renderer)
  48. {
  49. #if UNITY_2022_1_OR_NEWER
  50. return renderer.cameraColorTargetHandle;
  51. #else
  52. return renderer.cameraColorTarget;
  53. #endif
  54. }
  55. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  56. {
  57. var camera = renderingData.cameraData.camera;
  58. var outlineEffect = Outliner;
  59. if (outlineEffect == null || !outlineEffect.enabled)
  60. return;
  61. #if UNITY_EDITOR
  62. Parameters.Buffer.name = renderingData.cameraData.camera.name;
  63. #endif
  64. Outlinable.GetAllActiveOutlinables(renderingData.cameraData.camera, Parameters.OutlinablesToRender);
  65. Outliner.UpdateSharedParameters(Parameters, renderingData.cameraData.camera, renderingData.cameraData.isSceneViewCamera);
  66. RendererFilteringUtility.Filter(renderingData.cameraData.camera, Parameters);
  67. Parameters.TargetWidth = renderingData.cameraData.cameraTargetDescriptor.width;
  68. Parameters.TargetHeight = renderingData.cameraData.cameraTargetDescriptor.height;
  69. Parameters.Antialiasing = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
  70. Parameters.Target = RenderTargetUtility.ComposeTarget(Parameters, Renderer.cameraColorTarget);
  71. Parameters.DepthTarget =
  72. #if UNITY_2019_3_OR_NEWER && !UNITY_2019_3_0 && !UNITY_2019_3_1 && !UNITY_2019_3_2 && !UNITY_2019_3_3 && !UNITY_2019_3_4 && !UNITY_2019_3_5 && !UNITY_2019_3_6 && !UNITY_2019_3_7 && !UNITY_2019_3_8
  73. RenderTargetUtility.ComposeTarget(Parameters, !IsDepthTextureAvailable(Renderer) ? GetColorTarget(Renderer) :
  74. GetDepthTarget(Renderer));
  75. #else
  76. RenderTargetUtility.ComposeTarget(Parameters, Renderer.cameraColorTarget);
  77. #endif
  78. Parameters.Buffer.Clear();
  79. if (Outliner.RenderingStrategy == OutlineRenderingStrategy.Default)
  80. {
  81. OutlineEffect.SetupOutline(Parameters);
  82. Parameters.BlitMesh = null;
  83. Parameters.MeshPool.ReleaseAllMeshes();
  84. }
  85. else
  86. {
  87. temporaryOutlinables.Clear();
  88. temporaryOutlinables.AddRange(Parameters.OutlinablesToRender);
  89. Parameters.OutlinablesToRender.Clear();
  90. Parameters.OutlinablesToRender.Add(null);
  91. foreach (var outlinable in temporaryOutlinables)
  92. {
  93. Parameters.OutlinablesToRender[0] = outlinable;
  94. OutlineEffect.SetupOutline(Parameters);
  95. Parameters.BlitMesh = null;
  96. }
  97. Parameters.MeshPool.ReleaseAllMeshes();
  98. }
  99. context.ExecuteCommandBuffer(Parameters.Buffer);
  100. }
  101. }
  102. private class Pool
  103. {
  104. private Stack<SRPOutline> outlines = new Stack<SRPOutline>();
  105. private List<SRPOutline> createdOutlines = new List<SRPOutline>();
  106. public SRPOutline Get()
  107. {
  108. if (outlines.Count == 0)
  109. {
  110. outlines.Push(new SRPOutline());
  111. createdOutlines.Add(outlines.Peek());
  112. }
  113. return outlines.Pop();
  114. }
  115. public void ReleaseAll()
  116. {
  117. outlines.Clear();
  118. foreach (var outline in createdOutlines)
  119. outlines.Push(outline);
  120. }
  121. }
  122. private GameObject lastSelectedCamera;
  123. private Pool outlinePool = new Pool();
  124. private List<Outliner> outliners = new List<Outliner>();
  125. private bool GetOutlinersToRenderWith(RenderingData renderingData, List<Outliner> outliners)
  126. {
  127. outliners.Clear();
  128. var camera = renderingData.cameraData.camera.gameObject;
  129. camera.GetComponents(outliners);
  130. if (outliners.Count == 0)
  131. {
  132. #if UNITY_EDITOR
  133. if (renderingData.cameraData.isSceneViewCamera)
  134. {
  135. var foundObject = Array.Find(
  136. Array.ConvertAll(UnityEditor.Selection.gameObjects, x => x.GetComponent<Outliner>()),
  137. x => x != null);
  138. camera = foundObject?.gameObject ?? lastSelectedCamera;
  139. if (camera == null)
  140. return false;
  141. else
  142. camera.GetComponents(outliners);
  143. }
  144. else
  145. return false;
  146. #else
  147. return false;
  148. #endif
  149. }
  150. var hasOutliners = outliners.Count > 0;
  151. if (hasOutliners)
  152. lastSelectedCamera = camera;
  153. return hasOutliners;
  154. }
  155. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  156. {
  157. if (!GetOutlinersToRenderWith(renderingData, outliners))
  158. return;
  159. #if UNITY_2019_3_OR_NEWER && !UNITY_2019_3_0 && !UNITY_2019_3_1 && !UNITY_2019_3_2 && !UNITY_2019_3_3 && !UNITY_2019_3_4 && !UNITY_2019_3_5 && !UNITY_2019_3_6 && !UNITY_2019_3_7 && !UNITY_2019_3_8
  160. var additionalCameraData = renderingData.cameraData.camera.GetUniversalAdditionalCameraData();
  161. var activeStackCount = 0;
  162. if (additionalCameraData != null)
  163. {
  164. var stack = additionalCameraData.renderType == CameraRenderType.Overlay ? null : additionalCameraData.cameraStack;
  165. if (stack != null)
  166. {
  167. foreach (var camera in stack)
  168. {
  169. if (camera != null && camera.isActiveAndEnabled)
  170. activeStackCount++;
  171. }
  172. }
  173. }
  174. #endif
  175. foreach (var outliner in outliners)
  176. {
  177. var outline = outlinePool.Get();
  178. outline.Outliner = outliner;
  179. outline.Renderer = renderer;
  180. outline.renderPassEvent = outliner.RenderStage == RenderStage.AfterTransparents ? RenderPassEvent.AfterRenderingTransparents : RenderPassEvent.AfterRenderingOpaques;
  181. renderer.EnqueuePass(outline);
  182. }
  183. outlinePool.ReleaseAll();
  184. }
  185. public override void Create()
  186. {
  187. }
  188. }
  189. #endif