Preserve local transform when rebinding humanoid avatar

This commit is contained in:
Yū Kobayashi 2024-08-29 23:33:07 +09:00
parent 9d48ae4f65
commit 10cfde77a8
3 changed files with 88 additions and 13 deletions

View File

@ -81,19 +81,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
FixupExpressionsMenuPass.FixupExpressionsMenu(maContext);
});
#endif
seq.Run("Rebind humanoid avatar", ctx =>
{
// workaround problem with avatar matching
// https://github.com/bdunderscore/modular-avatar/issues/430
var animator = ctx.AvatarRootObject.GetComponent<Animator>();
if (animator)
{
var avatar = animator.avatar;
animator.avatar = null;
// ReSharper disable once Unity.InefficientPropertyAccess
animator.avatar = avatar;
}
});
seq.Run(RebindHumanoidAvatarPass.Instance);
seq.Run("Purge ModularAvatar components", ctx =>
{
foreach (var component in ctx.AvatarRootTransform.GetComponentsInChildren<AvatarTagComponent>(true))
@ -253,6 +241,14 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
}
#endif
class RebindHumanoidAvatarPass : MAPass<RebindHumanoidAvatarPass>
{
protected override void Execute(ndmf.BuildContext context)
{
new RebindHumanoidAvatar(context).Process();
}
}
class GCGameObjectsPluginPass : MAPass<GCGameObjectsPluginPass>
{
protected override void Execute(ndmf.BuildContext context)

View File

@ -0,0 +1,68 @@
using System.Linq;
using UnityEngine;
namespace nadena.dev.modular_avatar.core.editor.plugin
{
// workaround problem with avatar matching
// https://github.com/bdunderscore/modular-avatar/issues/430
internal class RebindHumanoidAvatar
{
private readonly ndmf.BuildContext _buildContext;
public RebindHumanoidAvatar(ndmf.BuildContext context)
{
_buildContext = context;
}
public void Process()
{
var avatarAnimator = _buildContext.AvatarRootObject.GetComponent<Animator>();
if (avatarAnimator == null) return;
var localTransformValues = _buildContext.AvatarRootObject
.GetComponentsInChildren<Transform>(true)
.ToDictionary((t) => t, LocalTransformValue.FromTransform);
var boundAvatar = avatarAnimator.avatar;
avatarAnimator.avatar = null;
// ReSharper disable once Unity.InefficientPropertyAccess
avatarAnimator.avatar = boundAvatar;
// resetting avatar also resets local transform value from avatar asset
// needs to restore them manually from pre-cache
// https://github.com/bdunderscore/modular-avatar/issues/1036
for (var bone = HumanBodyBones.Hips; bone < HumanBodyBones.LastBone; ++bone)
{
var boneTransform = avatarAnimator.GetBoneTransform(bone);
if (boneTransform == null) continue;
if (localTransformValues.TryGetValue(boneTransform, out var preserved))
{
preserved.RestoreToTransform(boneTransform);
}
}
}
struct LocalTransformValue
{
Vector3 Position;
Quaternion Rotation;
Vector3 Scale;
internal static LocalTransformValue FromTransform(Transform t)
{
return new LocalTransformValue
{
Position = t.localPosition,
Rotation = t.localRotation,
Scale = t.localScale
};
}
internal readonly void RestoreToTransform(Transform t)
{
t.SetLocalPositionAndRotation(Position, Rotation);
t.localScale = Scale;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f0b7a3de79e73a4f853218f26ed7077
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: