From 1e334ae1e28624815a8b1106a579cc7121b36895 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:39:15 +0900 Subject: [PATCH] feat: A/T Pose conversion on "Reset position to base avatar" --- Editor/Inspector/MergeArmatureEditor.cs | 65 ++++++++++++++++++++++++- Editor/Localization/en-US.json | 3 +- Editor/Localization/ja-JP.json | 3 +- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Editor/Inspector/MergeArmatureEditor.cs b/Editor/Inspector/MergeArmatureEditor.cs index 3785a608..1ef30034 100644 --- a/Editor/Inspector/MergeArmatureEditor.cs +++ b/Editor/Inspector/MergeArmatureEditor.cs @@ -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(); + 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 } } } -} \ No newline at end of file +} diff --git a/Editor/Localization/en-US.json b/Editor/Localization/en-US.json index 812970c0..90adff0d 100644 --- a/Editor/Localization/en-US.json +++ b/Editor/Localization/en-US.json @@ -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" -} \ No newline at end of file +} diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 7c011df0..f87e0e35 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -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": "条件" -} \ No newline at end of file +}