mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
fix: ScaleAdjuster not usable when gizmos are not enabled (#595)
Fixes: #588, #589
This commit is contained in:
parent
de71e1f544
commit
2ad324380e
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
@ -12,133 +9,17 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
private SerializedProperty _scale;
|
||||
|
||||
private ModularAvatarScaleAdjuster[] _sortedTargets;
|
||||
private Vector3[] _originalScales;
|
||||
|
||||
private Vector3 gizmoScale = Vector3.one;
|
||||
|
||||
private bool _adjustChildPositions;
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
_scale = serializedObject.FindProperty("m_Scale");
|
||||
|
||||
_sortedTargets = targets.Cast<ModularAvatarScaleAdjuster>().OrderBy(TransformDepth).ToArray();
|
||||
_originalScales = _sortedTargets.Select(t => t.Scale).ToArray();
|
||||
}
|
||||
|
||||
private int TransformDepth(ModularAvatarScaleAdjuster obj)
|
||||
{
|
||||
var t = obj.transform;
|
||||
var depth = 0;
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
depth++;
|
||||
t = t.parent;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSceneGUI()
|
||||
{
|
||||
Selection.selectionChanged -= UnhideTools;
|
||||
Selection.selectionChanged += UnhideTools;
|
||||
Tools.hidden = (Tools.current == Tool.Scale);
|
||||
if (!Tools.hidden) return;
|
||||
|
||||
var handlePos = _sortedTargets[0].transform;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var handleSize = HandleUtility.GetHandleSize(handlePos.position);
|
||||
gizmoScale = Handles.ScaleHandle(gizmoScale, handlePos.position, handlePos.rotation, handleSize);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
for (int i = 0; i < _sortedTargets.Length; i++)
|
||||
{
|
||||
UpdateScale(i, handlePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScale(int i, Transform refTransform)
|
||||
{
|
||||
var xform = _sortedTargets[i].transform;
|
||||
var target = _sortedTargets[i];
|
||||
|
||||
Matrix4x4 initialTransform = xform.parent.localToWorldMatrix * Matrix4x4.TRS(
|
||||
xform.localPosition,
|
||||
xform.localRotation,
|
||||
xform.localScale
|
||||
);
|
||||
|
||||
Matrix4x4 initialScale = Matrix4x4.TRS(
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
_originalScales[i]
|
||||
);
|
||||
|
||||
Matrix4x4 newTransform = refTransform.localToWorldMatrix * Matrix4x4.TRS(
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
gizmoScale
|
||||
);
|
||||
|
||||
float scaleX = TransformVec(Vector3.right);
|
||||
float scaleY = TransformVec(Vector3.up);
|
||||
float scaleZ = TransformVec(Vector3.forward);
|
||||
|
||||
Undo.RecordObject(target, "Adjust scale");
|
||||
var targetL2W = target.transform.localToWorldMatrix;
|
||||
var baseToScaleCoord = (targetL2W * Matrix4x4.Scale(target.Scale)).inverse * targetL2W;
|
||||
|
||||
target.Scale = new Vector3(scaleX, scaleY, scaleZ);
|
||||
|
||||
var scaleToBaseCoord = Matrix4x4.Scale(target.Scale);
|
||||
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(target);
|
||||
|
||||
// Update child positions
|
||||
if (_adjustChildPositions)
|
||||
{
|
||||
var updateTransform = scaleToBaseCoord * baseToScaleCoord;
|
||||
foreach (Transform child in target.transform)
|
||||
{
|
||||
Undo.RecordObject(child, "Adjust scale");
|
||||
child.localPosition = updateTransform.MultiplyPoint(child.localPosition);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(child);
|
||||
}
|
||||
}
|
||||
|
||||
float TransformVec(Vector3 vec)
|
||||
{
|
||||
// first, place our measurement vector into world spoce
|
||||
vec = (initialTransform * initialScale).MultiplyVector(vec);
|
||||
// now put it into reference space
|
||||
vec = refTransform.worldToLocalMatrix.MultiplyVector(vec);
|
||||
// and return using the adjusted scale
|
||||
vec = newTransform.MultiplyVector(vec);
|
||||
// now come back into local space
|
||||
vec = (initialTransform.inverse).MultiplyVector(vec);
|
||||
|
||||
return vec.magnitude;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnhideTools()
|
||||
{
|
||||
Tools.hidden = false;
|
||||
}
|
||||
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(_scale, G("scale_adjuster.scale"));
|
||||
|
||||
_adjustChildPositions = EditorGUILayout.Toggle(G("scale_adjuster.adjust_children"), _adjustChildPositions);
|
||||
ScaleAdjusterTool.AdjustChildPositions = EditorGUILayout.Toggle(G("scale_adjuster.adjust_children"),
|
||||
ScaleAdjusterTool.AdjustChildPositions);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
|
249
Editor/Inspector/ScaleAdjusterTool.cs
Normal file
249
Editor/Inspector/ScaleAdjusterTool.cs
Normal file
@ -0,0 +1,249 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal static class ScaleAdjusterTool
|
||||
{
|
||||
private const string UNDO_STRING = "Adjust scale";
|
||||
public static bool AdjustChildPositions = true;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
Selection.selectionChanged += OnSelectionChanged;
|
||||
}
|
||||
|
||||
abstract class ScaleHolder
|
||||
{
|
||||
public abstract Object Obj { get; }
|
||||
|
||||
public Vector3 InitialScale { get; protected set; }
|
||||
public Vector3 LastScale { get; protected set; }
|
||||
|
||||
public abstract bool IsValid { get; }
|
||||
public abstract Vector3 Scale { get; set; }
|
||||
|
||||
public abstract Matrix4x4 ParentLocalToWorld { get; }
|
||||
public abstract Matrix4x4 LocalBaseTransform { get; }
|
||||
}
|
||||
|
||||
class GameObjectScaler : ScaleHolder
|
||||
{
|
||||
private readonly GameObject _obj;
|
||||
|
||||
public override Object Obj => _obj;
|
||||
|
||||
public GameObjectScaler(GameObject obj)
|
||||
{
|
||||
_obj = obj;
|
||||
LastScale = InitialScale = obj.transform.localScale;
|
||||
}
|
||||
|
||||
public override bool IsValid => _obj != null;
|
||||
|
||||
public override Vector3 Scale
|
||||
{
|
||||
get => _obj.transform.localScale;
|
||||
set
|
||||
{
|
||||
Undo.RecordObject(_obj.transform, UNDO_STRING);
|
||||
|
||||
_obj.transform.localScale = value;
|
||||
LastScale = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Matrix4x4 ParentLocalToWorld => _obj.transform.parent.localToWorldMatrix;
|
||||
|
||||
public override Matrix4x4 LocalBaseTransform => Matrix4x4.TRS(
|
||||
_obj.transform.localPosition,
|
||||
_obj.transform.localRotation,
|
||||
Vector3.one
|
||||
);
|
||||
}
|
||||
|
||||
class AdjusterScaler : ScaleHolder
|
||||
{
|
||||
private readonly ModularAvatarScaleAdjuster _obj;
|
||||
private string UNDO_STRING;
|
||||
|
||||
public override Object Obj => _obj;
|
||||
|
||||
public AdjusterScaler(ModularAvatarScaleAdjuster obj)
|
||||
{
|
||||
_obj = obj;
|
||||
LastScale = InitialScale = obj.Scale;
|
||||
}
|
||||
|
||||
public override bool IsValid => _obj != null;
|
||||
|
||||
public override Vector3 Scale
|
||||
{
|
||||
get => _obj.Scale;
|
||||
set
|
||||
{
|
||||
Undo.RecordObject(_obj, UNDO_STRING);
|
||||
|
||||
var targetL2W = _obj.transform.localToWorldMatrix;
|
||||
var baseToScaleCoord = (targetL2W * Matrix4x4.Scale(_obj.Scale)).inverse * targetL2W;
|
||||
|
||||
_obj.Scale = value;
|
||||
LastScale = value;
|
||||
|
||||
var scaleToBaseCoord = Matrix4x4.Scale(_obj.Scale);
|
||||
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(_obj);
|
||||
|
||||
// Update child positions
|
||||
if (AdjustChildPositions)
|
||||
{
|
||||
var updateTransform = scaleToBaseCoord * baseToScaleCoord;
|
||||
foreach (Transform child in _obj.transform)
|
||||
{
|
||||
Undo.RecordObject(child, UNDO_STRING);
|
||||
child.localPosition = updateTransform.MultiplyPoint(child.localPosition);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Matrix4x4 ParentLocalToWorld => _obj.transform.parent.localToWorldMatrix;
|
||||
|
||||
public override Matrix4x4 LocalBaseTransform => Matrix4x4.TRS(
|
||||
_obj.transform.localPosition,
|
||||
_obj.transform.localRotation,
|
||||
_obj.transform.localScale
|
||||
);
|
||||
}
|
||||
|
||||
private static List<ScaleHolder> _selection = new List<ScaleHolder>();
|
||||
private static bool? _active = null;
|
||||
private static Vector3 _gizmoScale;
|
||||
private static Quaternion _handleRotation;
|
||||
|
||||
private static void OnSelectionChanged()
|
||||
{
|
||||
_selection.Clear();
|
||||
Tools.hidden = false;
|
||||
_active = null;
|
||||
}
|
||||
|
||||
private static void OnSceneGUI(SceneView obj)
|
||||
{
|
||||
if (Tools.current != Tool.Scale)
|
||||
{
|
||||
if (_active == true)
|
||||
{
|
||||
Tools.hidden = false;
|
||||
_active = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldEnable())
|
||||
{
|
||||
Tools.hidden = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var handleSize = HandleUtility.GetHandleSize(Tools.handlePosition);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_gizmoScale = Handles.ScaleHandle(_gizmoScale, Tools.handlePosition, _handleRotation, handleSize);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
foreach (var target in _selection)
|
||||
{
|
||||
UpdateScale(target, _gizmoScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateScale(ScaleHolder target, Vector3 gizmoScale)
|
||||
{
|
||||
var refTransformInv = Matrix4x4.TRS(
|
||||
Tools.handlePosition,
|
||||
_handleRotation,
|
||||
Vector3.one
|
||||
).inverse;
|
||||
var gizmoTransform = Matrix4x4.TRS(
|
||||
Tools.handlePosition,
|
||||
_handleRotation,
|
||||
gizmoScale
|
||||
);
|
||||
|
||||
Matrix4x4 initialTransform = target.ParentLocalToWorld * target.LocalBaseTransform;
|
||||
|
||||
Matrix4x4 initialScale = Matrix4x4.Scale(target.InitialScale);
|
||||
|
||||
float scaleX = TransformVec(Vector3.right);
|
||||
float scaleY = TransformVec(Vector3.up);
|
||||
float scaleZ = TransformVec(Vector3.forward);
|
||||
|
||||
target.Scale = new Vector3(scaleX, scaleY, scaleZ);
|
||||
|
||||
float TransformVec(Vector3 vec)
|
||||
{
|
||||
// first, place our measurement vector into world spoce
|
||||
vec = (initialTransform * initialScale).MultiplyVector(vec);
|
||||
// now put it into reference space
|
||||
vec = refTransformInv.MultiplyVector(vec);
|
||||
// and return using the adjusted scale
|
||||
vec = gizmoTransform.MultiplyVector(vec);
|
||||
// now come back into local space
|
||||
vec = (initialTransform.inverse).MultiplyVector(vec);
|
||||
|
||||
return vec.magnitude;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldEnable()
|
||||
{
|
||||
if (_selection.Any(s => !s.IsValid))
|
||||
{
|
||||
_active = null;
|
||||
}
|
||||
|
||||
if (_selection.Any(s => (s.Scale - s.LastScale).sqrMagnitude > 0.00001f))
|
||||
{
|
||||
_active = null;
|
||||
}
|
||||
|
||||
if (_active.HasValue)
|
||||
{
|
||||
return _active.Value;
|
||||
}
|
||||
|
||||
_selection.Clear();
|
||||
_gizmoScale = Vector3.one;
|
||||
_handleRotation = Tools.handleRotation;
|
||||
bool anyAdjuster = false;
|
||||
|
||||
foreach (var obj in Selection.gameObjects)
|
||||
{
|
||||
var adjuster = obj.GetComponent<ModularAvatarScaleAdjuster>();
|
||||
if (adjuster != null)
|
||||
{
|
||||
_selection.Add(new AdjusterScaler(adjuster));
|
||||
anyAdjuster = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_selection.Add(new GameObjectScaler(obj));
|
||||
}
|
||||
}
|
||||
|
||||
_active = anyAdjuster;
|
||||
return anyAdjuster;
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/ScaleAdjusterTool.cs.meta
Normal file
3
Editor/Inspector/ScaleAdjusterTool.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73643bebace8434baf2fcace7a8b7863
|
||||
timeCreated: 1703745833
|
Loading…
Reference in New Issue
Block a user