やあ
ブレンダーでキャラクターをいっぱい作った後にちょっと骨の位置を修正したいなーってなったときに書いた、骨を特定のアーマチュアに揃えるスクリプトだよ。
揃える元のアーマチュアがある場合
import bpy from typing import Dict, List def get_obj(name : str): return bpy.data.objects.get(name) def get_children(result: Dict, target_bone) -> List: if len(target_bone.children) == 0: return [] child_name = [] next_tasks = [] for child in target_bone.children: next_tasks.append(child) child_name.append(child.name) if target_bone.name in result: result[target_bone.name] += child_name else: result[target_bone.name] = child_name for child in next_tasks: get_children(result, child) bpy.ops.object.mode_set(mode='OBJECT') """ ---- ソースオブジェクト ---- """ source_obj_name = "source_armature_name" source_armature = get_obj(source_obj_name) source_armature.select = True root_bone_name = "Root" """ ---- 処理をしたいオブジェクトの名前 """ target_obj_names = [ "Armature_A", "Armature_B" ] """ ---- 処理をしたくない骨の親の名前 ---- 例 : 親 : Hand 子 : Thumb, Index, Middle, Ring, Pinky となっているときに、 Handを追加すると、子が無視されます """ ignore_bones_parent_names = [ ] """ ---- 無視したい骨の名前 ---- """ ignore_bone_names = [ ] """ ---- 無視したい骨の名前の一部 ---- """ ignore_part_of_names = [ "IK_", "C_" ] """ ---- トランスフォーム : ヘッドを無視する骨の名前 ---- """ ignore_head_bone_names = [ ] """ ---- トランスフォーム : テイルを無視する骨の名前 ---- """ ignore_tail_bone_names = [ ] """ ---- トランスフォーム : ロールを無視する骨の名前 ---- """ ignore_roll_bone_names = [ ] is_debug = True for target_obj_name in target_obj_names: target_armature = get_obj(target_obj_name) if target_armature: if is_debug: print(target_armature) target_armature.select = True bpy.ops.object.mode_set(mode='EDIT') root_bone = target_armature.pose.bones.get(root_bone_name) if root_bone: children = dict() get_children(children, root_bone) for parent_name, childs in children.items(): if parent_name in ignore_bones_parent_names: continue for bone_name in childs: if bone_name in ignore_bone_names: continue is_found_ignore_bone = False for ignore_part_of_name in ignore_part_of_names: if ignore_part_of_name in bone_name: is_found_ignore_bone = True break if is_found_ignore_bone: continue target_bone = target_armature.data.edit_bones.get(bone_name) if target_bone: source_align_bone = source_armature.data.edit_bones.get(bone_name) if source_align_bone: if parent_name not in ignore_head_bone_names: target_bone.head = [source_align_bone.head[0], source_align_bone.head[1], source_align_bone.head[2]] if parent_name not in ignore_tail_bone_names: target_bone.tail = [source_align_bone.tail[0], source_align_bone.tail[1], source_align_bone.tail[2]] if parent_name not in ignore_roll_bone_names: target_bone.roll = source_align_bone.roll else: if is_debug: print("root bone is None at : " + target_armature.name) bpy.ops.object.mode_set(mode='OBJECT') target_armature.select = False else: if is_debug: print("Target armature is None at : " + target_obj_name) bpy.ops.object.mode_set(mode='OBJECT')
# 指定するのが面倒だから全オブジェクトについて処理したい場合
import bpy from typing import Dict, List def get_obj(name : str): return bpy.data.objects[name] def get_children(result: Dict, target_bone) -> List: if len(target_bone.children) == 0: return [] child_name = [] next_tasks = [] for child in target_bone.children: next_tasks.append(child) child_name.append(child.name) if target_bone.name in result: result[target_bone.name] += child_name else: result[target_bone.name] = child_name for child in next_tasks: get_children(result, child) bpy.ops.object.mode_set(mode='OBJECT') """ ---- ソースオブジェクト ---- """ source_obj_name = "Source_Armature" source_armature = get_obj(source_obj_name) source_armature.select = True root_bone_name = "Root" """ ---- 処理をしたくない骨の親の名前 ---- 例 : 親 : Hand 子 : Thumb, Index, Middle, Ring, Pinky となっているときに、 Handを追加すると、子が無視されます """ ignore_bones_parent_names = [ ] """ ---- 無視したい骨の名前 ---- """ ignore_bone_names = [ ] """ ---- 無視したい骨の名前の一部 ---- """ ignore_part_of_names = [ "IK_", "C_" ] """ ---- トランスフォーム : ヘッドを無視する骨の名前 ---- """ ignore_head_bone_names = [ ] """ ---- トランスフォーム : テイルを無視する骨の名前 ---- """ ignore_tail_bone_names = [ ] """ ---- トランスフォーム : ロールを無視する骨の名前 ---- """ ignore_roll_bone_names = [ ] is_debug = True for obj in bpy.data.objects: if obj.type == "ARMATURE": target_armature = get_obj(obj.name) if target_armature: if is_debug: print(target_armature) target_armature.select = True bpy.ops.object.mode_set(mode='EDIT') root_bone = target_armature.pose.bones.get(root_bone_name) if root_bone: children = dict() get_children(children, root_bone) for parent_name, childs in children.items(): if parent_name in ignore_bones_parent_names: continue for bone_name in childs: if bone_name in ignore_bone_names: continue is_found_ignore_bone = False for ignore_part_of_name in ignore_part_of_names: if ignore_part_of_name in bone_name: is_found_ignore_bone = True break if is_found_ignore_bone: continue target_bone = target_armature.data.edit_bones.get(bone_name) if target_bone: source_align_bone = source_armature.data.edit_bones.get(bone_name) if source_align_bone: if parent_name not in ignore_head_bone_names: target_bone.head = [source_align_bone.head[0], source_align_bone.head[1], source_align_bone.head[2]] if parent_name not in ignore_tail_bone_names: target_bone.tail = [source_align_bone.tail[0], source_align_bone.tail[1], source_align_bone.tail[2]] if parent_name not in ignore_roll_bone_names: target_bone.roll = source_align_bone.roll else: if is_debug: print("root bone is None " + target_armature.name) bpy.ops.object.mode_set(mode='OBJECT') target_armature.select = False else: if is_debug: print("Target armature is None " + obj.name) bpy.ops.object.mode_set(mode='OBJECT')
値を入力して揃える
import bpy align_bone_name = "Hand_L" target_obj_names = [ "Armature_A", "Armature_B" ] def get_obj(name : str): return bpy.data.objects.get(name) source_align_bone_head = [-1.3189, 0.1459, 1.9255] source_align_bone_tail = [-1.3189, -0.2293, 1.9255] source_align_bone_roll = 0.0 if source_align_bone_head == source_align_bone_tail: print(""" -------------- Warning. -------------- The head vector matches the tail vector. This will cause align_bone to be removed. So, this script is cancelled. -------------------------------------- """) else: for target_obj_name in target_obj_names: target_armature = get_obj(target_obj_name) if target_armature: target_armature.select = True print(target_armature) bpy.ops.object.mode_set(mode='EDIT') target_bone = target_armature.data.edit_bones.get(align_bone_name) if target_bone: target_bone.head = source_align_bone_head target_bone.tail = source_align_bone_tail target_bone.roll = source_align_bone_roll bpy.ops.object.mode_set(mode='OBJECT') target_armature.select = False