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.

241 lines
10 KiB

  1. using UnityEditorInternal;
  2. using UnityEngine;
  3. using UnityEngine.PostProcessing;
  4. namespace UnityEditor.PostProcessing
  5. {
  6. public class VectorscopeMonitor : PostProcessingMonitor
  7. {
  8. static GUIContent s_MonitorTitle = new GUIContent("Vectorscope");
  9. ComputeShader m_ComputeShader;
  10. ComputeBuffer m_Buffer;
  11. Material m_Material;
  12. RenderTexture m_VectorscopeTexture;
  13. Rect m_MonitorAreaRect;
  14. public VectorscopeMonitor()
  15. {
  16. m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/VectorscopeCompute.compute");
  17. }
  18. public override void Dispose()
  19. {
  20. GraphicsUtils.Destroy(m_Material);
  21. GraphicsUtils.Destroy(m_VectorscopeTexture);
  22. if (m_Buffer != null)
  23. m_Buffer.Release();
  24. m_Material = null;
  25. m_VectorscopeTexture = 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.vectorscopeExposure;
  41. bool showBackground = m_MonitorSettings.vectorscopeShowBackground;
  42. refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the vectorscope in play mode; this may impact performances."), FxStyles.preButton);
  43. exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
  44. showBackground = GUILayout.Toggle(showBackground, new GUIContent(FxStyles.checkerIcon, "Show an YUV background in the vectorscope."), FxStyles.preButton);
  45. if (EditorGUI.EndChangeCheck())
  46. {
  47. Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Vectorscope Settings Changed");
  48. m_MonitorSettings.refreshOnPlay = refreshOnPlay;
  49. m_MonitorSettings.vectorscopeExposure = exposure;
  50. m_MonitorSettings.vectorscopeShowBackground = showBackground;
  51. InternalEditorUtility.RepaintAllViews();
  52. }
  53. }
  54. public override void OnMonitorGUI(Rect r)
  55. {
  56. if (Event.current.type == EventType.Repaint)
  57. {
  58. // If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the vectoscope data
  59. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
  60. InternalEditorUtility.RepaintAllViews();
  61. // Sizing
  62. float size = 0f;
  63. if (r.width < r.height)
  64. {
  65. size = m_VectorscopeTexture != null
  66. ? Mathf.Min(m_VectorscopeTexture.width, r.width - 35f)
  67. : r.width;
  68. }
  69. else
  70. {
  71. size = m_VectorscopeTexture != null
  72. ? Mathf.Min(m_VectorscopeTexture.height, r.height - 25f)
  73. : r.height;
  74. }
  75. m_MonitorAreaRect = new Rect(
  76. Mathf.Floor(r.x + r.width / 2f - size / 2f),
  77. Mathf.Floor(r.y + r.height / 2f - size / 2f - 5f),
  78. size, size
  79. );
  80. if (m_VectorscopeTexture != null)
  81. {
  82. m_Material.SetFloat("_Exposure", m_MonitorSettings.vectorscopeExposure);
  83. var oldActive = RenderTexture.active;
  84. Graphics.Blit(null, m_VectorscopeTexture, m_Material, m_MonitorSettings.vectorscopeShowBackground ? 0 : 1);
  85. RenderTexture.active = oldActive;
  86. Graphics.DrawTexture(m_MonitorAreaRect, m_VectorscopeTexture);
  87. var color = Color.white;
  88. const float kTickSize = 10f;
  89. const int kTickCount = 24;
  90. float radius = m_MonitorAreaRect.width / 2f;
  91. float midX = m_MonitorAreaRect.x + radius;
  92. float midY = m_MonitorAreaRect.y + radius;
  93. var center = new Vector2(midX, midY);
  94. // Cross
  95. color.a *= 0.5f;
  96. Handles.color = color;
  97. Handles.DrawLine(new Vector2(midX, m_MonitorAreaRect.y), new Vector2(midX, m_MonitorAreaRect.y + m_MonitorAreaRect.height));
  98. Handles.DrawLine(new Vector2(m_MonitorAreaRect.x, midY), new Vector2(m_MonitorAreaRect.x + m_MonitorAreaRect.width, midY));
  99. if (m_MonitorAreaRect.width > 100f)
  100. {
  101. color.a = 1f;
  102. // Ticks
  103. Handles.color = color;
  104. for (int i = 0; i < kTickCount; i++)
  105. {
  106. float a = (float)i / (float)kTickCount;
  107. float theta = a * (Mathf.PI * 2f);
  108. float tx = Mathf.Cos(theta + (Mathf.PI / 2f));
  109. float ty = Mathf.Sin(theta - (Mathf.PI / 2f));
  110. var innerVec = center + new Vector2(tx, ty) * (radius - kTickSize);
  111. var outerVec = center + new Vector2(tx, ty) * radius;
  112. Handles.DrawAAPolyLine(3f, innerVec, outerVec);
  113. }
  114. // Labels (where saturation reaches 75%)
  115. color.a = 1f;
  116. var oldColor = GUI.color;
  117. GUI.color = color * 2f;
  118. var point = new Vector2(-0.254f, -0.750f) * radius + center;
  119. var rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  120. GUI.Label(rect, "[R]", FxStyles.tickStyleCenter);
  121. point = new Vector2(-0.497f, 0.629f) * radius + center;
  122. rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  123. GUI.Label(rect, "[G]", FxStyles.tickStyleCenter);
  124. point = new Vector2(0.750f, 0.122f) * radius + center;
  125. rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  126. GUI.Label(rect, "[B]", FxStyles.tickStyleCenter);
  127. point = new Vector2(-0.750f, -0.122f) * radius + center;
  128. rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  129. GUI.Label(rect, "[Y]", FxStyles.tickStyleCenter);
  130. point = new Vector2(0.254f, 0.750f) * radius + center;
  131. rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  132. GUI.Label(rect, "[C]", FxStyles.tickStyleCenter);
  133. point = new Vector2(0.497f, -0.629f) * radius + center;
  134. rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
  135. GUI.Label(rect, "[M]", FxStyles.tickStyleCenter);
  136. GUI.color = oldColor;
  137. }
  138. }
  139. }
  140. }
  141. public override void OnFrameData(RenderTexture source)
  142. {
  143. if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
  144. return;
  145. if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
  146. return;
  147. float ratio = (float)source.width / (float)source.height;
  148. int h = 384;
  149. int w = Mathf.FloorToInt(h * ratio);
  150. var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
  151. Graphics.Blit(source, rt);
  152. ComputeVectorscope(rt);
  153. m_BaseEditor.Repaint();
  154. RenderTexture.ReleaseTemporary(rt);
  155. }
  156. void CreateBuffer(int width, int height)
  157. {
  158. m_Buffer = new ComputeBuffer(width * height, sizeof(uint));
  159. }
  160. void ComputeVectorscope(RenderTexture source)
  161. {
  162. if (m_Buffer == null)
  163. {
  164. CreateBuffer(source.width, source.height);
  165. }
  166. else if (m_Buffer.count != (source.width * source.height))
  167. {
  168. m_Buffer.Release();
  169. CreateBuffer(source.width, source.height);
  170. }
  171. var cs = m_ComputeShader;
  172. int kernel = cs.FindKernel("KVectorscopeClear");
  173. cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
  174. cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
  175. cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
  176. kernel = cs.FindKernel("KVectorscope");
  177. cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
  178. cs.SetTexture(kernel, "_Source", source);
  179. cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
  180. cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
  181. cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
  182. if (m_VectorscopeTexture == null || m_VectorscopeTexture.width != source.width || m_VectorscopeTexture.height != source.height)
  183. {
  184. GraphicsUtils.Destroy(m_VectorscopeTexture);
  185. m_VectorscopeTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
  186. {
  187. hideFlags = HideFlags.DontSave,
  188. wrapMode = TextureWrapMode.Clamp,
  189. filterMode = FilterMode.Bilinear
  190. };
  191. }
  192. if (m_Material == null)
  193. m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Vectorscope Render")) { hideFlags = HideFlags.DontSave };
  194. m_Material.SetBuffer("_Vectorscope", m_Buffer);
  195. m_Material.SetVector("_Size", new Vector2(m_VectorscopeTexture.width, m_VectorscopeTexture.height));
  196. }
  197. }
  198. }