mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-02-07 06:12:47 +08:00
Fixing more issues with explicit constraint configurations
This commit is contained in:
parent
9b4d98a14d
commit
cb91283c1c
@ -29,18 +29,21 @@ 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 Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace net.fushizen.modular_avatar.core.editor
|
namespace net.fushizen.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
public class MergeArmatureHook
|
public class MergeArmatureHook
|
||||||
{
|
{
|
||||||
private Dictionary<Transform, Transform> BoneRemappings = new Dictionary<Transform, Transform>();
|
private Dictionary<Transform, Transform> BoneRemappings = new Dictionary<Transform, Transform>();
|
||||||
private List<GameObject> ToDelete = new List<GameObject>();
|
private HashSet<GameObject> ToDelete = new HashSet<GameObject>();
|
||||||
|
private HashSet<IConstraint> AddedConstraints = new HashSet<IConstraint>();
|
||||||
|
|
||||||
internal bool OnPreprocessAvatar(GameObject avatarGameObject)
|
internal bool OnPreprocessAvatar(GameObject avatarGameObject)
|
||||||
{
|
{
|
||||||
BoneRemappings.Clear();
|
BoneRemappings.Clear();
|
||||||
ToDelete.Clear();
|
ToDelete.Clear();
|
||||||
|
AddedConstraints.Clear();
|
||||||
|
|
||||||
var mergeArmatures = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeArmature>(true);
|
var mergeArmatures = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeArmature>(true);
|
||||||
|
|
||||||
@ -56,7 +59,7 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
foreach (var renderer in avatarGameObject.transform.GetComponentsInChildren<SkinnedMeshRenderer>())
|
foreach (var renderer in avatarGameObject.transform.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||||
{
|
{
|
||||||
var bones = renderer.bones;
|
var bones = renderer.bones;
|
||||||
for (int i = 0; i < bones.Length; i++) bones[i] = MapBoneReference(bones[i], false);
|
for (int i = 0; i < bones.Length; i++) bones[i] = MapBoneReference(bones[i], Retargetable.Ignore);
|
||||||
renderer.bones = bones;
|
renderer.bones = bones;
|
||||||
renderer.rootBone = MapBoneReference(renderer.rootBone);
|
renderer.rootBone = MapBoneReference(renderer.rootBone);
|
||||||
renderer.probeAnchor = MapBoneReference(renderer.probeAnchor);
|
renderer.probeAnchor = MapBoneReference(renderer.probeAnchor);
|
||||||
@ -80,12 +83,43 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
UpdateBoneReferences(c);
|
UpdateBoneReferences(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var c in avatarGameObject.transform.GetComponentsInChildren<IConstraint>())
|
||||||
|
{
|
||||||
|
if (!AddedConstraints.Contains(c))
|
||||||
|
{
|
||||||
|
FixupConstraint(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var bone in ToDelete) UnityEngine.Object.DestroyImmediate(bone);
|
foreach (var bone in ToDelete) UnityEngine.Object.DestroyImmediate(bone);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateBoneReferences(Component c)
|
private void FixupConstraint(IConstraint constraint)
|
||||||
|
{
|
||||||
|
int nSources = constraint.sourceCount;
|
||||||
|
for (int i = 0; i < nSources; i++)
|
||||||
|
{
|
||||||
|
var source = constraint.GetSource(i);
|
||||||
|
if (source.sourceTransform == null) continue;
|
||||||
|
if (!BoneRemappings.TryGetValue(source.sourceTransform, out var remap)) continue;
|
||||||
|
var retarget = BoneDatabase.GetRetargetedBone(remap);
|
||||||
|
|
||||||
|
if (retarget != null)
|
||||||
|
{
|
||||||
|
source.sourceTransform = retarget;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.sourceTransform = remap;
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint.SetSource(i, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBoneReferences(Component c, Retargetable retargetable = Retargetable.Disable)
|
||||||
{
|
{
|
||||||
SerializedObject so = new SerializedObject(c);
|
SerializedObject so = new SerializedObject(c);
|
||||||
SerializedProperty iter = so.GetIterator();
|
SerializedProperty iter = so.GetIterator();
|
||||||
@ -100,9 +134,31 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
enterChildren = false;
|
enterChildren = false;
|
||||||
break;
|
break;
|
||||||
case SerializedPropertyType.ObjectReference:
|
case SerializedPropertyType.ObjectReference:
|
||||||
|
if (iter.name == "m_GameObject") break;
|
||||||
|
|
||||||
if (iter.objectReferenceValue is Transform t)
|
if (iter.objectReferenceValue is Transform t)
|
||||||
{
|
{
|
||||||
iter.objectReferenceValue = MapBoneReference(t);
|
var mapped = MapBoneReference(t, retargetable);
|
||||||
|
if (mapped != iter.objectReferenceValue)
|
||||||
|
{
|
||||||
|
Debug.LogWarning(
|
||||||
|
$"Remapping property path {iter.propertyPath} from {iter.objectReferenceValue} to {mapped} on {c}");
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.objectReferenceValue = mapped;
|
||||||
|
ClearToDeleteFlag(mapped);
|
||||||
|
}
|
||||||
|
else if (iter.objectReferenceValue is GameObject go)
|
||||||
|
{
|
||||||
|
var mapped = MapBoneReference(go.transform, retargetable);
|
||||||
|
if (mapped?.gameObject != iter.objectReferenceValue)
|
||||||
|
{
|
||||||
|
Debug.LogWarning(
|
||||||
|
$"Remapping property path {iter.propertyPath} from {iter.objectReferenceValue} to {mapped} on {c}");
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.objectReferenceValue = mapped?.gameObject;
|
||||||
|
ClearToDeleteFlag(mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -112,14 +168,36 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
so.ApplyModifiedPropertiesWithoutUndo();
|
so.ApplyModifiedPropertiesWithoutUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Transform MapBoneReference(Transform bone, bool markNonRetargetable = true)
|
private void ClearToDeleteFlag(Transform t)
|
||||||
|
{
|
||||||
|
while (t != null && ToDelete.Contains(t.gameObject))
|
||||||
|
{
|
||||||
|
ToDelete.Remove(t.gameObject);
|
||||||
|
t = t.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Retargetable
|
||||||
|
{
|
||||||
|
Disable,
|
||||||
|
Ignore,
|
||||||
|
Use
|
||||||
|
}
|
||||||
|
|
||||||
|
private Transform MapBoneReference(Transform bone, Retargetable retargetable = Retargetable.Disable)
|
||||||
{
|
{
|
||||||
if (bone != null && BoneRemappings.TryGetValue(bone, out var newBone))
|
if (bone != null && BoneRemappings.TryGetValue(bone, out var newBone))
|
||||||
{
|
{
|
||||||
if (markNonRetargetable) BoneDatabase.MarkNonRetargetable(newBone);
|
if (retargetable == Retargetable.Disable) BoneDatabase.MarkNonRetargetable(newBone);
|
||||||
bone = newBone;
|
bone = newBone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bone != null && retargetable == Retargetable.Use)
|
||||||
|
{
|
||||||
|
var retargeted = BoneDatabase.GetRetargetedBone(bone);
|
||||||
|
if (retargeted != null) bone = retargeted;
|
||||||
|
}
|
||||||
|
|
||||||
return bone;
|
return bone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,8 +274,12 @@ 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,
|
private bool RecursiveMerge(
|
||||||
bool zipMerge)
|
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);
|
||||||
@ -223,6 +305,7 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
if (constraintType != null)
|
if (constraintType != null)
|
||||||
{
|
{
|
||||||
IConstraint constraint = (IConstraint) src.AddComponent(constraintType);
|
IConstraint constraint = (IConstraint) src.AddComponent(constraintType);
|
||||||
|
AddedConstraints.Add(constraint);
|
||||||
constraint.AddSource(new ConstraintSource()
|
constraint.AddSource(new ConstraintSource()
|
||||||
{
|
{
|
||||||
weight = 1,
|
weight = 1,
|
||||||
@ -250,8 +333,7 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
if ((constraintType != null && constraintType != typeof(ParentConstraint))
|
if ((constraintType != null && constraintType != typeof(ParentConstraint))
|
||||||
|| (constraintType == null && src.GetComponent<IConstraint>() != null))
|
|| (constraintType == null && src.GetComponent<IConstraint>() != null))
|
||||||
{
|
{
|
||||||
// We shouldn't merge any children as they'll potentially get out of sync with our constraint
|
zipMerge = false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transform> children = new List<Transform>();
|
List<Transform> children = new List<Transform>();
|
||||||
|
Loading…
Reference in New Issue
Block a user