// =============================================================================== // MeasureTool - Smart Scene Measurement & Analysis // // Creator: Scove // Last Updated: 2024-05-08 // Version: 3.0 // // Purpose: // A professional measurement tool that visualizes distances between objects // in the Scene View. Supports single distance, chain distance, and axis breakdown. // // Key Features: // 1. Two-Point & Chain Mode: Select 2 or more objects to measure. // 2. Axis Breakdown: Shows Delta X, Y, Z with Unity-standard colors. // 3. Scene Overlay: On-screen toggle and settings directly in Scene View. // 4. Readable UI: High-contrast labels with background for any lighting condition. // // How to Use: // 1. Place in an 'Editor' folder. // 2. Select 2 or more GameObjects in the Hierarchy. // 3. Use the "MEASURE" overlay in the Scene View to toggle axis details. // =============================================================================== using UnityEditor; using UnityEngine; using System.Collections.Generic; namespace Editor { [InitializeOnLoad] public class MeasureTool { // Settings (Persisted via EditorPrefs) private static bool IsEnabled = true; private static bool ShowAxisBreakdown = true; private static bool ShowTotalDistance = true; static MeasureTool() { IsEnabled = EditorPrefs.GetBool("MeasureTool_Enabled", true); ShowAxisBreakdown = EditorPrefs.GetBool("MeasureTool_Axis", true); SceneView.duringSceneGui += OnSceneGUI; } private static void OnSceneGUI(SceneView view) { DrawOverlay(view); if (!IsEnabled || Selection.transforms.Length < 2) return; Transform[] selected = Selection.transforms; // Draw measurement for each pair in the selection for (int i = 0; i < selected.Length - 1; i++) { DrawDistance(selected[i].position, selected[i + 1].position); } } private static void DrawDistance(Vector3 p1, Vector3 p2) { float distance = Vector3.Distance(p1, p2); Vector3 midPoint = (p1 + p2) * 0.5f; // 1. Draw the Main Dotted Line Handles.color = Color.cyan; Handles.DrawDottedLine(p1, p2, 4f); // Draw small spheres at start/end points for clarity Handles.SphereHandleCap(0, p1, Quaternion.identity, 0.1f, EventType.Repaint); Handles.SphereHandleCap(0, p2, Quaternion.identity, 0.1f, EventType.Repaint); // 2. Draw Main Label (Total Distance) if (ShowTotalDistance) { GUIStyle labelStyle = GetLabelStyle(Color.white, new Color(0, 0, 0, 0.6f)); string labelText = $"Dist: {distance:F2}m"; Handles.Label(midPoint + (Vector3.up * 0.1f), labelText, labelStyle); } // 3. Draw Axis Breakdown (X, Y, Z Delta) if (ShowAxisBreakdown) { Vector3 delta = new Vector3(Mathf.Abs(p1.x - p2.x), Mathf.Abs(p1.y - p2.y), Mathf.Abs(p1.z - p2.z)); // We only show axis delta if it's significant (> 0.01) string axisText = ""; if (delta.x > 0.01f) axisText += $"X: {delta.x:F2} "; if (delta.y > 0.01f) axisText += $"Y: {delta.y:F2} "; if (delta.z > 0.01f) axisText += $"Z: {delta.z:F2}"; if (!string.IsNullOrEmpty(axisText)) { GUIStyle axisStyle = GetLabelStyle(Color.white, new Color(0.1f, 0.1f, 0.1f, 0.8f)); axisStyle.richText = true; axisStyle.fontSize = 11; Handles.Label(midPoint - (Vector3.up * 0.3f), axisText, axisStyle); } } } private static void DrawOverlay(SceneView view) { Handles.BeginGUI(); // Positioning the overlay in the bottom right float width = 140; float height = 90; Rect rect = new Rect(view.position.width - width - 10, view.position.height - height - 30, width, height); GUILayout.BeginArea(rect, "MEASURE TOOL", GUI.skin.window); EditorGUI.BeginChangeCheck(); IsEnabled = GUILayout.Toggle(IsEnabled, " Enable Tool"); ShowTotalDistance = GUILayout.Toggle(ShowTotalDistance, " Show Total"); ShowAxisBreakdown = GUILayout.Toggle(ShowAxisBreakdown, " Axis Breakdown"); if (EditorGUI.EndChangeCheck()) { EditorPrefs.SetBool("MeasureTool_Enabled", IsEnabled); EditorPrefs.SetBool("MeasureTool_Axis", ShowAxisBreakdown); SceneView.RepaintAll(); } GUILayout.EndArea(); Handles.EndGUI(); } private static GUIStyle GetLabelStyle(Color textColor, Color bgColor) { GUIStyle style = new GUIStyle(); style.normal.textColor = textColor; style.fontSize = 13; style.fontStyle = FontStyle.Bold; style.alignment = TextAnchor.MiddleCenter; style.padding = new RectOffset(4, 4, 2, 2); // Create a background texture dynamically Texture2D tex = new Texture2D(1, 1); tex.SetPixel(0, 0, bgColor); tex.Apply(); style.normal.background = tex; return style; } } }