feat: A/T Pose conversion on "Reset position to base avatar"

This commit is contained in:
Sayamame-beans 2024-09-22 22:39:15 +09:00
parent 5090d45cfe
commit 1e334ae1e2
3 changed files with 68 additions and 3 deletions

View File

@ -84,6 +84,7 @@ namespace nadena.dev.modular_avatar.core.editor
}
private bool posResetOptionFoldout = false;
private bool posReset_convertATPose = true;
private bool posReset_adjustRotation = false;
private bool posReset_adjustScale = false;
private bool posReset_heuristicRootScale = true;
@ -134,6 +135,9 @@ namespace nadena.dev.modular_avatar.core.editor
MessageType.Info
);
posReset_convertATPose = EditorGUILayout.ToggleLeft(
G("merge_armature.reset_pos.convert_atpose"),
posReset_convertATPose);
posReset_adjustRotation = EditorGUILayout.ToggleLeft(
G("merge_armature.reset_pos.adjust_rotation"),
posReset_adjustRotation);
@ -188,6 +192,11 @@ namespace nadena.dev.modular_avatar.core.editor
}
}
if (posReset_convertATPose)
{
FixAPose(mama.transform);
}
if (posReset_heuristicRootScale && !suppressRootScale)
{
AdjustRootScale();
@ -202,6 +211,60 @@ namespace nadena.dev.modular_avatar.core.editor
mama.ResetArmatureLock();
}
void FixAPose(Transform outfitArmature)
{
if (mergeTarget == null) return;
if (rootAnimator == null) return;
FixSingleArm(HumanBodyBones.LeftShoulder);
FixSingleArm(HumanBodyBones.RightShoulder);
FixSingleArm(HumanBodyBones.LeftUpperArm);
FixSingleArm(HumanBodyBones.RightUpperArm);
void FixSingleArm(HumanBodyBones arm)
{
var lowerArm = (HumanBodyBones)((int)arm + 2);
// check if the rotation of the arm differs
var avatarArm = rootAnimator.GetBoneTransform(arm);
var outfitArm = avatarToOutfit(avatarArm);
var avatarLowerArm = rootAnimator.GetBoneTransform(lowerArm);
var outfitLowerArm = avatarToOutfit(avatarLowerArm);
if (outfitArm == null) return;
if (outfitLowerArm == null) return;
if (Vector3.Dot((outfitLowerArm.position - outfitArm.position).normalized, (avatarLowerArm.position - avatarArm.position).normalized) > 0.999f) return;
// Rotate the outfit arm to ensure these two bone orientations match.
Undo.RecordObject(outfitArm, "Merge Armature: Force outfit position");
var relRot = Quaternion.FromToRotation(
outfitLowerArm.position - outfitArm.position,
avatarLowerArm.position - avatarArm.position
);
outfitArm.rotation = relRot * outfitArm.rotation;
PrefabUtility.RecordPrefabInstancePropertyModifications(outfitArm);
}
Transform avatarToOutfit(Transform avBone)
{
if (avBone == null) return null;
if (!avBone.IsChildOf(mergeTarget.transform)) return null;
var parts = RuntimeUtil.RelativePath(mergeTarget, avBone.gameObject)
.Split('/');
var outfitPath = string.Join("/", parts.Select(p => mama.prefix + p + mama.suffix));
var candidate = outfitArmature.transform.Find(outfitPath);
if (candidate == null) return null;
var merger = candidate.GetComponentInParent<ModularAvatarMergeArmature>();
if (merger != mama) return null;
return candidate;
}
}
void AdjustRootScale()
{
// Adjust the overall scale of the avatar based on wingspan (arm length)
@ -279,4 +342,4 @@ namespace nadena.dev.modular_avatar.core.editor
}
}
}
}
}

View File

@ -86,6 +86,7 @@
"merge_armature.lockmode.bidirectional.body": "The base armature and the merged armature will always have the same position. This is useful when creating animations that are meant to target the base armature. In order to activate this, your armatures must already be in the exact same position.",
"merge_armature.reset_pos": "Reset position to base avatar",
"merge_armature.reset_pos.info": "This command will force the position of all bones in the outfit to match that of the base avatar. This can be helpful as a starting point for installing outfits not set up for your current avatar.",
"merge_armature.reset_pos.convert_atpose": "Convert A-Pose/T-Pose to match base avatar",
"merge_armature.reset_pos.adjust_rotation": "Also set rotation to base avatar",
"merge_armature.reset_pos.adjust_scale": "Also set local scale to base avatar",
"merge_armature.reset_pos.execute": "Do it!",
@ -281,4 +282,4 @@
"ro_sim.effect_group.rule_inverted": "This rule is inverted",
"ro_sim.effect_group.rule_inverted.tooltip": "This rule will be applied when one of its conditions is NOT met",
"ro_sim.effect_group.conditions": "Conditions"
}
}

View File

@ -82,6 +82,7 @@
"merge_armature.lockmode.bidirectional.body": "アバターと統合されるアーマチュアは常に同じ位置になります。元のアバターを操作するアニメーションを作る時に便利かもしれません。有効にするためには、統合されるアーマチュアの位置を統合先と同じにしておく必要があります。",
"merge_armature.reset_pos": "位置を元アバターに合わせてリセット",
"merge_armature.reset_pos.info": "このコマンドは、衣装のボーンの位置をアバターのボーンの位置に合わせます。非対応衣装を導入するとき、アバウトに合わせるために便利です。",
"merge_armature.reset_pos.convert_atpose": "Aポーズ/Tポーズを合わせる",
"merge_armature.reset_pos.adjust_rotation": "回転も合わせる",
"merge_armature.reset_pos.adjust_scale": "スケールも合わせる",
"merge_armature.reset_pos.execute": "実行",
@ -272,4 +273,4 @@
"ro_sim.effect_group.rule_inverted": "このルールの条件が反転されています",
"ro_sim.effect_group.rule_inverted.tooltip": "このルールは、いずれかの条件が満たされていない場合に適用されます",
"ro_sim.effect_group.conditions": "条件"
}
}