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

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));
}
}
}