From c50148a927097e93a804d1c22e399e0c87476071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=85=9C?= <2082529121@qq.com> Date: Sat, 6 Dec 2025 20:42:38 +0800 Subject: [PATCH] feat(importing): Add head bone tail positions and improve armature modification logic - Add 74 head bone tail position definitions to better_fbx_bone_tails dictionary for improved bone orientation accuracy - Create backup file modifyarmature_bak.py for version control - Conditionally apply delete_accessory_bones() only for Koikatsu armature type (C) - Add cf_J_hitomi_tx_R and cf_J_hitomi_tx_L to preserved bones list - Implement conditional bone reorientation logic for non-Koikatsu armature types (A/B/D) - Simplify leg bone tail relocation by removing better_fbx data check and always applying standard z-alignment - Improve armature modification workflow to handle different armature types with appropriate bone processing strategies --- importing/modifyarmature.py | 130 ++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 20 deletions(-) diff --git a/importing/modifyarmature.py b/importing/modifyarmature.py index 1275188..ed6e7ee 100644 --- a/importing/modifyarmature.py +++ b/importing/modifyarmature.py @@ -231,6 +231,82 @@ better_fbx_bone_tails = { 'cf_j_index01_R': (-0.0308635831, -0.0027105501, -0.0027000904), 'cf_j_index02_R': (-0.0205416679, -0.0018021995, -0.0018149614), 'cf_j_index03_R': (-0.0205416679, -0.0018021995, -0.0018149614), + + # 头部骨骼 (p_cf_head_bone 及其子骨骼,共74个) + 'p_cf_head_bone': (0.0, 0.0, 0.0099999998), + 'cf_J_N_FaceRoot': (-4e-10, 0.0, 0.0099999998), + 'cf_J_FaceRoot': (0.0, -0.0060000001, 0.0199999996), + 'cf_J_FaceBase': (6.7e-09, -0.0321580991, 0.0155400224), + 'cf_J_FaceUp_ty': (-5e-09, -0.0012981864, 0.0153640173), + 'cf_J_EarBase_ry_L': (0.0040000007, 0.0065659345, 0.0013576597), + 'cf_J_EarLow_L': (-0.0119999945, 0.0036456594, -0.0224846825), + 'cf_J_EarUp_L': (0.0200000033, 0.0094862096, 0.0251999944), + 'cf_J_EarBase_ry_R': (-0.0040000007, 0.0065659294, 0.0010771602), + 'cf_J_EarLow_R': (0.0120000094, 0.0036456697, -0.0230684578), + 'cf_J_EarUp_R': (-0.0200000033, 0.0094861891, 0.0252227858), + 'cf_J_FaceUp_tz': (1.5e-08, -0.0822834074, 0.0294848457), + 'cf_J_Eye_tz': (1.74653e-05, 7.5e-09, 0.0040000007), + 'cf_J_Eye_txdam_L': (0.0005303472, -0.0006456077, 0.0108191594), + 'cf_J_Eye_tx_L': (0.0005303472, -0.0006456077, 0.0108191594), + 'cf_J_Eye_rz_L': (0.0020232424, -0.0143185034, -0.0075755417), + 'cf_J_CheekUp2_L': (0.0024154074, 0.0097409822, -0.0335302614), + 'cf_J_Eye01_s_L': (-0.0192517117, -0.0222310573, -0.0043519735), + 'cf_J_Eye02_s_L': (-0.0125349201, -0.0245135501, 0.0108480155), + 'cf_J_Eye03_s_L': (0.0034999885, -0.0231375471, 0.0147431493), + 'cf_J_Eye04_s_L': (0.0165117607, -0.0177816749, 0.008518368), + 'cf_J_Eye05_s_L': (0.0244611353, -0.0106068701, -0.0038318336), + 'cf_J_Eye06_s_L': (0.0179830194, -0.0083362609, -0.0178645924), + 'cf_J_Eye07_s_L': (0.0006974302, -0.0135568678, -0.0231180415), + 'cf_J_Eye08_s_L': (-0.0155729428, -0.0184436664, -0.0195927024), + 'cf_J_Eye_txdam_R': (-0.0005300008, -0.0006456077, 0.0108191594), + 'cf_J_Eye_tx_R': (-0.0005300008, -0.0006456077, 0.0108191594), + 'cf_J_Eye_rz_R': (-0.0018717796, -0.0143385679, -0.007591337), + 'cf_J_CheekUp2_R': (-0.0024154112, 0.0097409934, -0.03353028), + 'cf_J_Eye01_s_R': (0.0192652196, -0.0221798792, -0.0043867007), + 'cf_J_Eye02_s_R': (0.012559589, -0.0245160758, 0.0108663738), + 'cf_J_Eye03_s_R': (-0.00215628, -0.0233592987, 0.0145589486), + 'cf_J_Eye04_s_R': (-0.0165314898, -0.017822504, 0.0085391998), + 'cf_J_Eye05_s_R': (-0.0245011002, -0.0106083676, -0.0038220957), + 'cf_J_Eye06_s_R': (-0.0179587901, -0.0083584338, -0.0178358555), + 'cf_J_Eye07_s_R': (-0.0006720722, -0.0135397911, -0.0230915993), + 'cf_J_Eye08_s_R': (0.0155643187, -0.018403694, -0.0196200199), + 'cf_J_Mayu_ty': (1.36853e-05, 0.0106744692, 0.0), + 'cf_J_Mayumoto_L': (0.0005722754, -0.0010105595, 0.0111785308), + 'cf_J_Mayu_L': (0.0005722754, -0.0010105595, 0.0111785308), + 'cf_J_MayuMid_s_L': (-0.0148523003, -0.0054057986, -3.12626e-05), + 'cf_J_MayuTip_s_L': (0.0133357644, 0.0048538223, 0.0), + 'cf_J_Mayumoto_R': (-0.0005719997, -0.0010160729, 0.0111785308), + 'cf_J_Mayu_R': (-0.0005719997, -0.0010160729, 0.0111785308), + 'cf_J_MayuMid_s_R': (0.0140953921, -0.0051302984, -3.12626e-05), + 'cf_J_MayuTip_s_R': (-0.0125368983, 0.0045630634, -3.12626e-05), + 'cf_J_FaceLow_tz': (5e-09, -0.025674995, -0.0074298549), + 'cf_J_MouthBase_ty': (-2e-10, -0.0008716434, 0.0101031829), + 'cf_J_MouthBase_rx': (-5e-09, 0.0124999955, 0.0), + 'cf_J_MouthCavity': (-1e-08, 0.0249999985, 0.0), + 'cf_J_MouthMove': (0.0, -0.0028492734, -0.0003052), + 'cf_J_Mouth_L': (0.0060000005, -0.0007560551, 0.0), + 'cf_J_Mouth_R': (-0.0059999996, -0.0007560551, 0.0), + 'cf_J_MouthLow': (0.0, -0.0030992031, -0.0026312196), + 'cf_J_Mouthup': (0.0, -0.0067858025, 0.0014104201), + 'cf_J_FaceLow_sx': (0.0, -0.0006982945, -0.0140105523), + 'cf_J_Chin_Base': (2e-10, -0.0075257719, -0.0307464823), + 'cf_J_CheekLow_s_L': (0.0259999987, 7.5e-09, -0.0293771196), + 'cf_J_CheekLow_s_R': (-0.0259999968, 0.0, -0.0293771196), + 'cf_J_Chin_s': (1e-08, -0.0174226761, -0.0165147893), + 'cf_J_ChinTip_Base': (1e-08, -0.0174226761, -0.0165147875), + 'cf_J_ChinLow': (0.0, -0.0020948797, -0.0420316607), + 'cf_J_CheekUpBase': (1.2e-09, -0.0249999985, 0.0044998601), + 'cf_J_CheekUp_s_L': (0.0459999964, -0.0249999911, 0.0045103002), + 'cf_J_CheekUp_s_R': (-0.0460000038, -0.0250000022, 0.00448942), + 'cf_J_NoseBase': (5e-09, -0.0072341338, 0.012515638), + 'cf_J_NoseBase_rx': (1e-08, -0.0150000006, 0.0), + 'cf_J_Nose_rx': (0.0, -0.0091642886, 0.0), + 'cf_J_Nose_tip': (0.0, -0.0091642886, 0.0), + 'cf_J_NoseBridge_ty': (-2e-10, -0.0008712783, 0.010564737), + 'cf_J_NoseBridge_rx': (-2e-10, -0.0008714795, 0.010564737), + 'N_tonn_face': (0.0, 0.0, 0.0099999998), + 'N_cf_haed': (0.0, 0.0, 0.0099999998), + 'cf_O_face_atari': (0.0, 0.0, 0.0099999998), } class modify_armature(bpy.types.Operator): @@ -410,8 +486,9 @@ class modify_armature(bpy.types.Operator): bpy.ops.armature.select_all(action='INVERT') bpy.ops.armature.delete() - # 删除无用的配饰骨骼(头发、衣服等),只保留核心人体骨骼 - # self.delete_accessory_bones() + # 只在选择 Koikatsu armature (C) 时删除配饰骨骼 + if bpy.context.scene.kkbp.armature_dropdown == 'C': + self.delete_accessory_bones() c.print_timer('delete_non_height_bones') @@ -433,6 +510,8 @@ class modify_armature(bpy.types.Operator): 'p_cf_head_bone', # 头部骨骼 'a_n_back', # 背部锚点 'a_n_headside', # 头部侧面锚点 + 'cf_J_hitomi_tx_R', + 'cf_J_hitomi_tx_L', ] # 收集所有需要删除的骨骼(不在 better_fbx_bone_tails 中且不在必须保留列表中的) @@ -531,6 +610,24 @@ class modify_armature(bpy.types.Operator): for finger in finger_list: resize_finger(finger) + # 对于非 Koikatsu armature (A/B/D),使用原始的骨骼重定向逻辑 + # Koikatsu armature (C) 会在最后统一应用 better_fbx 骨骼方向 + if bpy.context.scene.kkbp.armature_dropdown != 'C': + height_adjust = Vector((0,0,0.1)) + def reorient(bone): + armature.data.edit_bones[bone].tail = armature.data.edit_bones[bone].head + height_adjust + + reorient_list = [ + 'cf_j_thigh00_R', 'cf_j_thigh00_L', + 'cf_j_leg01_R', 'cf_j_leg01_L', + 'cf_j_leg03_R', 'cf_j_leg03_L', + 'cf_j_foot_R', 'cf_j_foot_L', + 'cf_d_arm01_R', 'cf_d_arm01_L', + 'cf_d_shoulder02_R', 'cf_d_shoulder02_L',] + + for bone in reorient_list: + reorient(bone) + c.print_timer('modify_finger_bone_orientations') def set_bone_roll_data(self): @@ -884,14 +981,8 @@ class modify_armature(bpy.types.Operator): #relocate the tail of some bones to make IKs easier def relocate_tail(bone1, bone2, direction): if direction == 'leg': - # 使用 better_fbx 数据而不是简单地对齐到目标骨骼 - if bone1 in better_fbx_bone_tails: - print(f"[KKBP] 保留 {bone1} 的 better_fbx 骨骼方向") - # 不修改尾部,保留之前设置的方向 - pass - else: - armature.data.edit_bones[bone1].tail.z = armature.data.edit_bones[bone2].head.z - armature.data.edit_bones[bone1].roll = 0 + armature.data.edit_bones[bone1].tail.z = armature.data.edit_bones[bone2].head.z + armature.data.edit_bones[bone1].roll = 0 #move the bone forward a bit or the ik bones might not bend correctly armature.data.edit_bones[bone1].head.y += -0.01 elif direction == 'arm': @@ -904,15 +995,9 @@ class modify_armature(bpy.types.Operator): armature.data.edit_bones[bone1].tail.z += .01 armature.data.edit_bones[bone1].head = armature.data.edit_bones[bone2].head else: - # 使用 better_fbx 数据而不是简单地对齐到目标骨骼 - if bone1 in better_fbx_bone_tails: - print(f"[KKBP] 保留 {bone1} 的 better_fbx 骨骼方向") - # 不修改尾部,保留之前设置的方向 - pass - else: - armature.data.edit_bones[bone1].tail.y = armature.data.edit_bones[bone2].head.y - armature.data.edit_bones[bone1].tail.z = armature.data.edit_bones[bone2].head.z - armature.data.edit_bones[bone1].roll = 0 + armature.data.edit_bones[bone1].tail.y = armature.data.edit_bones[bone2].head.y + armature.data.edit_bones[bone1].tail.z = armature.data.edit_bones[bone2].head.z + armature.data.edit_bones[bone1].roll = 0 relocate_tail('cf_j_leg01_R', 'cf_j_foot_R', 'leg') relocate_tail('cf_j_leg01_L', 'cf_j_foot_L', 'leg') relocate_tail('cf_j_forearm01_R', 'cf_j_hand_R', 'arm') @@ -1127,7 +1212,12 @@ class modify_armature(bpy.types.Operator): c.print_timer('rename_mmd_bones') def apply_better_fbx_bone_orientations(self): - '''统一应用 better_fbx 骨骼方向,确保不被其他步骤覆盖''' + '''统一应用 better_fbx 骨骼方向,确保不被其他步骤覆盖 (仅在选择 Koikatsu armature 时)''' + # 只在选择 Koikatsu armature (C) 时应用 better_fbx 骨骼方向 + if bpy.context.scene.kkbp.armature_dropdown != 'C': + c.print_timer('apply_better_fbx_bone_orientations (skipped)') + return + armature = c.get_armature() c.switch(armature, 'edit')