MMDモデルへのRigify適用

はじめに

ありがたいことにRigifyの記事が増えており、Rigifyでもっと遊んでみたい。
MMD向けのモデルが大好きなので、Rigifyを適用してBlenderで使いやすくしてみる。

注意事項

レミリアモデルでしかテストしていないので、
他のモデルに使用するにはコード修正が必要と思われます。

MMD以外での使用を禁止しているモデルが多いので、
ご利用の際はモデルのREADMEをよくご確認ください。

MMDモデルのインポート

ここではフリック氏配布のレミリアモデルを使用する。

URL : http://seiga.nicovideo.jp/seiga/im2651527

MMDモデルのインポーターは、sugiany氏作成のものを使用する。

URL : https://github.com/sugiany/blender_mmd_tools
※2015/12/20時点での最新のものを使用。

インポート直後の画像はこちら。

img

インポート後の設定は好みだが、ここでは以下の5つの設定を行う。

  1. マテリアル設定
    ツールシェルフ > mmd_toolsタブ > 「Convert Materials For Cycles」ボタンをクリックし、Cycles用マテリアルの設定をする。

  2. 剛体設定
    ツールシェルフ > mmd_toolsタブ > Rigidbody「Build」ボタンをクリックし、剛体設定を完了させる。

  3. 白目修正
    目に影が出来てしまうので、”目玉”のマテリアルを変更する。
    MMDBasicShaderを切断し、放射シェーダーを接続する。

  4. オブジェクト分離
    以下のマテリアルを選択し、オブジェクトを分離する。
    (ショートカット : P)

    • 青ざめ
    • 魅了の眼
    • 口2
    • 頬紅
    • 照れ
    • 瞳2
  5. オブジェクト配置
    まずはAlt+Hですべてのオブジェクトを表示させ、
    各オブジェクトのレイヤーを変更する。
    必須の設定ではないが、ボーン、メッシュ、それ以外でレイヤーを分けると楽。






ここまではインポーターの機能やモデル特有の設定なので特に自動化はしない。

Rigify適用

ここからはスクリプトを使用してRigifyを適用していく。
エラーに備え、Blenderのシステムコンソールを表示させておく。
(Window > Toggle System Console)

基本データ

まずはMMDとRigifyのボーン名の対応情報を持つスクリプトファイルをBlenderに作成する。
スクリーンレイアウトをScriptingに変更し、テキストを新規作成する。
ファイル名は”commons.py”とする。
※この名前を使用してモジュールインポートしているので、ファイル名は固定で。

img

以下のコードをテキストエディタに貼り付ける。

class BoneNameMap(dict):
pitchipoy = True
def __init__(self, pitchipoy=True):
dict.__init__(self)
self.pitchipoy = pitchipoy
def set_LR_name(self, key, value, value_suffix=""):
self[key + ".L"] = value + ".L" + value_suffix
self[key + ".R"] = value + ".R" + value_suffix
class MetarigMmdTailBoneNameMap(BoneNameMap):
def __init__(self, pitchipoy=True):
BoneNameMap.__init__(self, pitchipoy)
self.set_LR_name("shoulder", "肩")
self.set_LR_name("upper_arm", "腕捩")
self.set_LR_name("forearm", "手捩")
self.set_LR_name("hand", "手首")
self.set_LR_name("thumb.01", "親指0")
self.set_LR_name("thumb.02", "親指1")
self.set_LR_name("thumb.03", "親指2")
self.set_LR_name("f_index.01", "人指1")
self.set_LR_name("f_index.02", "人指2")
self.set_LR_name("f_index.03", "人指3")
self.set_LR_name("f_middle.01", "中指1")
self.set_LR_name("f_middle.02", "中指2")
self.set_LR_name("f_middle.03", "中指3")
self.set_LR_name("f_ring.01", "薬指1")
self.set_LR_name("f_ring.02", "薬指2")
self.set_LR_name("f_ring.03", "薬指3")
self.set_LR_name("f_pinky.01", "小指1")
self.set_LR_name("f_pinky.02", "小指2")
self.set_LR_name("f_pinky.03", "小指3")
self.set_LR_name("thigh", "足")
self.set_LR_name("shin", "ひざ")
self.set_LR_name("foot", "足首")
if self.pitchipoy:
self["spine.001"] = "上半身"
self["spine.003"] = "上半身2"
self["spine.005"] = "首"
self["spine.006"] = "頭"
else:
self["spine"] = "上半身"
self["chest"] = "上半身2"
self["neck"] = "首"
self["head"] = "頭"
class MetarigMmdHeadBoneNameMap(BoneNameMap):
def __init__(self, pitchipoy=True):
BoneNameMap.__init__(self, pitchipoy)
self.set_LR_name("shoulder", "肩")
self.set_LR_name("upper_arm", "腕")
self.set_LR_name("thumb.01", "親指0")
self.set_LR_name("f_index.01", "人指1")
self.set_LR_name("f_middle.01", "中指1")
self.set_LR_name("f_ring.01", "薬指1")
self.set_LR_name("f_pinky.01", "小指1")
self.set_LR_name("thigh", "足")
if self.pitchipoy:
self["face"] = "頭"
else:
self["neck"] = "首"
class MmdRigifyBoneNameMap(BoneNameMap):
def __init__(self, pitchipoy=True):
BoneNameMap.__init__(self, pitchipoy)
self.set_LR_name("足首D", "DEF-foot")
self.set_LR_name("足先EX", "DEF-toe")
self.set_LR_name("肩", "DEF-shoulder")
self.set_LR_name("手首", "DEF-hand")
self.set_LR_name("親指1", "DEF-thumb.02")
self.set_LR_name("親指2", "DEF-thumb.03")
self.set_LR_name("人指2", "DEF-f_index.02")
self.set_LR_name("人指3", "DEF-f_index.03")
self.set_LR_name("中指2", "DEF-f_middle.02")
self.set_LR_name("中指3", "DEF-f_middle.03")
self.set_LR_name("薬指2", "DEF-f_ring.02")
self.set_LR_name("薬指3", "DEF-f_ring.03")
self.set_LR_name("小指2", "DEF-f_pinky.02")
self.set_LR_name("小指3", "DEF-f_pinky.03")
if self.pitchipoy:
self["下半身"] = "DEF-spine"
self["上半身"] = "DEF-spine.001"
self["上半身2"] = "DEF-spine.003"
self["首"] = "DEF-spine.005"
self["頭"] = "DEF-spine.006"
self.set_LR_name("足D", "DEF-thigh", ".001")
self.set_LR_name("ひざD", "DEF-shin", ".001")
self.set_LR_name("腕", "DEF-upper_arm")
self.set_LR_name("腕捩", "DEF-upper_arm", ".001")
self.set_LR_name("ひじ", "DEF-forearm")
self.set_LR_name("手捩", "DEF-forearm", ".001")
self.set_LR_name("親指0", "DEF-thumb.01")
self.set_LR_name("人指1", "DEF-f_index.01")
self.set_LR_name("中指1", "DEF-f_middle.01")
self.set_LR_name("薬指1", "DEF-f_ring.01")
self.set_LR_name("小指1", "DEF-f_pinky.01")
else:
self["下半身"] = "DEF-hips"
self["上半身"] = "DEF-spine"
self["上半身2"] = "DEF-chest"
self["首"] = "DEF-neck"
self["頭"] = "DEF-head"
self.set_LR_name("足D", "DEF-thigh.02")
self.set_LR_name("ひざD", "DEF-shin.02")
self.set_LR_name("腕", "DEF-upper_arm.01")
self.set_LR_name("腕捩", "DEF-upper_arm.02")
self.set_LR_name("ひじ", "DEF-forearm.01")
self.set_LR_name("手捩", "DEF-forearm.02")
self.set_LR_name("親指0", "DEF-thumb.01", ".01")
self.set_LR_name("人指1", "DEF-f_index.01", ".01")
self.set_LR_name("中指1", "DEF-f_middle.01", ".01")
self.set_LR_name("薬指1", "DEF-f_ring.01", ".01")
self.set_LR_name("小指1", "DEF-f_pinky.01", ".01")
if __name__ == "__main__":
print("---------- start test ----------")
print("* test MetarigMmdTailBoneNameMap")
metarig_tail_map = MetarigMmdTailBoneNameMap(True)
[print(x) for x in metarig_tail_map.keys()]
print()
print("* test MetarigMmdHeadBoneNameMap")
metarig_head_map = MetarigMmdHeadBoneNameMap(True)
[print(x) for x in metarig_head_map.keys()]
print()
print("* test MmdRigifyBoneNameMap")
mmd_rigify_map = MmdRigifyBoneNameMap(True)
[print(x) for x in mmd_rigify_map.values()]
print("---------- end test ----------")
view raw commons.py hosted with ❤ by GitHub



このスクリプトは他のスクリプトから呼ばれるものなので、
ここではまだスクリプト実行を行わない。
貼り付け後の画像は以下。

img

metarig生成

テキストを新規作成し、以下のコードを張り付ける。
※ファイル名は何でもよい。

import bpy, mathutils
from mathutils import Vector
from commons import MetarigMmdTailBoneNameMap, MetarigMmdHeadBoneNameMap
class MetarigController:
pitchipoy = True
obj_mmd = bpy.context.active_object
obj_metarig = None
arm_mmd = None
arm_metarig = None
bone_name_map_tail = MetarigMmdTailBoneNameMap(pitchipoy)
bone_name_map_head = MetarigMmdHeadBoneNameMap(pitchipoy)
extra_required_bone_names = ["下半身",]
mmd_bone_map = {}
bone_location_map_tail = {}
bone_location_map_head = {}
def execute(self):
if self.check() == False: return
if self.get_bone() == False: return
if self.init_bone_location_map() == False: return
if self.create_metarig() == False: return
if self.edit_bone() == False: return
# Rigifyの生成も可能だが、かなり時間が必要なうえ、
# 画面の表示が変化しないのでここでは実行しない。
# 生成したMetarigを微調整する可能性もある。
# if self.createRigify() == False: return
def check(self):
if self.obj_mmd is None:
print('can not find object')
return False
if self.obj_mmd.type != 'ARMATURE':
print('selected object is not armature : ' + self.obj_mmd.type)
return False
if self.obj_mmd.mode != 'OBJECT':
print('selected object is not object mode : ' + self.obj_mmd.mode)
return False
# if hasattr(self.obj_mmd, "mmd_root") == False:
# print('selected object has no attrivute : mmd_root')
# return False
self.arm_mmd = self.obj_mmd.data
if self.arm_mmd is None:
print('can not find MMD armature')
return False
print('success check')
return True
def get_bone(self):
# 重複のないボーン名のリストを作成する。
bone_name_list =[]
bone_name_list.extend(self.bone_name_map_tail.values())
bone_name_list.extend(self.bone_name_map_head.values())
bone_name_list.extend(self.extra_required_bone_names)
bone_name_list = list(set(bone_name_list))
# ボーン名をキーにしたMMDボーン辞書を作成
for bone in self.arm_mmd.bones:
if bone.name in bone_name_list:
self.mmd_bone_map[bone.name] = bone
# 必要なボーンが無い場合は終了
if len(bone_name_list) != len(self.mmd_bone_map.keys()):
print('MMD armature has no required bone.')
return False
print('success get bone')
return True
def init_bone_location_map(self):
# 単純な対応関係ではないボーンの位置を設定する。
# metarigタイプ別の設定
if self.pitchipoy:
# pelvisの先端は特に設定していない。
self.bone_location_map_tail["spine.004"] = self.getCenter(self.mmd_bone_map["首"])
self.bone_location_map_tail["spine"] = self.mmd_bone_map["下半身"].head_local
self.bone_location_map_tail["spine.002"] = self.getCenter(self.mmd_bone_map["上半身2"])
self.bone_location_map_tail["face"] = self.getCenter(self.mmd_bone_map["頭"])
spine_tail = self.mmd_bone_map["下半身"].tail_local
self.bone_location_map_head["spine"] = spine_tail
self.bone_location_map_head["pelvis.L"] = spine_tail
self.bone_location_map_head["pelvis.R"] = spine_tail
heel_tail_L = self.mmd_bone_map["ひざ.L"].tail_local.copy()
heel_tail_L[0] += 0.067
heel_tail_L[1] += 0.05
heel_tail_L[2] = 0.0
self.bone_location_map_tail["heel.02.L"] = heel_tail_L
heel_tail_R = self.mmd_bone_map["ひざ.R"].tail_local.copy()
heel_tail_R[0] -= 0.067
heel_tail_R[1] += 0.05
heel_tail_R[2] = 0.0
self.bone_location_map_tail["heel.02.R"] = heel_tail_R
heel_head_L = self.mmd_bone_map["ひざ.L"].tail_local.copy()
heel_head_L[0] -= 0.067
heel_head_L[1] += 0.05
heel_head_L[2] = 0.0
self.bone_location_map_head["heel.02.L"] = heel_head_L
heel_head_R = self.mmd_bone_map["ひざ.R"].tail_local.copy()
heel_head_R[0] += 0.067
heel_head_R[1] += 0.05
heel_head_R[2] = 0.0
self.bone_location_map_head["heel.02.R"] = heel_head_R
else:
self.bone_location_map_tail["hips"] = self.mmd_bone_map["下半身"].head_local
ex_heel_tailL = self.mmd_bone_map["ひざ.L"].tail_local.copy()
ex_heel_tailL[1] += 0.12
ex_heel_tailL[2] = 0.0
self.bone_location_map_tail["heel.L"] = ex_heel_tailL
ex_heel_tailR = self.mmd_bone_map["ひざ.R"].tail_local.copy()
ex_heel_tailR[1] += 0.12
ex_heel_tailR[2] = 0.0
self.bone_location_map_tail["heel.R"] = ex_heel_tailR
heel_tail_L = self.mmd_bone_map["ひざ.L"].tail_local.copy()
heel_tail_L[0] += 0.067
heel_tail_L[2] = 0.0
self.bone_location_map_tail["heel.02.L"] = heel_tail_L
heel_tail_R = self.mmd_bone_map["ひざ.R"].tail_local.copy()
heel_tail_R[0] -= 0.067
heel_tail_R[2] = 0.0
self.bone_location_map_tail["heel.02.R"] = heel_tail_R
heel_head_L = self.mmd_bone_map["ひざ.L"].tail_local.copy()
heel_head_L[0] -= 0.067
heel_head_L[2] = 0.0
self.bone_location_map_head["heel.02.L"] = heel_head_L
heel_head_R = self.mmd_bone_map["ひざ.R"].tail_local.copy()
heel_head_R[0] += 0.067
heel_head_R[2] = 0.0
self.bone_location_map_head["heel.02.R"] = heel_head_R
# tail
self.bone_location_map_tail["palm.01.L"] = self.mmd_bone_map["人指1.L"].head_local
self.bone_location_map_tail["palm.02.L"] = self.mmd_bone_map["中指1.L"].head_local
self.bone_location_map_tail["palm.03.L"] = self.mmd_bone_map["薬指1.L"].head_local
self.bone_location_map_tail["palm.04.L"] = self.mmd_bone_map["小指1.L"].head_local
self.bone_location_map_tail["palm.01.R"] = self.mmd_bone_map["人指1.R"].head_local
self.bone_location_map_tail["palm.02.R"] = self.mmd_bone_map["中指1.R"].head_local
self.bone_location_map_tail["palm.03.R"] = self.mmd_bone_map["薬指1.R"].head_local
self.bone_location_map_tail["palm.04.R"] = self.mmd_bone_map["小指1.R"].head_local
toe_L = self.mmd_bone_map["足首.L"].tail_local.copy()
toe_L[1] -= 0.11
self.bone_location_map_tail["toe.L"] = toe_L
toe_R = self.mmd_bone_map["足首.R"].tail_local.copy()
toe_R[1] -= 0.11
self.bone_location_map_tail["toe.R"] = toe_R
# head
wrist_L = self.mmd_bone_map["手捩.L"].tail_local
index_L = self.mmd_bone_map["人指1.L"].head_local
middle_L = self.mmd_bone_map["中指1.L"].head_local
ring_L = self.mmd_bone_map["薬指1.L"].head_local
pinky_L = self.mmd_bone_map["小指1.L"].head_local
self.bone_location_map_head["palm.01.L"] = self.getCentre(index_L, wrist_L)
self.bone_location_map_head["palm.02.L"] = self.getCentre(middle_L, wrist_L)
self.bone_location_map_head["palm.03.L"] = self.getCentre(ring_L, wrist_L)
self.bone_location_map_head["palm.04.L"] = self.getCentre(pinky_L, wrist_L)
wrist_R = self.mmd_bone_map["手捩.R"].tail_local
index_R = self.mmd_bone_map["人指1.R"].head_local
middle_R = self.mmd_bone_map["中指1.R"].head_local
ring_R = self.mmd_bone_map["薬指1.R"].head_local
pinky_R = self.mmd_bone_map["小指1.R"].head_local
self.bone_location_map_head["palm.01.R"] = self.getCentre(index_R, wrist_R)
self.bone_location_map_head["palm.02.R"] = self.getCentre(middle_R, wrist_R)
self.bone_location_map_head["palm.03.R"] = self.getCentre(ring_R, wrist_R)
self.bone_location_map_head["palm.04.R"] = self.getCentre(pinky_R, wrist_R)
print('success init bone location map')
return True
def getCenter(self, bone):
return self.getCentre(bone.tail_local, bone.head_local)
def getCentre(self, vector1, vector2):
def_x = (vector1[0] - vector2[0]) / 2.0
def_y = (vector1[1] - vector2[1]) / 2.0
def_z = (vector1[2] - vector2[2]) / 2.0
return Vector((vector2[0] + def_x, vector2[1] + def_y, vector2[2] + def_z))
def create_metarig(self):
# Rigifyのメタリグはどこに置いたとしても、
# 生成ボタンをおすと(0, 0, 0)にRigifyArmatureが生成される。
# よってメタリグも(0, 0, 0)に生成するようにする。
bpy.context.scene.cursor_location = (0.0, 0.0, 0.0)
if self.pitchipoy: bpy.ops.object.armature_pitchipoy_human_metarig_add()
else: bpy.ops.object.armature_human_metarig_add()
self.obj_metarig = bpy.context.object
self.arm_metarig = self.obj_metarig.data
# 縮尺をだいたい合わせる
z_mmd = self.mmd_bone_map["頭"].tail_local[2]
if self.pitchipoy:
z_rigify = self.arm_metarig.bones["spine.006"].tail_local[2]
else:
z_rigify = self.arm_metarig.bones["head"].tail_local[2]
scale = z_mmd / z_rigify
self.obj_metarig.scale = (scale, scale, scale)
bpy.ops.object.transform_apply(scale=True)
print('success create metarig')
return True
def edit_bone(self):
bpy.context.scene.objects.active = self.obj_metarig
self.obj_metarig.select = True
bpy.ops.object.mode_set(mode='EDIT')
for bone_rigify in self.arm_metarig.edit_bones:
# tailの位置合わせ
if bone_rigify.name in self.bone_name_map_tail:
key_mmd = self.bone_name_map_tail[bone_rigify.name]
bone_mmd = self.mmd_bone_map[key_mmd]
bone_rigify.tail = bone_mmd.tail_local
# headの位置合わせ
if bone_rigify.name in self.bone_name_map_head:
key_mmd = self.bone_name_map_head[bone_rigify.name]
bone_mmd = self.mmd_bone_map[key_mmd]
bone_rigify.head = bone_mmd.head_local
# その他の位置合わせ
if bone_rigify.name in self.bone_location_map_tail:
bone_rigify.tail = self.bone_location_map_tail[bone_rigify.name]
if bone_rigify.name in self.bone_location_map_head:
bone_rigify.head = self.bone_location_map_head[bone_rigify.name]
bpy.ops.object.mode_set(mode='OBJECT')
print('success edit bone')
return True
def createRigify(self):
bpy.ops.pose.rigify_generate()
print('success create rigify')
return True
if __name__ == "__main__":
print("---------- start script ----------")
MetarigController().execute()
print("---------- end script ----------")



MMDアーマチュアを選択した状態で、スクリプトを実行する。

img

スクリプト実行後、metarigが生成されていることを確認する。

img

Rigify生成

メタリグのアーマチュアタブの一番下、「生成」(Generate)ボタンをクリックし、
Rigifyアーマチュアを生成する。

img

必須ではないが、Rigifyアーマチュア生成後はmetarigをどこか適当なレイヤーに移動させておく。
ここではボーンシェイプオブジェクトが生成される19番レイヤーに移動しておく。

img

Rigifyボーン設定

以下のコードをテキストエディタに張り付ける。
※metarig生成時のコードを上書きでOK

import bpy
from commons import MmdRigifyBoneNameMap
class RigifyBoneController:
pitchipoy = True
objects = bpy.context.selected_objects
obj_mmd = None
obj_rigify = None
arm_mmd = None
arm_rigify = None
rig_id = ""
bone_name_map = MmdRigifyBoneNameMap(pitchipoy)
def execute(self):
if self.check() == False: return
if self.join() == False: return
if self.change_parent() == False: return
def check(self):
if len(self.objects) != 2:
print('selected objects count : ' + str(len(self.objects)))
return False
for obj in self.objects:
if obj.type != 'ARMATURE':
print('selected object is not mesh : ' + obj.type)
return False
if obj.mode != 'OBJECT':
print('selected object is not object mode : ' + obj.mode)
return False
for obj in self.objects:
if "rig_id" in obj.data:
self.obj_rigify = obj
else:
self.obj_mmd = obj
if self.obj_mmd == None:
print('can not find MMD object')
return False
if self.obj_rigify == None:
print('can not find Rigify object')
return False
self.arm_mmd = self.obj_mmd.data
self.arm_rigify = self.obj_rigify.data
self.rig_id = self.arm_rigify["rig_id"]
print("rigify rig id : " + self.rig_id)
print('success check')
return True
def join(self):
# ボーンレイヤーを変更
for bone in self.arm_mmd.bones:
if bone.layers[0] == True:
bone.layers[24] = True
bone.layers[0] = False
if bone.layers[8] == True:
bone.layers[25] = True
bone.layers[8] = False
# 可視レイヤーを一時保存
layers = self.arm_rigify.layers
# 統合
bpy.context.scene.objects.active = self.obj_mmd
bpy.ops.object.join()
self.arm_mmd.layers = layers
self.obj_mmd.draw_type = 'WIRE'
self.arm_mmd["rig_id"] = self.rig_id
# MMDボーンを可視にしないと、ボーンコンストレイントの編集でエラーとなる
self.arm_mmd.layers[24] = True
self.arm_mmd.layers[25] = True
# レントゲン設定(おまけ)
self.obj_mmd.show_x_ray = True
print('success join')
return True
def change_parent(self):
bpy.context.scene.objects.active = self.obj_mmd
self.obj_mmd.select = True
bpy.ops.object.mode_set(mode='EDIT')
for bone in self.arm_mmd.edit_bones:
if bone.name in self.bone_name_map:
continue
if bone.parent is not None:
if bone.parent.name in self.bone_name_map:
parentName = self.bone_name_map[bone.parent.name]
bone.parent = self.arm_mmd.edit_bones[parentName]
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='POSE')
for bone in self.obj_mmd.pose.bones:
for constraint in bone.constraints:
if constraint.type == 'CHILD_OF':
if constraint.subtarget in self.bone_name_map:
# ボーンコンストレイントの親を変更
constraint.subtarget = self.bone_name_map[constraint.subtarget]
# 逆補正を設定
pbone = bpy.context.active_object.pose.bones[bone.name]
context = bpy.context.copy()
context["constraint"] = constraint
bpy.context.active_object.data.bones.active = pbone.bone
bpy.ops.constraint.childof_set_inverse(context, constraint=constraint.name, owner='BONE')
bpy.ops.object.mode_set(mode='OBJECT')
self.arm_mmd.layers[24] = False
self.arm_mmd.layers[25] = False
print('success change parent')
return True
if __name__ == "__main__":
print("---------- start script ----------")
RigifyBoneController().execute()
print("---------- end script ----------")



MMDアーマチュアと、生成されたRigifyアーマチュアを選択してスクリプトを実行する。
※アクティブオブジェクトはスクリプト内で設定しているので、選択する順番は適当でOK

img

スクリプトを実行すると、MMDアーマチュアとRigifyアーマチュアが統合される。

img

ここでは大まかに以下の処理を行っている。

  • MMDボーンを24,25番レイヤーに移動
  • MMDアーマチュアとRigifyアーマチュアを統合
  • MMDボーンの親をRigifyボーンに変更
  • MMDボーンに付与されているコンストレイントのターゲット先をRigifyボーンに変更

頂点グループ名変更

以下のコードをテキストエディタに張り付ける。
※Rigifyボーン設定時のコードを上書きでOK

import bpy
from commons import MmdRigifyBoneNameMap
class VertexNameController:
pitchipoy = True
obj = bpy.context.active_object
bone_name_map = MmdRigifyBoneNameMap(pitchipoy)
def execute(self):
if self.check() == False: return
if self.rename() == False: return
def check(self):
if self.obj.type != 'MESH':
print('selected object is not mesh : ' + obj.type)
return False
if self.obj.mode != 'OBJECT':
print('selected object is not object mode : ' + self.obj.mode)
return False
bone_count = 0
for vertex_group in self.obj.vertex_groups:
if vertex_group.name in self.bone_name_map:
bone_count += 1
if len(self.bone_name_map.keys()) != bone_count:
print('bone count : ' + str(bone_count))
return False
print('success check')
return True
def rename(self):
for vertex_group in self.obj.vertex_groups:
if vertex_group.name in self.bone_name_map:
vertex_group.name = self.bone_name_map[vertex_group.name]
print('success rename')
return True
if __name__ == "__main__":
print("---------- start script ----------")
VertexNameController().execute()
print("---------- end script ----------")



モデルのメッシュを選択した状態でスクリプトを実行する。

img

スクリプト実行後、モデルの頂点グループ名がRigifyボーンの名前に置き換わる。

img

剛体設定

以下のコードをテキストエディタに張り付ける。
※頂点グループ名変更時のコードを上書きでOK

import bpy
from commons import MmdRigifyBoneNameMap
class RigController:
pitchipoy = True
objects = bpy.context.selected_objects
bone_name_map = MmdRigifyBoneNameMap(pitchipoy)
def execute(self):
if self.change_parent() == False: return
def change_parent(self):
for obj in self.objects:
if obj.type != 'MESH':
continue
for constraint in obj.constraints:
if constraint.type != 'CHILD_OF':
continue
if constraint.subtarget in self.bone_name_map:
# 一つ一つの処理が重いので、名前を表示させて進捗確認
print(obj.name)
bpy.context.scene.objects.active = obj
obj.select = True
bpy.ops.object.mode_set(mode='EDIT')
# ボーンコンストレイントの親を変更
constraint.subtarget = self.bone_name_map[constraint.subtarget]
# 逆補正を設定
context = bpy.context.copy()
context["constraint"] = constraint
bpy.context.active_object.data = obj.data
bpy.ops.constraint.childof_set_inverse(context, constraint=constraint.name, owner='OBJECT')
bpy.ops.object.mode_set(mode='OBJECT')
print('success change parent')
return True
if __name__ == "__main__":
print("---------- start script ----------")
RigController().execute()
print("---------- end script ----------")
view raw adjust_rig.py hosted with ❤ by GitHub



剛体を選択した状態でスクリプトを実行する。
※結構時間がかかるので、コンソールを眺めながらのんびり待つ。

img

確認

再生ボタンをクリックしてRigifyボーンを動かすと、
メッシュと剛体がボーンに追従して動くことが確認できる。

img

おまけ

Deformボーンの表示・非表示ボタンの追加は以下の記事を参考に。
URL : http://ch.nicovideo.jp/takosuke/blomaga/ar710878

おわりに

私自身は、今のところレミリアモデルしか使用する予定がないので、
他のモデルへの対応は未定。
また、Rigify Typeに応じた処理なども実装していないですが、
標準Rigifyボーンで満足してしまっているのでこちらも優先度が低いです。

各スクリプトファイルのpitchipoyプロパティをすべてFalseにすると、
pitchipoyでない方のRigifyアーマチュアの作成が可能です。

このページのソースコードはすべてライセンスCC0とします。
MMD x Rigifyのアドオンが増えることを願います。
(Rigify適用モデルを配布なんかしていただけたら・・・凄くありがたい!)

何かありましたら、@takosuke_twまで連絡下さい。