using UnityEngine; using UnityEngine.PostProcessing; namespace UnityEditor.PostProcessing { using Settings = BloomModel.Settings; [PostProcessingModelEditor(typeof(BloomModel))] public class BloomModelEditor : PostProcessingModelEditor { struct BloomSettings { public SerializedProperty intensity; public SerializedProperty threshold; public SerializedProperty softKnee; public SerializedProperty radius; public SerializedProperty antiFlicker; } struct LensDirtSettings { public SerializedProperty texture; public SerializedProperty intensity; } BloomSettings m_Bloom; LensDirtSettings m_LensDirt; public override void OnEnable() { m_Bloom = new BloomSettings { intensity = FindSetting((Settings x) => x.bloom.intensity), threshold = FindSetting((Settings x) => x.bloom.threshold), softKnee = FindSetting((Settings x) => x.bloom.softKnee), radius = FindSetting((Settings x) => x.bloom.radius), antiFlicker = FindSetting((Settings x) => x.bloom.antiFlicker) }; m_LensDirt = new LensDirtSettings { texture = FindSetting((Settings x) => x.lensDirt.texture), intensity = FindSetting((Settings x) => x.lensDirt.intensity) }; } public override void OnInspectorGUI() { EditorGUILayout.Space(); PrepareGraph(); DrawGraph(); EditorGUILayout.Space(); EditorGUILayout.PropertyField(m_Bloom.intensity); EditorGUILayout.PropertyField(m_Bloom.threshold, EditorGUIHelper.GetContent("Threshold (Gamma)")); EditorGUILayout.PropertyField(m_Bloom.softKnee); EditorGUILayout.PropertyField(m_Bloom.radius); EditorGUILayout.PropertyField(m_Bloom.antiFlicker); EditorGUILayout.Space(); EditorGUILayout.LabelField("Dirt", EditorStyles.boldLabel); EditorGUI.indentLevel++; EditorGUILayout.PropertyField(m_LensDirt.texture); EditorGUILayout.PropertyField(m_LensDirt.intensity); EditorGUI.indentLevel--; } #region Graph float m_GraphThreshold; float m_GraphKnee; float m_GraphIntensity; // Number of vertices in curve const int k_CurveResolution = 48; // Vertex buffers Vector3[] m_RectVertices = new Vector3[4]; Vector3[] m_LineVertices = new Vector3[2]; Vector3[] m_CurveVertices = new Vector3[k_CurveResolution]; Rect m_RectGraph; float m_RangeX; float m_RangeY; float ResponseFunction(float x) { var rq = Mathf.Clamp(x - m_GraphThreshold + m_GraphKnee, 0, m_GraphKnee * 2); rq = rq * rq * 0.25f / m_GraphKnee; return Mathf.Max(rq, x - m_GraphThreshold) * m_GraphIntensity; } // Transform a point into the graph rect Vector3 PointInRect(float x, float y) { x = Mathf.Lerp(m_RectGraph.x, m_RectGraph.xMax, x / m_RangeX); y = Mathf.Lerp(m_RectGraph.yMax, m_RectGraph.y, y / m_RangeY); return new Vector3(x, y, 0); } // Draw a line in the graph rect void DrawLine(float x1, float y1, float x2, float y2, float grayscale) { m_LineVertices[0] = PointInRect(x1, y1); m_LineVertices[1] = PointInRect(x2, y2); Handles.color = Color.white * grayscale; Handles.DrawAAPolyLine(2.0f, m_LineVertices); } // Draw a rect in the graph rect void DrawRect(float x1, float y1, float x2, float y2, float fill, float line) { m_RectVertices[0] = PointInRect(x1, y1); m_RectVertices[1] = PointInRect(x2, y1); m_RectVertices[2] = PointInRect(x2, y2); m_RectVertices[3] = PointInRect(x1, y2); Handles.DrawSolidRectangleWithOutline( m_RectVertices, fill < 0 ? Color.clear : Color.white * fill, line < 0 ? Color.clear : Color.white * line ); } // Update internal state with a given bloom instance public void PrepareGraph() { var bloom = (BloomModel)target; m_RangeX = 5f; m_RangeY = 2f; m_GraphThreshold = bloom.settings.bloom.thresholdLinear; m_GraphKnee = bloom.settings.bloom.softKnee * m_GraphThreshold + 1e-5f; // Intensity is capped to prevent sampling errors m_GraphIntensity = Mathf.Min(bloom.settings.bloom.intensity, 10f); } // Draw the graph at the current position public void DrawGraph() { using (new GUILayout.HorizontalScope()) { GUILayout.Space(EditorGUI.indentLevel * 15f); m_RectGraph = GUILayoutUtility.GetRect(128, 80); } // Background DrawRect(0, 0, m_RangeX, m_RangeY, 0.1f, 0.4f); // Soft-knee range DrawRect(m_GraphThreshold - m_GraphKnee, 0, m_GraphThreshold + m_GraphKnee, m_RangeY, 0.25f, -1); // Horizontal lines for (var i = 1; i < m_RangeY; i++) DrawLine(0, i, m_RangeX, i, 0.4f); // Vertical lines for (var i = 1; i < m_RangeX; i++) DrawLine(i, 0, i, m_RangeY, 0.4f); // Label Handles.Label( PointInRect(0, m_RangeY) + Vector3.right, "Brightness Response (linear)", EditorStyles.miniLabel ); // Threshold line DrawLine(m_GraphThreshold, 0, m_GraphThreshold, m_RangeY, 0.6f); // Response curve var vcount = 0; while (vcount < k_CurveResolution) { var x = m_RangeX * vcount / (k_CurveResolution - 1); var y = ResponseFunction(x); if (y < m_RangeY) { m_CurveVertices[vcount++] = PointInRect(x, y); } else { if (vcount > 1) { // Extend the last segment to the top edge of the rect. var v1 = m_CurveVertices[vcount - 2]; var v2 = m_CurveVertices[vcount - 1]; var clip = (m_RectGraph.y - v1.y) / (v2.y - v1.y); m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip; } break; } } if (vcount > 1) { Handles.color = Color.white * 0.9f; Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices); } } #endregion } }