| | |
| | | using UnityEditorInternal; |
| | | using UnityEngine; |
| | | using UnityEngine.PostProcessing; |
| | | |
| | | namespace UnityEditor.PostProcessing |
| | | { |
| | | public class VectorscopeMonitor : PostProcessingMonitor |
| | | { |
| | | static GUIContent s_MonitorTitle = new GUIContent("Vectorscope"); |
| | | |
| | | ComputeShader m_ComputeShader; |
| | | ComputeBuffer m_Buffer; |
| | | Material m_Material; |
| | | RenderTexture m_VectorscopeTexture; |
| | | Rect m_MonitorAreaRect; |
| | | |
| | | public VectorscopeMonitor() |
| | | { |
| | | m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/VectorscopeCompute.compute"); |
| | | } |
| | | |
| | | public override void Dispose() |
| | | { |
| | | GraphicsUtils.Destroy(m_Material); |
| | | GraphicsUtils.Destroy(m_VectorscopeTexture); |
| | | |
| | | if (m_Buffer != null) |
| | | m_Buffer.Release(); |
| | | |
| | | m_Material = null; |
| | | m_VectorscopeTexture = null; |
| | | m_Buffer = null; |
| | | } |
| | | |
| | | public override bool IsSupported() |
| | | { |
| | | return m_ComputeShader != null && GraphicsUtils.supportsDX11; |
| | | } |
| | | |
| | | public override GUIContent GetMonitorTitle() |
| | | { |
| | | return s_MonitorTitle; |
| | | } |
| | | |
| | | public override void OnMonitorSettings() |
| | | { |
| | | EditorGUI.BeginChangeCheck(); |
| | | |
| | | bool refreshOnPlay = m_MonitorSettings.refreshOnPlay; |
| | | float exposure = m_MonitorSettings.vectorscopeExposure; |
| | | bool showBackground = m_MonitorSettings.vectorscopeShowBackground; |
| | | |
| | | refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the vectorscope in play mode; this may impact performances."), FxStyles.preButton); |
| | | exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f)); |
| | | showBackground = GUILayout.Toggle(showBackground, new GUIContent(FxStyles.checkerIcon, "Show an YUV background in the vectorscope."), FxStyles.preButton); |
| | | |
| | | if (EditorGUI.EndChangeCheck()) |
| | | { |
| | | Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Vectorscope Settings Changed"); |
| | | m_MonitorSettings.refreshOnPlay = refreshOnPlay; |
| | | m_MonitorSettings.vectorscopeExposure = exposure; |
| | | m_MonitorSettings.vectorscopeShowBackground = showBackground; |
| | | InternalEditorUtility.RepaintAllViews(); |
| | | } |
| | | } |
| | | |
| | | public override void OnMonitorGUI(Rect r) |
| | | { |
| | | if (Event.current.type == EventType.Repaint) |
| | | { |
| | | // If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the vectoscope data |
| | | if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0)) |
| | | InternalEditorUtility.RepaintAllViews(); |
| | | |
| | | // Sizing |
| | | float size = 0f; |
| | | |
| | | if (r.width < r.height) |
| | | { |
| | | size = m_VectorscopeTexture != null |
| | | ? Mathf.Min(m_VectorscopeTexture.width, r.width - 35f) |
| | | : r.width; |
| | | } |
| | | else |
| | | { |
| | | size = m_VectorscopeTexture != null |
| | | ? Mathf.Min(m_VectorscopeTexture.height, r.height - 25f) |
| | | : r.height; |
| | | } |
| | | |
| | | m_MonitorAreaRect = new Rect( |
| | | Mathf.Floor(r.x + r.width / 2f - size / 2f), |
| | | Mathf.Floor(r.y + r.height / 2f - size / 2f - 5f), |
| | | size, size |
| | | ); |
| | | |
| | | if (m_VectorscopeTexture != null) |
| | | { |
| | | m_Material.SetFloat("_Exposure", m_MonitorSettings.vectorscopeExposure); |
| | | |
| | | var oldActive = RenderTexture.active; |
| | | Graphics.Blit(null, m_VectorscopeTexture, m_Material, m_MonitorSettings.vectorscopeShowBackground ? 0 : 1); |
| | | RenderTexture.active = oldActive; |
| | | |
| | | Graphics.DrawTexture(m_MonitorAreaRect, m_VectorscopeTexture); |
| | | |
| | | var color = Color.white; |
| | | const float kTickSize = 10f; |
| | | const int kTickCount = 24; |
| | | |
| | | float radius = m_MonitorAreaRect.width / 2f; |
| | | float midX = m_MonitorAreaRect.x + radius; |
| | | float midY = m_MonitorAreaRect.y + radius; |
| | | var center = new Vector2(midX, midY); |
| | | |
| | | // Cross |
| | | color.a *= 0.5f; |
| | | Handles.color = color; |
| | | Handles.DrawLine(new Vector2(midX, m_MonitorAreaRect.y), new Vector2(midX, m_MonitorAreaRect.y + m_MonitorAreaRect.height)); |
| | | Handles.DrawLine(new Vector2(m_MonitorAreaRect.x, midY), new Vector2(m_MonitorAreaRect.x + m_MonitorAreaRect.width, midY)); |
| | | |
| | | if (m_MonitorAreaRect.width > 100f) |
| | | { |
| | | color.a = 1f; |
| | | |
| | | // Ticks |
| | | Handles.color = color; |
| | | for (int i = 0; i < kTickCount; i++) |
| | | { |
| | | float a = (float)i / (float)kTickCount; |
| | | float theta = a * (Mathf.PI * 2f); |
| | | float tx = Mathf.Cos(theta + (Mathf.PI / 2f)); |
| | | float ty = Mathf.Sin(theta - (Mathf.PI / 2f)); |
| | | var innerVec = center + new Vector2(tx, ty) * (radius - kTickSize); |
| | | var outerVec = center + new Vector2(tx, ty) * radius; |
| | | Handles.DrawAAPolyLine(3f, innerVec, outerVec); |
| | | } |
| | | |
| | | // Labels (where saturation reaches 75%) |
| | | color.a = 1f; |
| | | var oldColor = GUI.color; |
| | | GUI.color = color * 2f; |
| | | |
| | | var point = new Vector2(-0.254f, -0.750f) * radius + center; |
| | | var rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[R]", FxStyles.tickStyleCenter); |
| | | |
| | | point = new Vector2(-0.497f, 0.629f) * radius + center; |
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[G]", FxStyles.tickStyleCenter); |
| | | |
| | | point = new Vector2(0.750f, 0.122f) * radius + center; |
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[B]", FxStyles.tickStyleCenter); |
| | | |
| | | point = new Vector2(-0.750f, -0.122f) * radius + center; |
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[Y]", FxStyles.tickStyleCenter); |
| | | |
| | | point = new Vector2(0.254f, 0.750f) * radius + center; |
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[C]", FxStyles.tickStyleCenter); |
| | | |
| | | point = new Vector2(0.497f, -0.629f) * radius + center; |
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f); |
| | | GUI.Label(rect, "[M]", FxStyles.tickStyleCenter); |
| | | GUI.color = oldColor; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | public override void OnFrameData(RenderTexture source) |
| | | { |
| | | if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay) |
| | | return; |
| | | |
| | | if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0)) |
| | | return; |
| | | |
| | | float ratio = (float)source.width / (float)source.height; |
| | | int h = 384; |
| | | int w = Mathf.FloorToInt(h * ratio); |
| | | |
| | | var rt = RenderTexture.GetTemporary(w, h, 0, source.format); |
| | | Graphics.Blit(source, rt); |
| | | ComputeVectorscope(rt); |
| | | m_BaseEditor.Repaint(); |
| | | RenderTexture.ReleaseTemporary(rt); |
| | | } |
| | | |
| | | void CreateBuffer(int width, int height) |
| | | { |
| | | m_Buffer = new ComputeBuffer(width * height, sizeof(uint)); |
| | | } |
| | | |
| | | void ComputeVectorscope(RenderTexture source) |
| | | { |
| | | if (m_Buffer == null) |
| | | { |
| | | CreateBuffer(source.width, source.height); |
| | | } |
| | | else if (m_Buffer.count != (source.width * source.height)) |
| | | { |
| | | m_Buffer.Release(); |
| | | CreateBuffer(source.width, source.height); |
| | | } |
| | | |
| | | var cs = m_ComputeShader; |
| | | |
| | | int kernel = cs.FindKernel("KVectorscopeClear"); |
| | | cs.SetBuffer(kernel, "_Vectorscope", m_Buffer); |
| | | cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f)); |
| | | cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1); |
| | | |
| | | kernel = cs.FindKernel("KVectorscope"); |
| | | cs.SetBuffer(kernel, "_Vectorscope", m_Buffer); |
| | | cs.SetTexture(kernel, "_Source", source); |
| | | cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0); |
| | | cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f)); |
| | | cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1); |
| | | |
| | | if (m_VectorscopeTexture == null || m_VectorscopeTexture.width != source.width || m_VectorscopeTexture.height != source.height) |
| | | { |
| | | GraphicsUtils.Destroy(m_VectorscopeTexture); |
| | | m_VectorscopeTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear) |
| | | { |
| | | hideFlags = HideFlags.DontSave, |
| | | wrapMode = TextureWrapMode.Clamp, |
| | | filterMode = FilterMode.Bilinear |
| | | }; |
| | | } |
| | | |
| | | if (m_Material == null) |
| | | m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Vectorscope Render")) { hideFlags = HideFlags.DontSave }; |
| | | |
| | | m_Material.SetBuffer("_Vectorscope", m_Buffer); |
| | | m_Material.SetVector("_Size", new Vector2(m_VectorscopeTexture.width, m_VectorscopeTexture.height)); |
| | | } |
| | | } |
| | | } |
| | | using UnityEditorInternal;
|
| | | using UnityEngine;
|
| | | using UnityEngine.PostProcessing;
|
| | |
|
| | | namespace UnityEditor.PostProcessing
|
| | | {
|
| | | public class VectorscopeMonitor : PostProcessingMonitor
|
| | | {
|
| | | static GUIContent s_MonitorTitle = new GUIContent("Vectorscope");
|
| | |
|
| | | ComputeShader m_ComputeShader;
|
| | | ComputeBuffer m_Buffer;
|
| | | Material m_Material;
|
| | | RenderTexture m_VectorscopeTexture;
|
| | | Rect m_MonitorAreaRect;
|
| | |
|
| | | public VectorscopeMonitor()
|
| | | {
|
| | | m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/VectorscopeCompute.compute");
|
| | | }
|
| | |
|
| | | public override void Dispose()
|
| | | {
|
| | | GraphicsUtils.Destroy(m_Material);
|
| | | GraphicsUtils.Destroy(m_VectorscopeTexture);
|
| | |
|
| | | if (m_Buffer != null)
|
| | | m_Buffer.Release();
|
| | |
|
| | | m_Material = null;
|
| | | m_VectorscopeTexture = null;
|
| | | m_Buffer = null;
|
| | | }
|
| | |
|
| | | public override bool IsSupported()
|
| | | {
|
| | | return m_ComputeShader != null && GraphicsUtils.supportsDX11;
|
| | | }
|
| | |
|
| | | public override GUIContent GetMonitorTitle()
|
| | | {
|
| | | return s_MonitorTitle;
|
| | | }
|
| | |
|
| | | public override void OnMonitorSettings()
|
| | | {
|
| | | EditorGUI.BeginChangeCheck();
|
| | |
|
| | | bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
|
| | | float exposure = m_MonitorSettings.vectorscopeExposure;
|
| | | bool showBackground = m_MonitorSettings.vectorscopeShowBackground;
|
| | |
|
| | | refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the vectorscope in play mode; this may impact performances."), FxStyles.preButton);
|
| | | exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
|
| | | showBackground = GUILayout.Toggle(showBackground, new GUIContent(FxStyles.checkerIcon, "Show an YUV background in the vectorscope."), FxStyles.preButton);
|
| | |
|
| | | if (EditorGUI.EndChangeCheck())
|
| | | {
|
| | | Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Vectorscope Settings Changed");
|
| | | m_MonitorSettings.refreshOnPlay = refreshOnPlay;
|
| | | m_MonitorSettings.vectorscopeExposure = exposure;
|
| | | m_MonitorSettings.vectorscopeShowBackground = showBackground;
|
| | | InternalEditorUtility.RepaintAllViews();
|
| | | }
|
| | | }
|
| | |
|
| | | public override void OnMonitorGUI(Rect r)
|
| | | {
|
| | | if (Event.current.type == EventType.Repaint)
|
| | | {
|
| | | // If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the vectoscope data
|
| | | if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
| | | InternalEditorUtility.RepaintAllViews();
|
| | |
|
| | | // Sizing
|
| | | float size = 0f;
|
| | |
|
| | | if (r.width < r.height)
|
| | | {
|
| | | size = m_VectorscopeTexture != null
|
| | | ? Mathf.Min(m_VectorscopeTexture.width, r.width - 35f)
|
| | | : r.width;
|
| | | }
|
| | | else
|
| | | {
|
| | | size = m_VectorscopeTexture != null
|
| | | ? Mathf.Min(m_VectorscopeTexture.height, r.height - 25f)
|
| | | : r.height;
|
| | | }
|
| | |
|
| | | m_MonitorAreaRect = new Rect(
|
| | | Mathf.Floor(r.x + r.width / 2f - size / 2f),
|
| | | Mathf.Floor(r.y + r.height / 2f - size / 2f - 5f),
|
| | | size, size
|
| | | );
|
| | |
|
| | | if (m_VectorscopeTexture != null)
|
| | | {
|
| | | m_Material.SetFloat("_Exposure", m_MonitorSettings.vectorscopeExposure);
|
| | |
|
| | | var oldActive = RenderTexture.active;
|
| | | Graphics.Blit(null, m_VectorscopeTexture, m_Material, m_MonitorSettings.vectorscopeShowBackground ? 0 : 1);
|
| | | RenderTexture.active = oldActive;
|
| | |
|
| | | Graphics.DrawTexture(m_MonitorAreaRect, m_VectorscopeTexture);
|
| | |
|
| | | var color = Color.white;
|
| | | const float kTickSize = 10f;
|
| | | const int kTickCount = 24;
|
| | |
|
| | | float radius = m_MonitorAreaRect.width / 2f;
|
| | | float midX = m_MonitorAreaRect.x + radius;
|
| | | float midY = m_MonitorAreaRect.y + radius;
|
| | | var center = new Vector2(midX, midY);
|
| | |
|
| | | // Cross
|
| | | color.a *= 0.5f;
|
| | | Handles.color = color;
|
| | | Handles.DrawLine(new Vector2(midX, m_MonitorAreaRect.y), new Vector2(midX, m_MonitorAreaRect.y + m_MonitorAreaRect.height));
|
| | | Handles.DrawLine(new Vector2(m_MonitorAreaRect.x, midY), new Vector2(m_MonitorAreaRect.x + m_MonitorAreaRect.width, midY));
|
| | |
|
| | | if (m_MonitorAreaRect.width > 100f)
|
| | | {
|
| | | color.a = 1f;
|
| | |
|
| | | // Ticks
|
| | | Handles.color = color;
|
| | | for (int i = 0; i < kTickCount; i++)
|
| | | {
|
| | | float a = (float)i / (float)kTickCount;
|
| | | float theta = a * (Mathf.PI * 2f);
|
| | | float tx = Mathf.Cos(theta + (Mathf.PI / 2f));
|
| | | float ty = Mathf.Sin(theta - (Mathf.PI / 2f));
|
| | | var innerVec = center + new Vector2(tx, ty) * (radius - kTickSize);
|
| | | var outerVec = center + new Vector2(tx, ty) * radius;
|
| | | Handles.DrawAAPolyLine(3f, innerVec, outerVec);
|
| | | }
|
| | |
|
| | | // Labels (where saturation reaches 75%)
|
| | | color.a = 1f;
|
| | | var oldColor = GUI.color;
|
| | | GUI.color = color * 2f;
|
| | |
|
| | | var point = new Vector2(-0.254f, -0.750f) * radius + center;
|
| | | var rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[R]", FxStyles.tickStyleCenter);
|
| | |
|
| | | point = new Vector2(-0.497f, 0.629f) * radius + center;
|
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[G]", FxStyles.tickStyleCenter);
|
| | |
|
| | | point = new Vector2(0.750f, 0.122f) * radius + center;
|
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[B]", FxStyles.tickStyleCenter);
|
| | |
|
| | | point = new Vector2(-0.750f, -0.122f) * radius + center;
|
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[Y]", FxStyles.tickStyleCenter);
|
| | |
|
| | | point = new Vector2(0.254f, 0.750f) * radius + center;
|
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[C]", FxStyles.tickStyleCenter);
|
| | |
|
| | | point = new Vector2(0.497f, -0.629f) * radius + center;
|
| | | rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
| | | GUI.Label(rect, "[M]", FxStyles.tickStyleCenter);
|
| | | GUI.color = oldColor;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | public override void OnFrameData(RenderTexture source)
|
| | | {
|
| | | if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
|
| | | return;
|
| | |
|
| | | if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
| | | return;
|
| | |
|
| | | float ratio = (float)source.width / (float)source.height;
|
| | | int h = 384;
|
| | | int w = Mathf.FloorToInt(h * ratio);
|
| | |
|
| | | var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
|
| | | Graphics.Blit(source, rt);
|
| | | ComputeVectorscope(rt);
|
| | | m_BaseEditor.Repaint();
|
| | | RenderTexture.ReleaseTemporary(rt);
|
| | | }
|
| | |
|
| | | void CreateBuffer(int width, int height)
|
| | | {
|
| | | m_Buffer = new ComputeBuffer(width * height, sizeof(uint));
|
| | | }
|
| | |
|
| | | void ComputeVectorscope(RenderTexture source)
|
| | | {
|
| | | if (m_Buffer == null)
|
| | | {
|
| | | CreateBuffer(source.width, source.height);
|
| | | }
|
| | | else if (m_Buffer.count != (source.width * source.height))
|
| | | {
|
| | | m_Buffer.Release();
|
| | | CreateBuffer(source.width, source.height);
|
| | | }
|
| | |
|
| | | var cs = m_ComputeShader;
|
| | |
|
| | | int kernel = cs.FindKernel("KVectorscopeClear");
|
| | | cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
|
| | | cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
|
| | | cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
|
| | |
|
| | | kernel = cs.FindKernel("KVectorscope");
|
| | | cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
|
| | | cs.SetTexture(kernel, "_Source", source);
|
| | | cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
|
| | | cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
|
| | | cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
|
| | |
|
| | | if (m_VectorscopeTexture == null || m_VectorscopeTexture.width != source.width || m_VectorscopeTexture.height != source.height)
|
| | | {
|
| | | GraphicsUtils.Destroy(m_VectorscopeTexture);
|
| | | m_VectorscopeTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
|
| | | {
|
| | | hideFlags = HideFlags.DontSave,
|
| | | wrapMode = TextureWrapMode.Clamp,
|
| | | filterMode = FilterMode.Bilinear
|
| | | };
|
| | | }
|
| | |
|
| | | if (m_Material == null)
|
| | | m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Vectorscope Render")) { hideFlags = HideFlags.DontSave };
|
| | |
|
| | | m_Material.SetBuffer("_Vectorscope", m_Buffer);
|
| | | m_Material.SetVector("_Size", new Vector2(m_VectorscopeTexture.width, m_VectorscopeTexture.height));
|
| | | }
|
| | | }
|
| | | }
|