Skip to content

Instantly share code, notes, and snippets.

@orangy
Created October 26, 2019 20:15
Show Gist options
  • Save orangy/8f5626fad791df28cf5cba8c4c5aa28d to your computer and use it in GitHub Desktop.
Save orangy/8f5626fad791df28cf5cba8c4c5aa28d to your computer and use it in GitHub Desktop.
Improve transform inspector to show and edit bounds
using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;
using Component = UnityEngine.Component;
namespace Editor.Customizations
{
[CustomEditor(typeof(Transform))]
public class TransformCustomizedEditor : UnityEditor.Editor
{
private UnityEditor.Editor myDefaultEditor;
private Transform myTransform;
private static bool ourLockAspect = true;
private static GUIContent ourLockedContent;
private static GUIContent ourUnlockedContent;
private static GUIStyle ourLockContentStyle;
void OnEnable()
{
if (ourLockedContent == null)
{
ourLockedContent = new GUIContent()
{
text = "Bounds",
tooltip = "Aspect Ratio is locked, click to unlock",
image = EditorGUIUtility.IconContent("InspectorLock", "").image
};
ourUnlockedContent = new GUIContent()
{
text = "Bounds",
tooltip = "Aspect Ratio is unlocked, click to lock",
image = EditorGUIUtility.IconContent("d_InspectorLock", "").image
};
}
// When this inspector is created, also create the built-in inspector
myDefaultEditor = CreateEditor(targets, Type.GetType("UnityEditor.TransformInspector, UnityEditor"));
myTransform = target as Transform;
}
void OnDisable()
{
// When OnDisable is called, the default editor we created should be destroyed to avoid memory leakage.
// Also, make sure to call any required methods like OnDisable
var disableMethod = myDefaultEditor.GetType().GetMethod("OnDisable",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (disableMethod != null)
disableMethod.Invoke(myDefaultEditor, null);
DestroyImmediate(myDefaultEditor);
}
public override void OnInspectorGUI()
{
myDefaultEditor.OnInspectorGUI();
if (TryGetBounds(myTransform, out var bounds))
EditorBounds(bounds);
}
private static bool TryGetBounds(Component transform, out Bounds bounds)
{
var gameObject = transform.gameObject;
if (gameObject.TryGetComponent<Collider>(out var collider))
{
bounds = collider.bounds;
return true;
}
if (gameObject.TryGetComponent<Renderer>(out var renderer))
{
bounds = renderer.bounds;
return true;
}
bounds = default;
return false;
}
[DrawGizmo(GizmoType.Selected)]
static void DrawGizmosSelected(Transform transform, GizmoType gizmoType)
{
if (TryGetBounds(transform, out var bounds))
Gizmos.DrawWireCube(bounds.center, bounds.extents * 2);
}
private void EditorBounds(Bounds bounds)
{
EditorGUILayout.Space();
var lockedContent = ourLockAspect ? ourLockedContent : ourUnlockedContent;
if (ourLockContentStyle == null)
{
// This cannot be done in OnEnable, because skin is not loaded yet :(
ourLockContentStyle = new GUIStyle(EditorStyles.boldLabel)
{
fontStyle = FontStyle.Bold
};
}
ourLockAspect = GUILayout.Toggle(ourLockAspect, lockedContent, ourLockContentStyle);
var originalSize = bounds.extents * 2;
var newSize = EditorGUILayout.Vector3Field("Size", originalSize);
var localScale = myTransform.localScale;
// fullSize = originalSize / originalScale
// newScale = newSize / fullSize
if (!Mathf.Approximately(newSize.x, originalSize.x))
{
var aspect = newSize.x / originalSize.x;
if (ourLockAspect)
localScale *= aspect;
else
localScale.x *= aspect;
}
if (!Mathf.Approximately(newSize.y, originalSize.y))
{
var aspect = newSize.y / originalSize.y;
if (ourLockAspect)
localScale *= aspect;
else
localScale.y *= aspect;
}
if (!Mathf.Approximately(newSize.z, originalSize.z))
{
var aspect = newSize.z / originalSize.z;
if (ourLockAspect)
localScale *= aspect;
else
localScale.z *= aspect;
}
myTransform.localScale = localScale;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment