HighlightPlusRenderPassFeature.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. using UnityEngine.Rendering.Universal;
  5. namespace HighlightPlus {
  6. public class HighlightPlusRenderPassFeature : ScriptableRendererFeature {
  7. class HighlightPass : ScriptableRenderPass {
  8. // far objects render first
  9. class DistanceComparer : IComparer<HighlightEffect> {
  10. public Vector3 camPos;
  11. public int Compare(HighlightEffect e1, HighlightEffect e2) {
  12. Vector3 e1Pos = e1.transform.position;
  13. float dx1 = e1Pos.x - camPos.x;
  14. float dy1 = e1Pos.y - camPos.y;
  15. float dz1 = e1Pos.z - camPos.z;
  16. float distE1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1 + e1.sortingOffset;
  17. Vector3 e2Pos = e2.transform.position;
  18. float dx2 = e2Pos.x - camPos.x;
  19. float dy2 = e2Pos.y - camPos.y;
  20. float dz2 = e2Pos.z - camPos.z;
  21. float distE2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2 + e2.sortingOffset;
  22. if (distE1 > distE2) return -1;
  23. if (distE1 < distE2) return 1;
  24. return 0;
  25. }
  26. }
  27. public bool usesCameraOverlay;
  28. ScriptableRenderer renderer;
  29. RenderTextureDescriptor cameraTextureDescriptor;
  30. DistanceComparer effectDistanceComparer;
  31. bool clearStencil;
  32. FullScreenBlitMethod fullScreenBlitMethod = FullScreenBlit;
  33. int frameCount;
  34. public void Setup(HighlightPlusRenderPassFeature passFeature, ScriptableRenderer renderer) {
  35. this.renderPassEvent = passFeature.renderPassEvent;
  36. this.clearStencil = passFeature.clearStencil;
  37. this.renderer = renderer;
  38. if (effectDistanceComparer == null) {
  39. effectDistanceComparer = new DistanceComparer();
  40. }
  41. HighlightEffect.isVREnabled = UnityEngine.XR.XRSettings.enabled && Application.isPlaying;
  42. }
  43. public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
  44. this.cameraTextureDescriptor = cameraTextureDescriptor;
  45. #if UNITY_2021_2_OR_NEWER
  46. ConfigureInput(ScriptableRenderPassInput.Depth);
  47. #endif
  48. }
  49. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) {
  50. int count = HighlightEffect.effects.Count;
  51. if (count == 0) return;
  52. Camera cam = renderingData.cameraData.camera;
  53. int camLayer = 1 << cam.gameObject.layer;
  54. CameraType camType = cam.cameraType;
  55. #if UNITY_2022_1_OR_NEWER
  56. RTHandle cameraColorTarget = renderer.cameraColorTargetHandle;
  57. RTHandle cameraDepthTarget = renderer.cameraDepthTargetHandle;
  58. #else
  59. RenderTargetIdentifier cameraColorTarget = renderer.cameraColorTarget;
  60. RenderTargetIdentifier cameraDepthTarget = renderer.cameraDepthTarget;
  61. #endif
  62. #if !UNITY_2021_2_OR_NEWER
  63. // In Unity 2021.2, when MSAA > 1, cameraDepthTarget is no longer cameraColorTarget
  64. if (!usesCameraOverlay && (cameraTextureDescriptor.msaaSamples > 1 || cam.cameraType == CameraType.SceneView)) {
  65. cameraDepthTarget = cameraColorTarget;
  66. }
  67. #endif
  68. if (!HighlightEffect.customSorting && ( (camType == CameraType.Game && (frameCount++) % 10 == 0) || !Application.isPlaying)) {
  69. effectDistanceComparer.camPos = cam.transform.position;
  70. HighlightEffect.effects.Sort(effectDistanceComparer);
  71. }
  72. bool clearStencil = this.clearStencil;
  73. for (int k = 0; k < count; k++) {
  74. HighlightEffect effect = HighlightEffect.effects[k];
  75. if (!(effect.ignoreObjectVisibility || effect.isVisible)) continue;
  76. if (!effect.isActiveAndEnabled) continue;
  77. if (camType == CameraType.Reflection && !effect.reflectionProbes) continue;
  78. if ((effect.camerasLayerMask & camLayer) == 0) continue;
  79. CommandBuffer cb = effect.GetCommandBuffer(cam, cameraColorTarget, cameraDepthTarget, fullScreenBlitMethod, clearStencil);
  80. if (cb != null) {
  81. context.ExecuteCommandBuffer(cb);
  82. clearStencil = false;
  83. }
  84. }
  85. }
  86. static Mesh _fullScreenMesh;
  87. static Mesh fullscreenMesh {
  88. get {
  89. if (_fullScreenMesh != null) {
  90. return _fullScreenMesh;
  91. }
  92. float num = 1f;
  93. float num2 = 0f;
  94. Mesh val = new Mesh();
  95. _fullScreenMesh = val;
  96. _fullScreenMesh.SetVertices(new List<Vector3> {
  97. new Vector3 (-1f, -1f, 0f),
  98. new Vector3 (-1f, 1f, 0f),
  99. new Vector3 (1f, -1f, 0f),
  100. new Vector3 (1f, 1f, 0f)
  101. });
  102. _fullScreenMesh.SetUVs(0, new List<Vector2> {
  103. new Vector2 (0f, num2),
  104. new Vector2 (0f, num),
  105. new Vector2 (1f, num2),
  106. new Vector2 (1f, num)
  107. });
  108. _fullScreenMesh.SetIndices(new int[6] { 0, 1, 2, 2, 1, 3 }, (MeshTopology)0, 0, false);
  109. _fullScreenMesh.UploadMeshData(true);
  110. return _fullScreenMesh;
  111. }
  112. }
  113. static Matrix4x4 matrix4x4Identity = Matrix4x4.identity;
  114. static void FullScreenBlit(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int passIndex) {
  115. destination = new RenderTargetIdentifier(destination, 0, CubemapFace.Unknown, -1);
  116. cmd.SetRenderTarget(destination);
  117. cmd.SetGlobalTexture(ShaderParams.MainTex, source);
  118. cmd.DrawMesh(fullscreenMesh, matrix4x4Identity, material, 0, passIndex);
  119. }
  120. public override void FrameCleanup(CommandBuffer cmd) {
  121. }
  122. }
  123. HighlightPass renderPass;
  124. public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
  125. [Tooltip("Clears stencil buffer before rendering highlight effects. This option can solve compatibility issues with shaders that also use stencil buffers.")]
  126. public bool clearStencil;
  127. /// <summary>
  128. /// Makes the effects visible in Edit mode.
  129. /// </summary>
  130. [Tooltip("If enabled, effects will be visible also in Edit mode (when not in Play mode).")]
  131. public bool previewInEditMode = true;
  132. /// <summary>
  133. /// Makes the effects visible in Edit mode.
  134. /// </summary>
  135. [Tooltip("If enabled, effects will be visible also in Preview camera (preview camera shown when a camera is selected in Editor).")]
  136. public bool showInPreviewCamera = true;
  137. public static bool installed;
  138. public static bool showingInEditMode;
  139. const string PREVIEW_CAMERA_NAME = "Preview Camera";
  140. void OnDisable() {
  141. installed = false;
  142. }
  143. public override void Create() {
  144. renderPass = new HighlightPass();
  145. }
  146. // This method is called when setting up the renderer once per-camera.
  147. public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
  148. showingInEditMode = previewInEditMode;
  149. Camera cam = renderingData.cameraData.camera;
  150. #if UNITY_EDITOR
  151. if (!previewInEditMode && !Application.isPlaying) {
  152. return;
  153. }
  154. if (cam.cameraType == CameraType.Preview) {
  155. return;
  156. }
  157. if (!showInPreviewCamera && PREVIEW_CAMERA_NAME.Equals(cam.name)) {
  158. return;
  159. }
  160. #endif
  161. #if UNITY_2019_4_OR_NEWER
  162. if (renderingData.cameraData.renderType == CameraRenderType.Base) {
  163. renderPass.usesCameraOverlay = cam.GetUniversalAdditionalCameraData().cameraStack.Count > 0;
  164. }
  165. #endif
  166. renderPass.Setup(this, renderer);
  167. renderer.EnqueuePass(renderPass);
  168. installed = true;
  169. }
  170. }
  171. }