# coding: utf-8 import unreal import re import argparse parser = argparse.ArgumentParser() parser.add_argument("-vrm") parser.add_argument("-rig") parser.add_argument("-meta") args = parser.parse_args() print(args.vrm) #print(dummy[3]) humanoidBoneList = [ "hips", "leftUpperLeg", "rightUpperLeg", "leftLowerLeg", "rightLowerLeg", "leftFoot", "rightFoot", "spine", "chest", "upperChest", # 9 optional "neck", "head", "leftShoulder", "rightShoulder", "leftUpperArm", "rightUpperArm", "leftLowerArm", "rightLowerArm", "leftHand", "rightHand", "leftToes", "rightToes", "leftEye", "rightEye", "jaw", "leftThumbProximal", # 24 "leftThumbIntermediate", "leftThumbDistal", "leftIndexProximal", "leftIndexIntermediate", "leftIndexDistal", "leftMiddleProximal", "leftMiddleIntermediate", "leftMiddleDistal", "leftRingProximal", "leftRingIntermediate", "leftRingDistal", "leftLittleProximal", "leftLittleIntermediate", "leftLittleDistal", "rightThumbProximal", "rightThumbIntermediate", "rightThumbDistal", "rightIndexProximal", "rightIndexIntermediate", "rightIndexDistal", "rightMiddleProximal", "rightMiddleIntermediate", "rightMiddleDistal", "rightRingProximal", "rightRingIntermediate", "rightRingDistal", "rightLittleProximal", "rightLittleIntermediate", "rightLittleDistal", #54 ] humanoidBoneParentList = [ "", #"hips", "hips",#"leftUpperLeg", "hips",#"rightUpperLeg", "leftUpperLeg",#"leftLowerLeg", "rightUpperLeg",#"rightLowerLeg", "leftLowerLeg",#"leftFoot", "rightLowerLeg",#"rightFoot", "hips",#"spine", "spine",#"chest", "chest",#"upperChest" 9 optional "chest",#"neck", "neck",#"head", "chest",#"leftShoulder", # <-- upper.. "chest",#"rightShoulder", "leftShoulder",#"leftUpperArm", "rightShoulder",#"rightUpperArm", "leftUpperArm",#"leftLowerArm", "rightUpperArm",#"rightLowerArm", "leftLowerArm",#"leftHand", "rightLowerArm",#"rightHand", "leftFoot",#"leftToes", "rightFoot",#"rightToes", "head",#"leftEye", "head",#"rightEye", "head",#"jaw", "leftHand",#"leftThumbProximal", "leftThumbProximal",#"leftThumbIntermediate", "leftThumbIntermediate",#"leftThumbDistal", "leftHand",#"leftIndexProximal", "leftIndexProximal",#"leftIndexIntermediate", "leftIndexIntermediate",#"leftIndexDistal", "leftHand",#"leftMiddleProximal", "leftMiddleProximal",#"leftMiddleIntermediate", "leftMiddleIntermediate",#"leftMiddleDistal", "leftHand",#"leftRingProximal", "leftRingProximal",#"leftRingIntermediate", "leftRingIntermediate",#"leftRingDistal", "leftHand",#"leftLittleProximal", "leftLittleProximal",#"leftLittleIntermediate", "leftLittleIntermediate",#"leftLittleDistal", "rightHand",#"rightThumbProximal", "rightThumbProximal",#"rightThumbIntermediate", "rightThumbIntermediate",#"rightThumbDistal", "rightHand",#"rightIndexProximal", "rightIndexProximal",#"rightIndexIntermediate", "rightIndexIntermediate",#"rightIndexDistal", "rightHand",#"rightMiddleProximal", "rightMiddleProximal",#"rightMiddleIntermediate", "rightMiddleIntermediate",#"rightMiddleDistal", "rightHand",#"rightRingProximal", "rightRingProximal",#"rightRingIntermediate", "rightRingIntermediate",#"rightRingDistal", "rightHand",#"rightLittleProximal", "rightLittleProximal",#"rightLittleIntermediate", "rightLittleIntermediate",#"rightLittleDistal", ] for i in range(len(humanoidBoneList)): humanoidBoneList[i] = humanoidBoneList[i].lower() for i in range(len(humanoidBoneParentList)): humanoidBoneParentList[i] = humanoidBoneParentList[i].lower() ###### reg = unreal.AssetRegistryHelpers.get_asset_registry(); ## rigs = unreal.ControlRigBlueprint.get_currently_open_rig_blueprints() print(rigs) for r in rigs: s:str = r.get_path_name() ss:str = args.rig if (s.find(ss) < 0): print("no rig") else: rig = r #rig = rigs[10] h_mod = rig.get_hierarchy_modifier() #elements = h_mod.get_selection() #sk = rig.get_preview_mesh() #k = sk.skeleton #print(k) #print(sk.bone_tree) # #kk = unreal.RigElementKey(unreal.RigElementType.BONE, "hipssss"); #kk.name = "" #kk.type = 1; #print(h_mod.get_bone(kk)) #print(h_mod.get_elements()) ### 全ての骨 modelBoneListAll = [] modelBoneNameList = [] #for e in reversed(h_mod.get_elements()): # if (e.type != unreal.RigElementType.BONE): # h_mod.remove_element(e) for e in h_mod.get_elements(): if (e.type == unreal.RigElementType.BONE): modelBoneListAll.append(e) modelBoneNameList.append("{}".format(e.name).lower()) # else: # h_mod.remove_element(e) print(modelBoneListAll[0]) #exit #print(k.get_editor_property("bone_tree")[0].get_editor_property("translation_retargeting_mode")) #print(k.get_editor_property("bone_tree")[0].get_editor_property("parent_index")) #unreal.select #vrmlist = unreal.VrmAssetListObject #vrmmeta = vrmlist.vrm_meta_object #print(vrmmeta.humanoid_bone_table) #selected_actors = unreal.EditorLevelLibrary.get_selected_level_actors() #selected_static_mesh_actors = unreal.EditorFilterLibrary.by_class(selected_actors,unreal.StaticMeshActor.static_class()) #static_meshes = np.array([]) ## meta 取得 reg = unreal.AssetRegistryHelpers.get_asset_registry(); a = reg.get_all_assets(); if (args.meta): for aa in a: if (aa.get_editor_property("object_path") == args.meta): v:unreal.VrmMetaObject = aa vv = aa.get_asset() if (vv == None): for aa in a: if (aa.get_editor_property("object_path") == args.vrm): v:unreal.VrmAssetListObject = aa vv = v.get_asset().vrm_meta_object print(vv) meta = vv #v:unreal.VrmAssetListObject = None #if (True): # a = reg.get_assets_by_path(args.vrm) # a = reg.get_all_assets(); # for aa in a: # if (aa.get_editor_property("object_path") == args.vrm): # v:unreal.VrmAssetListObject = aa #v = unreal.VrmAssetListObject.cast(v) #print(v) #unreal.VrmAssetListObject.vrm_meta_object #meta = v.vrm_meta_object() #meta = unreal.EditorFilterLibrary.by_class(asset,unreal.VrmMetaObject.static_class()) print (meta) #print(meta[0].humanoid_bone_table) ### モデル骨のうち、ヒューマノイドと同じもの ### 上の変換テーブル humanoidBoneToModel = {"" : ""} humanoidBoneToModel.clear() ### modelBoneでループ #for bone_h in meta.humanoid_bone_table: for bone_h_base in humanoidBoneList: bone_h = None for e in meta.humanoid_bone_table: if ("{}".format(e).lower() == bone_h_base): bone_h = e; break; print("{}".format(bone_h)) if (bone_h==None): continue bone_m = meta.humanoid_bone_table[bone_h] bone_m_normalized = "{}".format(bone_m).lower().strip() try: i = modelBoneNameList.index(bone_m_normalized) except ValueError: i = -1 if (i < 0): continue if ("{}".format(bone_h).lower() == "upperchest"): continue; humanoidBoneToModel["{}".format(bone_h).lower()] = bone_m_normalized if ("{}".format(bone_h).lower() == "chest"): #upperchestがあれば、これの次に追加 bh = 'upperchest' print("upperchest: check begin") for e in meta.humanoid_bone_table: if ("{}".format(e).lower() != 'upperchest'): continue bm = "{}".format(meta.humanoid_bone_table[e]).lower() if (bm == ''): continue humanoidBoneToModel[bh] = bm humanoidBoneParentList[10] = "upperchest" humanoidBoneParentList[12] = "upperchest" humanoidBoneParentList[13] = "upperchest" print("upperchest: find and insert parent") break print("upperchest: check end") FIX_THUMB_MAPPING_FOR_VRM0X = True print("Validating thumb bone mapping...") print(f"Automatic thumb mapping fix: {'ENABLED' if FIX_THUMB_MAPPING_FOR_VRM0X else 'DISABLED'}") for hand_side in ["left", "right"]: thumb_proximal_key = f"{hand_side}thumbproximal" thumb_intermediate_key = f"{hand_side}thumbintermediate" thumb_distal_key = f"{hand_side}thumbdistal" if thumb_proximal_key in humanoidBoneToModel and thumb_intermediate_key in humanoidBoneToModel and thumb_distal_key in humanoidBoneToModel: bone1 = humanoidBoneToModel[thumb_proximal_key] bone2 = humanoidBoneToModel[thumb_intermediate_key] bone3 = humanoidBoneToModel[thumb_distal_key] print(f"{hand_side.capitalize()} thumb mapping:") print(f" Proximal -> {bone1}") print(f" Intermediate -> {bone2}") print(f" Distal -> {bone3}") if FIX_THUMB_MAPPING_FOR_VRM0X and "thumb" in bone1 and "thumb" in bone2: match1 = re.search(r'thumb[\D]*(\d+)', bone1) match2 = re.search(r'thumb[\D]*(\d+)', bone2) if match1 and match2: num1 = int(match1.group(1)) num2 = int(match2.group(1)) if not (1 <= num1 <= 3 and 1 <= num2 <= 3): print(f" Thumb bone numbers outside expected range (1-3): Proximal -> thumb{num1}, Intermediate -> thumb{num2}. Skipping auto-fix.") elif num1 == 2 and num2 == 3: print(f" Detected off-by-one error: Proximal -> thumb{num1}, Intermediate -> thumb{num2}") thumb1_candidates = [b for b in modelBoneNameList if re.match(r'.*thumb[\D]*1(?:\D|$)', b, re.IGNORECASE)] if thumb1_candidates: simple_candidates = [b for b in thumb1_candidates if not any(suffix in b for suffix in ['_twist', '_helper', '_ik', '_fk'])] thumb1_bone = simple_candidates[0] if simple_candidates else thumb1_candidates[0] print(f" Applying fix: Proximal -> {thumb1_bone}, Intermediate -> {bone1}, Distal -> {bone2}") humanoidBoneToModel[thumb_proximal_key] = thumb1_bone humanoidBoneToModel[thumb_intermediate_key] = bone1 humanoidBoneToModel[thumb_distal_key] = bone2 else: print(" Could not find thumb1 bone to apply fix") elif num1 == 1 and num2 == 2: print(" Thumb bone mapping appears correct (1, 2, 3 pattern detected)") print("Thumb validation complete.") parent=None control_to_mat={None:None} count = 0 ### 骨名からControlへのテーブル name_to_control = {"dummy_for_table" : None} print("loop begin") ###### root key = unreal.RigElementKey(unreal.RigElementType.SPACE, 'root_s') space = h_mod.get_space(key) if (space.get_editor_property('index') < 0): space = h_mod.add_space('root_s', space_type=unreal.RigSpaceType.SPACE) else: space = key key = unreal.RigElementKey(unreal.RigElementType.CONTROL, 'root_c') control = h_mod.get_control(key) if (control.get_editor_property('index') < 0): control = h_mod.add_control('root_c', space_name=space.name, gizmo_color=[1.0, 0.0, 0.0, 1.0], ) else: control = key h_mod.reparent_element(control, space) parent = control cc = h_mod.get_control(control) cc.set_editor_property('gizmo_visible', False) h_mod.set_control(cc) for ee in humanoidBoneToModel: element = humanoidBoneToModel[ee] humanoidBone = ee modelBoneNameSmall = element # 対象の骨 #modelBoneNameSmall = "{}".format(element.name).lower() #humanoidBone = modelBoneToHumanoid[modelBoneNameSmall]; boneNo = humanoidBoneList.index(humanoidBone) print("{}_{}_{}__parent={}".format(modelBoneNameSmall, humanoidBone, boneNo,humanoidBoneParentList[boneNo])) # 親 if count != 0: parent = name_to_control[humanoidBoneParentList[boneNo]] # 階層作成 bIsNew = False name_s = "{}_s".format(humanoidBone) key = unreal.RigElementKey(unreal.RigElementType.SPACE, name_s) space = h_mod.get_space(key) if (space.get_editor_property('index') < 0): space = h_mod.add_space(name_s, space_type=unreal.RigSpaceType.SPACE) bIsNew = True else: space = key name_c = "{}_c".format(humanoidBone) key = unreal.RigElementKey(unreal.RigElementType.CONTROL, name_c) control = h_mod.get_control(key) if (control.get_editor_property('index') < 0): control = h_mod.add_control(name_c, space_name=space.name, gizmo_color=[1.0, 0.0, 0.0, 1.0], ) #h_mod.get_control(control).gizmo_transform = gizmo_trans if (24<=boneNo & boneNo<=53): gizmo_trans = unreal.Transform([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.1, 0.1, 0.1]) else: gizmo_trans = unreal.Transform([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [1, 1, 1]) if (17<=boneNo & boneNo<=18): gizmo_trans = unreal.Transform([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [1, 1, 1]) cc = h_mod.get_control(control) cc.set_editor_property('gizmo_transform', gizmo_trans) cc.set_editor_property('control_type', unreal.RigControlType.ROTATOR) h_mod.set_control(cc) #h_mod.set_control_value_transform(control,gizmo_trans) bIsNew = True else: control = key if (bIsNew == True): h_mod.reparent_element(control, space) # テーブル登録 name_to_control[humanoidBone] = control print(humanoidBone) # ロケータ 座標更新 # 不要な上層階層を考慮 try: boneIndex = modelBoneNameList.index(modelBoneNameSmall) except ValueError: print(f"ERROR: Bone '{modelBoneNameSmall}' not found in skeleton hierarchy!") print(f"Available bones: {modelBoneNameList[:10]}...") continue gTransform = h_mod.get_global_transform(modelBoneListAll[boneIndex]) if "thumb" in humanoidBone.lower(): print(f"Thumb bone: {humanoidBone} -> model bone: {modelBoneNameSmall} (index: {boneIndex})") print(f" Transform location: {gTransform.translation}") if count == 0: bone_initial_transform = gTransform else: #bone_initial_transform = h_mod.get_initial_transform(element) bone_initial_transform = gTransform.multiply(control_to_mat[parent].inverse()) h_mod.set_initial_transform(space, bone_initial_transform) control_to_mat[control] = gTransform # 階層修正 h_mod.reparent_element(space, parent) count += 1 if (count >= 500): break