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.

280 lines
12 KiB

  1. using UnityEditorInternal;
  2. using UnityEngine;
  3. using UnityEngine.PostProcessing;
  4. namespace UnityEditor.PostProcessing
  5. {
  6. public class WaveformMonitor : PostProcessingMonitor
  7. {
  8. static GUIContent s_MonitorTitle = new GUIContent("Waveform");
  9. ComputeShader m_ComputeShader;
  10. ComputeBuffer m_Buffer;
  11. Material m_Material;
  12. RenderTexture m_WaveformTexture;
  13. Rect m_MonitorAreaRect;
  14. public WaveformMonitor()
  15. {
  16. m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/WaveformCompute.compute");
  17. }
  18. public override void Dispose()
  19. {
  20. GraphicsUtils.Destroy(m_Material);
  21. GraphicsUtils.Destroy(m_WaveformTexture);
  22. if (m_Buffer != null)
  23. m_Buffer.Release();
  24. m_Material = null;
  25. m_WaveformTexture = null;
  26. m_Buffer = null;
  27. }
  28. public override bool IsSupported()
  29. {
  30. return m_ComputeShader != null && GraphicsUtils.supportsDX11;
  31. }
  32. public override GUIContent GetMonitorTitle()
  33. {
  34. return s_MonitorTitle;
  35. }
  36. public override void OnMonitorSettings()
  37. {
  38. EditorGUI.BeginChangeCheck();
  39. bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
  40. float exposure = m_MonitorSettings.waveformExposure;
  41. bool Y = m_MonitorSettings.waveformY;
  42. bool R = m_MonitorSettings.waveformR;
  43. bool G = m_MonitorSettings.waveformG;
  44. bool B = m_MonitorSettings.waveformB;
  45. refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the waveform in play mode; this may impact performances."), FxStyles.preButton);
  46. exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
  47. Y = GUILayout.Toggle(Y, new GUIContent("Y", "Show the luminance waveform only."), FxStyles.preButton);
  48. if (Y)
  49. {
  50. R = false;
  51. G = false;
  52. B = false;
  53. }
  54. R = GUILayout.Toggle(R, new GUIContent("R", "Show the red waveform."), FxStyles.preButton);
  55. G = GUILayout.Toggle(G, new GUIContent("G", "Show the green waveform."), FxStyles.preButton);
  56. B = GUILayout.Toggle(B, new GUIContent("B", "Show the blue waveform."), FxStyles.preButton);
  57. if (R || G || B)
  58. Y = false;
  59. if (!Y && !R && !G && !B)
  60. {
  61. R = true;
  62. G = true;
  63. B = true;
  64. }
  65. if (EditorGUI.EndChangeCheck())
  66. {
  67. Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Waveforme Settings Changed");
  68. m_MonitorSettings.refreshOnPlay = refreshOnPlay;
  69. m_MonitorSettings.waveformExposure = exposure;
  70. m_MonitorSettings.waveformY = Y;
  71. m_MonitorSettings.waveformR = R;
  72. m_MonitorSettings.waveformG = G;
  73. m_MonitorSettings.waveformB = B;
  74. InternalEditorUtility.RepaintAllViews();
  75. }
  76. }
  77. public override void OnMonitorGUI(Rect r)
  78. {
  79. if (Event.current.type == EventType.Repaint)
  80. {
  81. // If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the waveform data
  82. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
  83. InternalEditorUtility.RepaintAllViews();
  84. // Sizing
  85. float width = m_WaveformTexture != null
  86. ? Mathf.Min(m_WaveformTexture.width, r.width - 65f)
  87. : r.width;
  88. float height = m_WaveformTexture != null
  89. ? Mathf.Min(m_WaveformTexture.height, r.height - 45f)
  90. : r.height;
  91. m_MonitorAreaRect = new Rect(
  92. Mathf.Floor(r.x + r.width / 2f - width / 2f),
  93. Mathf.Floor(r.y + r.height / 2f - height / 2f - 5f),
  94. width, height
  95. );
  96. if (m_WaveformTexture != null)
  97. {
  98. m_Material.SetFloat("_Exposure", m_MonitorSettings.waveformExposure);
  99. var oldActive = RenderTexture.active;
  100. Graphics.Blit(null, m_WaveformTexture, m_Material, 0);
  101. RenderTexture.active = oldActive;
  102. Graphics.DrawTexture(m_MonitorAreaRect, m_WaveformTexture);
  103. var color = Color.white;
  104. const float kTickSize = 5f;
  105. // Rect, lines & ticks points
  106. // A B C D E
  107. // P F
  108. // O G
  109. // N H
  110. // M L K J I
  111. var A = new Vector3(m_MonitorAreaRect.x, m_MonitorAreaRect.y);
  112. var E = new Vector3(A.x + m_MonitorAreaRect.width + 1f, m_MonitorAreaRect.y);
  113. var I = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 1f);
  114. var M = new Vector3(A.x, I.y);
  115. var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
  116. var G = new Vector3(E.x, E.y + (I.y - E.y) / 2f);
  117. var K = new Vector3(M.x + (I.x - M.x) / 2f, M.y);
  118. var O = new Vector3(A.x, A.y + (M.y - A.y) / 2f);
  119. var P = new Vector3(A.x, A.y + (O.y - A.y) / 2f);
  120. var F = new Vector3(E.x, E.y + (G.y - E.y) / 2f);
  121. var N = new Vector3(A.x, O.y + (M.y - O.y) / 2f);
  122. var H = new Vector3(E.x, G.y + (I.y - G.y) / 2f);
  123. var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
  124. var L = new Vector3(M.x + (K.x - M.x) / 2f, M.y);
  125. var D = new Vector3(C.x + (E.x - C.x) / 2f, A.y);
  126. var J = new Vector3(K.x + (I.x - K.x) / 2f, M.y);
  127. // Borders
  128. Handles.color = color;
  129. Handles.DrawLine(A, E);
  130. Handles.DrawLine(E, I);
  131. Handles.DrawLine(I, M);
  132. Handles.DrawLine(M, new Vector3(A.x, A.y - 1f));
  133. // Vertical ticks
  134. Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
  135. Handles.DrawLine(P, new Vector3(P.x - kTickSize, P.y));
  136. Handles.DrawLine(O, new Vector3(O.x - kTickSize, O.y));
  137. Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
  138. Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
  139. Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
  140. Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
  141. Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
  142. Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
  143. Handles.DrawLine(I, new Vector3(I.x + kTickSize, I.y));
  144. // Horizontal ticks
  145. Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
  146. Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
  147. Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
  148. Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
  149. Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
  150. Handles.DrawLine(M, new Vector3(M.x, M.y + kTickSize));
  151. Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
  152. Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
  153. Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
  154. Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
  155. // Labels
  156. GUI.color = color;
  157. GUI.Label(new Rect(A.x - kTickSize - 34f, A.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleRight);
  158. GUI.Label(new Rect(O.x - kTickSize - 34f, O.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleRight);
  159. GUI.Label(new Rect(M.x - kTickSize - 34f, M.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleRight);
  160. GUI.Label(new Rect(E.x + kTickSize + 4f, E.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleLeft);
  161. GUI.Label(new Rect(G.x + kTickSize + 4f, G.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleLeft);
  162. GUI.Label(new Rect(I.x + kTickSize + 4f, I.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleLeft);
  163. GUI.Label(new Rect(M.x - 15f, M.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
  164. GUI.Label(new Rect(K.x - 15f, K.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
  165. GUI.Label(new Rect(I.x - 15f, I.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
  166. }
  167. }
  168. }
  169. public override void OnFrameData(RenderTexture source)
  170. {
  171. if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
  172. return;
  173. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
  174. return;
  175. float ratio = (float)source.width / (float)source.height;
  176. int h = 384;
  177. int w = Mathf.FloorToInt(h * ratio);
  178. var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
  179. Graphics.Blit(source, rt);
  180. ComputeWaveform(rt);
  181. m_BaseEditor.Repaint();
  182. RenderTexture.ReleaseTemporary(rt);
  183. }
  184. void CreateBuffer(int width, int height)
  185. {
  186. m_Buffer = new ComputeBuffer(width * height, sizeof(uint) << 2);
  187. }
  188. void ComputeWaveform(RenderTexture source)
  189. {
  190. if (m_Buffer == null)
  191. {
  192. CreateBuffer(source.width, source.height);
  193. }
  194. else if (m_Buffer.count != (source.width * source.height))
  195. {
  196. m_Buffer.Release();
  197. CreateBuffer(source.width, source.height);
  198. }
  199. var channels = m_MonitorSettings.waveformY
  200. ? new Vector4(0f, 0f, 0f, 1f)
  201. : new Vector4(m_MonitorSettings.waveformR ? 1f : 0f, m_MonitorSettings.waveformG ? 1f : 0f, m_MonitorSettings.waveformB ? 1f : 0f, 0f);
  202. var cs = m_ComputeShader;
  203. int kernel = cs.FindKernel("KWaveformClear");
  204. cs.SetBuffer(kernel, "_Waveform", m_Buffer);
  205. cs.Dispatch(kernel, source.width, 1, 1);
  206. kernel = cs.FindKernel("KWaveform");
  207. cs.SetBuffer(kernel, "_Waveform", m_Buffer);
  208. cs.SetTexture(kernel, "_Source", source);
  209. cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
  210. cs.SetVector("_Channels", channels);
  211. cs.Dispatch(kernel, source.width, 1, 1);
  212. if (m_WaveformTexture == null || m_WaveformTexture.width != source.width || m_WaveformTexture.height != source.height)
  213. {
  214. GraphicsUtils.Destroy(m_WaveformTexture);
  215. m_WaveformTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
  216. {
  217. hideFlags = HideFlags.DontSave,
  218. wrapMode = TextureWrapMode.Clamp,
  219. filterMode = FilterMode.Bilinear
  220. };
  221. }
  222. if (m_Material == null)
  223. m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Waveform Render")) { hideFlags = HideFlags.DontSave };
  224. m_Material.SetBuffer("_Waveform", m_Buffer);
  225. m_Material.SetVector("_Size", new Vector2(m_WaveformTexture.width, m_WaveformTexture.height));
  226. m_Material.SetVector("_Channels", channels);
  227. }
  228. }
  229. }