Fix merging armatures containing explicitly set constraints

This commit is contained in:
bd_ 2022-10-02 16:43:01 -07:00 committed by bd_
parent 505ebeffc5
commit ea2011f68d

View File

@ -22,15 +22,13 @@
* SOFTWARE. * SOFTWARE.
*/ */
using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.Animations; using UnityEngine.Animations;
using VRC.Dynamics; using VRC.Dynamics;
using VRC.SDK3.Dynamics.PhysBone.Components; using VRC.SDK3.Dynamics.PhysBone.Components;
using VRC.SDKBase.Editor.BuildPipeline;
using Matrix4x4 = UnityEngine.Matrix4x4;
using Vector3 = UnityEngine.Vector3;
namespace net.fushizen.modular_avatar.core.editor namespace net.fushizen.modular_avatar.core.editor
{ {
@ -43,12 +41,12 @@ namespace net.fushizen.modular_avatar.core.editor
{ {
BoneRemappings.Clear(); BoneRemappings.Clear();
ToDelete.Clear(); ToDelete.Clear();
var mergeArmatures = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeArmature>(true); var mergeArmatures = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeArmature>(true);
BoneRemappings.Clear(); BoneRemappings.Clear();
ToDelete.Clear(); ToDelete.Clear();
foreach (var mergeArmature in mergeArmatures) foreach (var mergeArmature in mergeArmatures)
{ {
MergeArmature(mergeArmature); MergeArmature(mergeArmature);
@ -69,7 +67,7 @@ namespace net.fushizen.modular_avatar.core.editor
if (c.rootTransform == null) c.rootTransform = c.transform; if (c.rootTransform == null) c.rootTransform = c.transform;
UpdateBoneReferences(c); UpdateBoneReferences(c);
} }
foreach (var c in avatarGameObject.transform.GetComponentsInChildren<VRCPhysBoneCollider>()) foreach (var c in avatarGameObject.transform.GetComponentsInChildren<VRCPhysBoneCollider>())
{ {
if (c.rootTransform == null) c.rootTransform = c.transform; if (c.rootTransform == null) c.rootTransform = c.transform;
@ -81,7 +79,7 @@ namespace net.fushizen.modular_avatar.core.editor
if (c.rootTransform == null) c.rootTransform = c.transform; if (c.rootTransform == null) c.rootTransform = c.transform;
UpdateBoneReferences(c); UpdateBoneReferences(c);
} }
foreach (var bone in ToDelete) UnityEngine.Object.DestroyImmediate(bone); foreach (var bone in ToDelete) UnityEngine.Object.DestroyImmediate(bone);
return true; return true;
@ -98,7 +96,8 @@ namespace net.fushizen.modular_avatar.core.editor
enterChildren = true; enterChildren = true;
switch (iter.propertyType) switch (iter.propertyType)
{ {
case SerializedPropertyType.String: enterChildren = false; case SerializedPropertyType.String:
enterChildren = false;
break; break;
case SerializedPropertyType.ObjectReference: case SerializedPropertyType.ObjectReference:
if (iter.objectReferenceValue is Transform t) if (iter.objectReferenceValue is Transform t)
@ -120,21 +119,43 @@ namespace net.fushizen.modular_avatar.core.editor
if (markNonRetargetable) BoneDatabase.MarkNonRetargetable(newBone); if (markNonRetargetable) BoneDatabase.MarkNonRetargetable(newBone);
bone = newBone; bone = newBone;
} }
return bone; return bone;
} }
private bool HasAdditionalComponents(GameObject go, out bool needsConstraint) private bool HasAdditionalComponents(GameObject go, out Type constraintType)
{ {
bool hasComponents = false; bool hasComponents = false;
needsConstraint = false; bool needsConstraint = false;
bool hasPositionConstraint = false;
bool hasRotationConstraint = false;
foreach (Component c in go.GetComponents<Component>()) foreach (Component c in go.GetComponents<Component>())
{ {
switch (c) switch (c)
{ {
case Transform _: break; case Transform _: break;
case ModularAvatarMergeArmature _: break; case ModularAvatarMergeArmature _: break;
case VRCPhysBone _: case VRCPhysBoneCollider _: hasComponents = true; case VRCPhysBone _:
case VRCPhysBoneCollider _:
hasComponents = true;
break;
case AimConstraint _:
case LookAtConstraint _:
case RotationConstraint _:
hasRotationConstraint = true;
needsConstraint = true;
hasComponents = true;
break;
case PositionConstraint _:
hasPositionConstraint = true;
needsConstraint = true;
hasComponents = true;
break;
case ParentConstraint _:
needsConstraint = false;
hasPositionConstraint = hasRotationConstraint = true;
hasComponents = true;
break; break;
default: default:
hasComponents = true; hasComponents = true;
@ -143,9 +164,26 @@ namespace net.fushizen.modular_avatar.core.editor
} }
} }
if (!needsConstraint || (hasPositionConstraint && hasRotationConstraint))
{
constraintType = null;
}
else if (hasPositionConstraint)
{
constraintType = typeof(RotationConstraint);
}
else if (hasRotationConstraint)
{
constraintType = typeof(PositionConstraint);
}
else
{
constraintType = typeof(ParentConstraint);
}
return hasComponents; return hasComponents;
} }
private void MergeArmature(ModularAvatarMergeArmature mergeArmature) private void MergeArmature(ModularAvatarMergeArmature mergeArmature)
{ {
// TODO: error reporting framework? // TODO: error reporting framework?
@ -158,7 +196,8 @@ namespace net.fushizen.modular_avatar.core.editor
* (Attempts to) merge the source gameobject into the target gameobject. Returns true if the merged source * (Attempts to) merge the source gameobject into the target gameobject. Returns true if the merged source
* object must be retained. * object must be retained.
*/ */
private bool RecursiveMerge(ModularAvatarMergeArmature config, GameObject src, GameObject newParent, bool zipMerge) private bool RecursiveMerge(ModularAvatarMergeArmature config, GameObject src, GameObject newParent,
bool zipMerge)
{ {
GameObject mergedSrcBone = new GameObject(src.name + "@" + GUID.Generate()); GameObject mergedSrcBone = new GameObject(src.name + "@" + GUID.Generate());
mergedSrcBone.transform.SetParent(src.transform.parent); mergedSrcBone.transform.SetParent(src.transform.parent);
@ -172,34 +211,55 @@ namespace net.fushizen.modular_avatar.core.editor
var srcPath = RuntimeUtil.AvatarRootPath(src); var srcPath = RuntimeUtil.AvatarRootPath(src);
PathMappings.Remap(srcPath, new PathMappings.MappingEntry() PathMappings.Remap(srcPath, new PathMappings.MappingEntry()
{ {
transformPath = zipMerge ? RuntimeUtil.AvatarRootPath(newParent) : srcPath, transformPath = RuntimeUtil.AvatarRootPath(newParent),
path = srcPath path = srcPath
}); });
} }
mergedSrcBone.transform.SetParent(newParent.transform, true); mergedSrcBone.transform.SetParent(newParent.transform, true);
BoneRemappings[src.transform] = mergedSrcBone.transform; BoneRemappings[src.transform] = mergedSrcBone.transform;
bool retain = HasAdditionalComponents(src, out bool needsConstraint); bool retain = HasAdditionalComponents(src, out var constraintType);
if (needsConstraint) if (constraintType != null)
{ {
ParentConstraint constraint = src.AddComponent<ParentConstraint>(); IConstraint constraint = (IConstraint) src.AddComponent(constraintType);
constraint.AddSource(new ConstraintSource() constraint.AddSource(new ConstraintSource()
{ {
weight = 1, weight = 1,
sourceTransform = mergedSrcBone.transform sourceTransform = mergedSrcBone.transform
}); });
Matrix4x4 targetToSrc = src.transform.worldToLocalMatrix * newParent.transform.localToWorldMatrix; Matrix4x4 targetToSrc = src.transform.worldToLocalMatrix * newParent.transform.localToWorldMatrix;
constraint.translationOffsets = new Vector3[] {targetToSrc.MultiplyPoint(Vector3.zero)}; if (constraint is ParentConstraint pc)
constraint.rotationOffsets = new Vector3[] {targetToSrc.rotation.eulerAngles}; {
pc.translationOffsets = new Vector3[] {targetToSrc.MultiplyPoint(Vector3.zero)};
pc.rotationOffsets = new Vector3[] {targetToSrc.rotation.eulerAngles};
}
else if (constraint is PositionConstraint pos)
{
pos.translationOffset = targetToSrc.MultiplyPoint(Vector3.zero);
}
else if (constraint is RotationConstraint rot)
{
rot.rotationOffset = targetToSrc.rotation.eulerAngles;
}
constraint.locked = true; constraint.locked = true;
constraint.constraintActive = true; constraint.constraintActive = true;
} }
if ((constraintType != null && constraintType != typeof(ParentConstraint))
|| (constraintType == null && src.GetComponent<IConstraint>() != null))
{
// We shouldn't merge any children as they'll potentially get out of sync with our constraint
return true;
}
List<Transform> children = new List<Transform>(); List<Transform> children = new List<Transform>();
foreach (Transform child in src.transform) foreach (Transform child in src.transform)
{ {
children.Add(child); children.Add(child);
} }
foreach (Transform child in children) foreach (Transform child in children)
{ {
var childGameObject = child.gameObject; var childGameObject = child.gameObject;
@ -221,8 +281,6 @@ namespace net.fushizen.modular_avatar.core.editor
shouldZip = false; shouldZip = false;
} }
} }
var retainChild = RecursiveMerge(config, childGameObject, childNewParent, shouldZip); var retainChild = RecursiveMerge(config, childGameObject, childNewParent, shouldZip);
retain = retain || retainChild; retain = retain || retainChild;