Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a component to perform nonuniform scale adjustments #583

Merged
merged 1 commit into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions Editor/Inspector/ScaleAdjusterInspector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
using static nadena.dev.modular_avatar.core.editor.Localization;

namespace nadena.dev.modular_avatar.core.editor
{
[CustomEditor(typeof(ModularAvatarScaleAdjuster))]
[CanEditMultipleObjects]
internal class ScaleAdjusterInspector : MAEditorBase
{
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);

serializedObject.ApplyModifiedProperties();

Localization.ShowLanguageUI();
}
}
}
3 changes: 3 additions & 0 deletions Editor/Inspector/ScaleAdjusterInspector.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Editor/Localization/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,5 +232,7 @@
"setup_outfit.err.no_animator": "Your avatar does not have an Animator component.",
"setup_outfit.err.no_hips": "Your avatar does not have a Hips bone. Setup Outfit only works on humanoid avatars.",
"setup_outfit.err.no_outfit_hips": "Unable to identify the Hips object for the outfit. Searched for objects containing the following names:",
"move_independently.group-header": "Objects to move together"
"move_independently.group-header": "Objects to move together",
"scale_adjuster.scale": "Scale adjustment",
"scale_adjuster.adjust_children": "Adjust position of child objects"
}
4 changes: 3 additions & 1 deletion Editor/Localization/ja-jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,5 +193,7 @@
"setup_outfit.err.no_animator": "アバターにAnimatorコンポーネントがありません。",
"setup_outfit.err.no_hips": "アバターにHipsボーンがありません。なお、Setup Outfitはヒューマノイドアバター以外には対応していません。",
"setup_outfit.err.no_outfit_hips": "衣装のHipsボーンを発見できませんでした。以下の名前を含むボーンを探しました:",
"move_independently.group-header": "一緒に動かすオブジェクト"
"move_independently.group-header": "一緒に動かすオブジェクト",
"scale_adjuster.scale": "Scale調整値",
"scale_adjuster.adjust_children": "子オブジェクトの位置を調整"
}
5 changes: 5 additions & 0 deletions Editor/MergeArmatureHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ internal void OnPreprocessAvatar(ndmf.BuildContext context, GameObject avatarGam
TopoProcessMergeArmatures(mergeArmatures);

#if MA_VRCSDK3_AVATARS
foreach (var c in avatarGameObject.transform.GetComponentsInChildren<ScaleProxy>(true))
{
BoneDatabase.AddMergedBone(c.transform);
}

foreach (var c in avatarGameObject.transform.GetComponentsInChildren<VRCPhysBone>(true))
{
if (c.rootTransform == null) c.rootTransform = c.transform;
Expand Down
2 changes: 1 addition & 1 deletion Runtime/MAMoveIndependently.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ void Awake()

private void OnValidate()
{
Debug.Log("=== OnValidate");
hideFlags = HideFlags.DontSave;
_excluded = new HashSet<Transform>();
if (m_groupedBones == null)
Expand Down Expand Up @@ -110,6 +109,7 @@ private void CheckChildren(Transform parent)
foreach (Transform child in parent)
{
if (_excluded.Contains(child)) continue;
if (child.GetComponent<ScaleProxy>() != null) continue;

_observed.Add(child);

Expand Down
Loading
Loading