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.

338 lines
16 KiB

  1. using UnityEditorInternal;
  2. using UnityEngine;
  3. using UnityEngine.PostProcessing;
  4. namespace UnityEditor.PostProcessing
  5. {
  6. using HistogramMode = PostProcessingProfile.MonitorSettings.HistogramMode;
  7. public class HistogramMonitor : PostProcessingMonitor
  8. {
  9. static GUIContent s_MonitorTitle = new GUIContent("Histogram");
  10. ComputeShader m_ComputeShader;
  11. ComputeBuffer m_Buffer;
  12. Material m_Material;
  13. RenderTexture m_HistogramTexture;
  14. Rect m_MonitorAreaRect;
  15. public HistogramMonitor()
  16. {
  17. m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/HistogramCompute.compute");
  18. }
  19. public override void Dispose()
  20. {
  21. GraphicsUtils.Destroy(m_Material);
  22. GraphicsUtils.Destroy(m_HistogramTexture);
  23. if (m_Buffer != null)
  24. m_Buffer.Release();
  25. m_Material = null;
  26. m_HistogramTexture = null;
  27. m_Buffer = null;
  28. }
  29. public override bool IsSupported()
  30. {
  31. return m_ComputeShader != null && GraphicsUtils.supportsDX11;
  32. }
  33. public override GUIContent GetMonitorTitle()
  34. {
  35. return s_MonitorTitle;
  36. }
  37. public override void OnMonitorSettings()
  38. {
  39. EditorGUI.BeginChangeCheck();
  40. bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
  41. var mode = m_MonitorSettings.histogramMode;
  42. refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the histogram in play mode; this may impact performances."), FxStyles.preButton);
  43. mode = (HistogramMode)EditorGUILayout.EnumPopup(mode, FxStyles.preDropdown, GUILayout.MaxWidth(100f));
  44. if (EditorGUI.EndChangeCheck())
  45. {
  46. Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Histogram Settings Changed");
  47. m_MonitorSettings.refreshOnPlay = refreshOnPlay;
  48. m_MonitorSettings.histogramMode = mode;
  49. InternalEditorUtility.RepaintAllViews();
  50. }
  51. }
  52. public override void OnMonitorGUI(Rect r)
  53. {
  54. if (Event.current.type == EventType.Repaint)
  55. {
  56. // If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the histogram data
  57. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
  58. InternalEditorUtility.RepaintAllViews();
  59. // Sizing
  60. float width = m_HistogramTexture != null
  61. ? Mathf.Min(m_HistogramTexture.width, r.width - 65f)
  62. : r.width;
  63. float height = m_HistogramTexture != null
  64. ? Mathf.Min(m_HistogramTexture.height, r.height - 45f)
  65. : r.height;
  66. m_MonitorAreaRect = new Rect(
  67. Mathf.Floor(r.x + r.width / 2f - width / 2f),
  68. Mathf.Floor(r.y + r.height / 2f - height / 2f - 5f),
  69. width, height
  70. );
  71. if (m_HistogramTexture != null)
  72. {
  73. Graphics.DrawTexture(m_MonitorAreaRect, m_HistogramTexture);
  74. var color = Color.white;
  75. const float kTickSize = 5f;
  76. // Rect, lines & ticks points
  77. if (m_MonitorSettings.histogramMode == HistogramMode.RGBSplit)
  78. {
  79. // A B C D E
  80. // N F
  81. // M G
  82. // L K J I H
  83. var A = new Vector3(m_MonitorAreaRect.x - 1f, m_MonitorAreaRect.y - 1f);
  84. var E = new Vector3(A.x + m_MonitorAreaRect.width + 2f, m_MonitorAreaRect.y - 1f);
  85. var H = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 2f);
  86. var L = new Vector3(A.x, H.y);
  87. var N = new Vector3(A.x, A.y + (L.y - A.y) / 3f);
  88. var M = new Vector3(A.x, A.y + (L.y - A.y) * 2f / 3f);
  89. var F = new Vector3(E.x, E.y + (H.y - E.y) / 3f);
  90. var G = new Vector3(E.x, E.y + (H.y - E.y) * 2f / 3f);
  91. var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
  92. var J = new Vector3(L.x + (H.x - L.x) / 2f, L.y);
  93. var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
  94. var D = new Vector3(C.x + (E.x - C.x) / 2f, C.y);
  95. var I = new Vector3(J.x + (H.x - J.x) / 2f, J.y);
  96. var K = new Vector3(L.x + (J.x - L.x) / 2f, L.y);
  97. // Borders
  98. Handles.color = color;
  99. Handles.DrawLine(A, E);
  100. Handles.DrawLine(E, H);
  101. Handles.DrawLine(H, L);
  102. Handles.DrawLine(L, new Vector3(A.x, A.y - 1f));
  103. // Vertical ticks
  104. Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
  105. Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
  106. Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
  107. Handles.DrawLine(L, new Vector3(L.x - kTickSize, L.y));
  108. Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
  109. Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
  110. Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
  111. Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
  112. // Horizontal ticks
  113. Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
  114. Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
  115. Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
  116. Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
  117. Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
  118. Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
  119. Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
  120. Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
  121. Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
  122. Handles.DrawLine(H, new Vector3(H.x, H.y + kTickSize));
  123. // Separators
  124. Handles.DrawLine(N, F);
  125. Handles.DrawLine(M, G);
  126. // Labels
  127. GUI.color = color;
  128. GUI.Label(new Rect(L.x - 15f, L.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
  129. GUI.Label(new Rect(J.x - 15f, J.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
  130. GUI.Label(new Rect(H.x - 15f, H.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
  131. }
  132. else
  133. {
  134. // A B C D E
  135. // P F
  136. // O G
  137. // N H
  138. // M L K J I
  139. var A = new Vector3(m_MonitorAreaRect.x, m_MonitorAreaRect.y);
  140. var E = new Vector3(A.x + m_MonitorAreaRect.width + 1f, m_MonitorAreaRect.y);
  141. var I = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 1f);
  142. var M = new Vector3(A.x, I.y);
  143. var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
  144. var G = new Vector3(E.x, E.y + (I.y - E.y) / 2f);
  145. var K = new Vector3(M.x + (I.x - M.x) / 2f, M.y);
  146. var O = new Vector3(A.x, A.y + (M.y - A.y) / 2f);
  147. var P = new Vector3(A.x, A.y + (O.y - A.y) / 2f);
  148. var F = new Vector3(E.x, E.y + (G.y - E.y) / 2f);
  149. var N = new Vector3(A.x, O.y + (M.y - O.y) / 2f);
  150. var H = new Vector3(E.x, G.y + (I.y - G.y) / 2f);
  151. var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
  152. var L = new Vector3(M.x + (K.x - M.x) / 2f, M.y);
  153. var D = new Vector3(C.x + (E.x - C.x) / 2f, A.y);
  154. var J = new Vector3(K.x + (I.x - K.x) / 2f, M.y);
  155. // Borders
  156. Handles.color = color;
  157. Handles.DrawLine(A, E);
  158. Handles.DrawLine(E, I);
  159. Handles.DrawLine(I, M);
  160. Handles.DrawLine(M, new Vector3(A.x, A.y - 1f));
  161. // Vertical ticks
  162. Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
  163. Handles.DrawLine(P, new Vector3(P.x - kTickSize, P.y));
  164. Handles.DrawLine(O, new Vector3(O.x - kTickSize, O.y));
  165. Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
  166. Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
  167. Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
  168. Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
  169. Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
  170. Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
  171. Handles.DrawLine(I, new Vector3(I.x + kTickSize, I.y));
  172. // Horizontal ticks
  173. Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
  174. Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
  175. Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
  176. Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
  177. Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
  178. Handles.DrawLine(M, new Vector3(M.x, M.y + kTickSize));
  179. Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
  180. Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
  181. Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
  182. Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
  183. // Labels
  184. GUI.color = color;
  185. GUI.Label(new Rect(A.x - kTickSize - 34f, A.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleRight);
  186. GUI.Label(new Rect(O.x - kTickSize - 34f, O.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleRight);
  187. GUI.Label(new Rect(M.x - kTickSize - 34f, M.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleRight);
  188. GUI.Label(new Rect(E.x + kTickSize + 4f, E.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleLeft);
  189. GUI.Label(new Rect(G.x + kTickSize + 4f, G.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleLeft);
  190. GUI.Label(new Rect(I.x + kTickSize + 4f, I.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleLeft);
  191. GUI.Label(new Rect(M.x - 15f, M.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
  192. GUI.Label(new Rect(K.x - 15f, K.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
  193. GUI.Label(new Rect(I.x - 15f, I.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
  194. }
  195. }
  196. }
  197. }
  198. public override void OnFrameData(RenderTexture source)
  199. {
  200. if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
  201. return;
  202. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
  203. return;
  204. float ratio = (float)source.width / (float)source.height;
  205. int h = 512;
  206. int w = Mathf.FloorToInt(h * ratio);
  207. var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
  208. Graphics.Blit(source, rt);
  209. ComputeHistogram(rt);
  210. m_BaseEditor.Repaint();
  211. RenderTexture.ReleaseTemporary(rt);
  212. }
  213. void CreateBuffer(int width, int height)
  214. {
  215. m_Buffer = new ComputeBuffer(width * height, sizeof(uint) << 2);
  216. }
  217. void ComputeHistogram(RenderTexture source)
  218. {
  219. if (m_Buffer == null)
  220. {
  221. CreateBuffer(256, 1);
  222. }
  223. else if (m_Buffer.count != 256)
  224. {
  225. m_Buffer.Release();
  226. CreateBuffer(256, 1);
  227. }
  228. if (m_Material == null)
  229. {
  230. m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Histogram Render")) { hideFlags = HideFlags.DontSave };
  231. }
  232. var channels = Vector4.zero;
  233. switch (m_MonitorSettings.histogramMode)
  234. {
  235. case HistogramMode.Red: channels.x = 1f; break;
  236. case HistogramMode.Green: channels.y = 1f; break;
  237. case HistogramMode.Blue: channels.z = 1f; break;
  238. case HistogramMode.Luminance: channels.w = 1f; break;
  239. default: channels = new Vector4(1f, 1f, 1f, 0f); break;
  240. }
  241. var cs = m_ComputeShader;
  242. int kernel = cs.FindKernel("KHistogramClear");
  243. cs.SetBuffer(kernel, "_Histogram", m_Buffer);
  244. cs.Dispatch(kernel, 1, 1, 1);
  245. kernel = cs.FindKernel("KHistogramGather");
  246. cs.SetBuffer(kernel, "_Histogram", m_Buffer);
  247. cs.SetTexture(kernel, "_Source", source);
  248. cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
  249. cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
  250. cs.SetVector("_Channels", channels);
  251. cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 16f), Mathf.CeilToInt(source.height / 16f), 1);
  252. kernel = cs.FindKernel("KHistogramScale");
  253. cs.SetBuffer(kernel, "_Histogram", m_Buffer);
  254. cs.Dispatch(kernel, 1, 1, 1);
  255. if (m_HistogramTexture == null || m_HistogramTexture.width != source.width || m_HistogramTexture.height != source.height)
  256. {
  257. GraphicsUtils.Destroy(m_HistogramTexture);
  258. m_HistogramTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
  259. {
  260. hideFlags = HideFlags.DontSave,
  261. wrapMode = TextureWrapMode.Clamp,
  262. filterMode = FilterMode.Bilinear
  263. };
  264. }
  265. m_Material.SetBuffer("_Histogram", m_Buffer);
  266. m_Material.SetVector("_Size", new Vector2(m_HistogramTexture.width, m_HistogramTexture.height));
  267. m_Material.SetColor("_ColorR", new Color(1f, 0f, 0f, 1f));
  268. m_Material.SetColor("_ColorG", new Color(0f, 1f, 0f, 1f));
  269. m_Material.SetColor("_ColorB", new Color(0f, 0f, 1f, 1f));
  270. m_Material.SetColor("_ColorL", new Color(1f, 1f, 1f, 1f));
  271. m_Material.SetInt("_Channel", (int)m_MonitorSettings.histogramMode);
  272. int pass = 0;
  273. if (m_MonitorSettings.histogramMode == HistogramMode.RGBMerged)
  274. pass = 1;
  275. else if (m_MonitorSettings.histogramMode == HistogramMode.RGBSplit)
  276. pass = 2;
  277. Graphics.Blit(null, m_HistogramTexture, m_Material, pass);
  278. }
  279. }
  280. }