他のソフトからインポートしたアーマチュアにRigifyリグを作成する

Blenderでキャラクターのデータを作成する時に
Blenderだけで完結すればいいのですが　他のソフトで作成されたデータに動きを付けることもあります

他のソフトで作成されたアーマチュア（ボーン）を利用して
Blender標準搭載のリグシステムのRigifyのリグを作成する手順を考えたいと思います。


今回は[mixamo](https://www.mixamo.com/)からダウンロードしたモデルを使用します
（mixiamoのモデルからRigifyリグを生成するアドオン等はありますが 手順の例としての利用です）

:::note
バージョン4.0以降ではボーン周りに変更されていますが
私が現在業務で使用しているのは3.3のため3.3の内容です
:::
## トランスフォームの調整
mixamoモデルをインポートした状態ではアーマチュアのオブジェクトにスケール等のトランスフォームが入っています
Rigifyではオブジェクトにトランスフォームは無視した状態で作成されますので
トランスフォームを適用します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/e7e4b2d6-510c-f8f7-22f3-6874ca9f0bb9.png)

このままだと　アニメーションデータのルートボーンの移動量が100倍になってしまっているので
グラフエディタでルートボーンの移動のカーブのみ選択して　1/100に変更します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/d2e1a4d6-5eb6-e3b3-08ba-6388a916c561.png)
グラフエディタはX軸が時間軸　Y軸がそれぞれのチャンネルの数値なので
グラフエディタのピボットポイントを2Dカーソルにして　カーソルのY軸が0の状態で
Y軸に0.01倍に拡大　（S Y 0.01 とキー入力）すればいいことになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/2ae03b72-b5f3-f251-3240-e2d0543cf605.png)

:::note
Rigifyのリグのトランスフォームが初期値になるだけなので
作成後　リグのトランスフォームを揃えてしまっても問題ないかもしれません
:::
## 編集モードでのボーン調整
Rigifyのリグでは　背骨　腕　脚等の一連のものとして利用するボーンは
親子関係の上で　接続されている必要があります
単純に「接続」をチェックしただけでは親側のテールの位置に子のボーンが移動してしまうので
子のヘッドの位置に親ボーンのテールを移動させます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/32d556dc-40d2-947e-59a8-f8b98c5b02a0.png)
Shiftキーを押しながら　親側のボーンのテール　子側のボーンのヘッド　の順に選択して
スナップメニューの「選択→アクティブ」を実行することで位置を揃えます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/e83f76bd-df43-c9b4-5168-1171bda04abd.png)

mixamoのボーンで位置を揃えて接続する必要があるのは背骨と頭部　足先と手首親指のボーンになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/edb87b11-6901-ab25-b3cc-111d49aad285.png)

またリグの設定の都合で首の手前の背骨のボーンのテールも位置は揃えておきます

:::note
手元のmixamoモデルでは
左ひじはインポート時に「接続」がチェックされていたものの　右ひじが接続になっていない
といったこともあったので選択していないボーンもチェックする必要があるかもしれません
:::

### カカトのボーンの追加
Rigifyで脚の部分の接地の挙動を利用するために　カカトのボーンを追加する必要があります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/64842d02-e02f-5a84-600a-edea165cb0be.png)

カカトの位置に横向きにボーンを作成して　heel.L heel.Rと名付け
足先の接地部分のボーンの子に設定します　「変形」のチェックボックスは外しておきます

## Rigifyのメタリグ設定
Rigifyは ポーズモードでのボーンプロパティに表示される
**Rigify Type**という設定項目の情報を元にリグを作成します
キャプチャはRigifyの標準のメタリグの左上腕部の標準の設定です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/86c31d4a-e2f5-d8ad-da4b-5d66e33c8933.png)

背骨や腕などの操作に適したリグのプリセットが用意されていて
**Rig type**から選択できます　それぞれのタイプについては以前解説しました ので参照してください

https://qiita.com/yukimituki11/items/ea3c6aba5935ba81d13f

このRigify Typeでボーンの分割数や　リグを配置するボーンレイヤ
形式によってはリグの表示に使うシェイプの設定もできます

Rigifyの機能で作成できるアーマチュアの主要な部分の初期設定をキャプチャしてみるとこんな感じです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/255dc3fb-d1ce-da2d-6e09-06a6d424f179.png)

キャプチャ中の腕や脚のボーンでは
ひねりを加えるために肩と肘等の関節間を2分割（Limb Segments）する入っていて
Blender独自のボーン形式のベンディボーンで中間部分が滑らかに変形する設定になっています
ゲーム等のモーション作成では逆に邪魔になってしまう設定です

これらの設定を自前のボーンに設定していくのは大変です。
関連する設定を目的に合ったように自動設定するスクリプトを作成してみました

## メタリグ情報自動設定スクリプト
先に調整を行ったボーンにこのような設定を付けるスクリプトを作成しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/c5c6d457-2ae9-34d4-9316-eece22ee7651.png)
手動で設定した時の初期値に近いものですが
Limb Segmentsを1にしたり　ボーンレイヤの設定を調整して手間を減らしてあります。

目的のアーマチュアオブジェクトを選択して実行してください
```Apply_rigify_settings_mixamo.py
import bpy
## 外部から持ってきたボーンにRigifyセッティングをつける
setting_List = [
    ['mixamorig:Neck', 'neck_base'], ['mixamorig:Hips', 'spine_base'], 
    ['mixamorig:LeftArm', 'LeftArm'], ['mixamorig:RightArm', 'RightArm'], 
    ['mixamorig:LeftUpLeg', 'LeftLeg'], ['mixamorig:RightUpLeg', 'RightLeg'], 
    ['mixamorig:LeftHandThumb1', 'finger'], ['mixamorig:LeftHandIndex1', 'finger'],
    ['mixamorig:LeftHandMiddle1', 'finger'], ['mixamorig:LeftHandRing1', 'finger'], ['mixamorig:LeftHandPinky1', 'finger'],
    ['mixamorig:RightHandThumb1', 'finger'], ['mixamorig:RightHandIndex1', 'finger'],
    ['mixamorig:RightHandMiddle1', 'finger'], ['mixamorig:RightHandRing1', 'finger'], ['mixamorig:RightHandPinky1', 'finger'],
    ['mixamorig:LeftShoulder', 'Shoulder'], ['mixamorig:RightShoulder', 'Shoulder']
]

## メタリグ設定のテンプレート
# extra_ik_toe = Separate IK Toe[bool],rotation_axis = Rotation Axis['X','Z','automatic'] 
# segments= Limb[int] segments, bbones= bbone segments[int], ik_local_location[bool]
rigify_type_settings = {
    # 首の基部
    'neck_base': {'rigify_type': 'spines.super_head', 'layers':[3,],
                  'connect_chain': True, 'tweak_layers':[4,] ,},
    # 背骨の基部
    'spine_base': {'rigify_type': 'spines.basic_spine', 'layers':[3,],
                  'pivot_pos': 2, 'ik_local_location':False, 'make_fk_controls': True,
                  'fk_layers': [4,], 'tweak_layers': [4,],},
     
    # 左上腕
    'LeftArm': {'rigify_type': 'limbs.arm', 'layers': [7,],
                'segments': 1, 'bbones': 1, 'rotation_axis':'x', 'ik_local_location':False, 'auto_align_extremity':False,
                'fk_layers': [8,], 'tweak_layers':  [9,],},
    # 右上腕
    'RightArm':{'rigify_type': 'limbs.arm', 'layers': [10,],
                'segments': 1, 'bbones': 1, 'rotation_axis':'x', 'ik_local_location':False, 'auto_align_extremity':False,
                'fk_layers':[11,], 'tweak_layers': [12,],},
     
    # 左太もも
    'LeftLeg':{'rigify_type': 'limbs.leg', 'layers': [13,],
                'segments': 1, 'bbones': 1, 'rotation_axis':'x', 'ik_local_location':False,
                'fk_layers': [14,], 'tweak_layers': [15,],},
    # 右太もも
    'RightLeg':{'rigify_type': 'limbs.leg', 'layers': [16,],
                'segments': 1, 'bbones': 1, 'rotation_axis':'x', 'ik_local_location':False,
                'fk_layers': [17,], 'tweak_layers': [18,],},
    # 指
    'finger' :{'rigify_type': 'limbs.super_finger', 'layers': [5,],
                'bbones': 1, 'rotation_axis':'x', 'tweak_layers':[6,],},
    
    # 鎖骨
    'Shoulder':{'rigify_type': 'basic.super_copy', 'layers': [3,], 'relink_constraints':False,
                'make_control':True, 'make_widget':True, 'super_copy_widget_type':'bone', 'make_deform':True,},
    # 汎用のサークルコントローラ
    'Circle':{'rigify_type': 'basic.super_copy', 'layers': [20,], 'relink_constraints':False,
                'make_control':True, 'make_widget':True, 'super_copy_widget_type':'circle', 'make_deform':True,},
}
def set_rigify_type(pose_bones):
    for bone_name, set_name in setting_List:
        attr = rigify_type_settings[set_name]
        for key in attr.keys():
            if 'layers' == key:
                #　ボーンレイヤ設定
                pose_bones[bone_name].bone.layers = [(i in attr[key]) for i in range(32)]
            elif 'rigify_type' == key:
                pose_bones[bone_name].rigify_type = attr[key]
            elif 'fk_layers' == key:
                #　fkレイヤの配置レイヤ
                pose_bones[bone_name].rigify_parameters.fk_layers = [(i in attr[key]) for i in range(32)]
            elif 'tweak_layers' == key:
                #　tweakレイヤ配置レイヤ
                pose_bones[bone_name].rigify_parameters.tweak_layers = [(i in attr[key]) for i in range(32)]
            else:
                # その他の属性
                setattr(pose_bones[bone_name].rigify_parameters, key, attr[key]) 


# Rigify Layer name Settings
# name = Layer Name, row = UI row, group = bone group
rigify_layers_data = (
    {'layers':  0, 'acrive':  True, 'name': "Face", 'row': 1, 'select': False, 'group': 5},
    {'layers':  3, 'acrive':  True, 'name': "Torso", 'row': 3, 'select': False, 'group': 3},
    {'layers':  4, 'acrive': False, 'name': "Torso (Tweak)", 'row': 4, 'select': False, 'group': 4},
    {'layers':  5, 'acrive':  True, 'name': "Fingers", 'row': 5, 'select': False, 'group': 6},
    {'layers':  6, 'acrive': False, 'name': "Fingers (Detail)", 'row': 6, 'select': False, 'group': 5},
    {'layers':  7, 'acrive':  True, 'name': "Arm.L (IK)", 'row': 7, 'select': False, 'group': 2},
    {'layers':  8, 'acrive': False, 'name': "Arm.L (FK)", 'row': 8, 'select': False, 'group': 5},
    {'layers':  9, 'acrive': False, 'name': "Arm.L (Tweak)", 'row': 9, 'select': False, 'group': 4},
    {'layers': 10, 'acrive':  True, 'name': "Arm.R (IK)", 'row': 7, 'select': False, 'group': 2},
    {'layers': 11, 'acrive': False, 'name': "Arm.R (FK)", 'row': 8, 'select': False, 'group': 5},
    {'layers': 12, 'acrive': False, 'name': "Arm.R (Tweak)", 'row': 9, 'select': False, 'group': 4},
    {'layers': 13, 'acrive':  True, 'name': "Leg.L (IK)", 'row': 10, 'select': False, 'group': 2},
    {'layers': 14, 'acrive': False, 'name': "Leg.L (FK)", 'row': 11, 'select': False, 'group': 5},
    {'layers': 15, 'acrive': False, 'name': "Leg.L (Tweak)", 'row': 12, 'select': False, 'group': 4},
    {'layers': 16, 'acrive':  True, 'name': "Leg.R (IK)", 'row': 10, 'select': False, 'group': 2},
    {'layers': 17, 'acrive': False, 'name': "Leg.R (FK)", 'row': 11, 'select': False, 'group': 5},
    {'layers': 18, 'acrive': False, 'name': "Leg.R (Tweak)", 'row': 12, 'select': False, 'group': 4},
    )
def set_rigify_layers(bones):
    # ボーンレイヤ設定の作成
    # 全てのボーンレイヤを非表示状態に
    bones.layers  = [False]*32
    # Rigifyのレイヤを設定
    for attr in rigify_layers_data:
        if 'layers' in attr.keys():
            index = attr.pop('layers')
            bones.layers[index] = attr.pop('acrive')
            for key in attr.keys():
                setattr(bones.rigify_layers[index], key, attr[key])
        

active_object = bpy.context.active_object
if active_object.type == 'ARMATURE':
    bones = active_object.data
    pose_bones = active_object.pose.bones
    # ボーングループの作成
    bpy.ops.armature.rigify_add_bone_groups()
    # レイヤ設定の作成
    bpy.ops.pose.rigify_layer_init()
    # ボーンレイヤ情報の設定
    set_rigify_layers(bones)
    # Rigify用のメタリグ情報も設定
    set_rigify_type(pose_bones)
    #現在のボーンの表示するボーンレイヤ
    active_object.data.layers = [(i in [0,3,5,7,10,13,16,20]) for i in range(32)]
```

スクリプトの
**rigify_type_settings**の辞書に自分で名前をつけたメタリグの設定のテンプレートを記述していて
**setting_List**の配列に[設定したいボーン名,使用するテンプレート名]　のペアで設定対象を記述してます

ボーン名の対応付け設定を変更すれば　他の自作アーマチュアでも同じスクリプトが利用できるかと思います

設定が終わったら　オブジェクトデータプロパティの 「Generete Rig」のボタンを押すことでリグが作成されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/2ee75d99-9ea1-d1b2-e104-d4765068bdaa.png)
うまくリグが作成されない場合には　ボーンの「接続」のチェックが抜けてないか確認してみてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/5ae0222b-41b8-ebb6-384c-da9e91b53b24.png)
例えばこのエラーでは左脚の足先のボーンの接続のチェックを外して実行した例です
エラー箇所まではプログラムが進むので中途半端なアーマチュアが作成されます。

メッシュとの対応付けについては状況によって色々なので　別の機会に触れたいと思います。

### Rigify Type取得スクリプト
最後にRigify Typeの設定されているボーンの情報を取得するスクリプトを置いておきます

```py
import bpy
rigify_atrr = ['auto_align_extremity', 'bbones', 'cluster_ctrls', 'connect_chain', 'conv_bone', 'conv_def', 'copy_rotation_axes', 
 'def_parenting', 'extra_ik_layers', 'extra_ik_layers_extra', 'extra_ik_toe', 'eyelid_detach_option', 
 'eyelid_follow_default', 'eyelid_follow_split', 'fk_layers', 'fk_layers_extra', 'foot_pivot_type', 
 'front_paw_heel_influence', 'ik_local_location', 'jaw_locked_influence', 'jaw_mouth_influence', 
 'jaw_secondary_influence', 'limb_type', 'limb_uniform_scale', 'make_control', 'make_controls', 
 'make_custom_pivot', 'make_deform', 'make_deforms', 'make_extra_control', 'make_extra_deform', 
 'make_extra_ik_control', 'make_fk_controls', 'make_ik_wrist_pivot', 'make_parent_switch', 'make_widget', 
 'name', 'neck_pos', 'optional_widget_type', 'palm_both_sides', 'palm_rotation_axis', 'parent_bone', 
 'pivot_master_widget_type', 'pivot_pos', 'primary_layers', 'primary_layers_extra', 'primary_rotation_axis', 
 'register_parent', 'register_parent_tags', 'relink_constraints', 'rna_type', 'roll_alignment', 'rotation_axis', 
 'secondary_layers', 'secondary_layers_extra', 'segments', 'skin_anchor_hide', 'skin_chain_connect_ends', 
 'skin_chain_connect_mirror', 'skin_chain_connect_sharp_angle', 'skin_chain_falloff', 'skin_chain_falloff_length', 
 'skin_chain_falloff_scale', 'skin_chain_falloff_spherical', 'skin_chain_falloff_to_controls', 
 'skin_chain_falloff_twist', 'skin_chain_pivot_pos', 'skin_chain_priority', 'skin_chain_use_reparent', 
 'skin_chain_use_scale', 'skin_control_orientation_bone', 'skin_glue_add_constraint', 
 'skin_glue_add_constraint_influence', 'skin_glue_head_mode', 'skin_glue_tail_reparent', 'skin_glue_use_tail', 
 'skin_primary_layers', 'skin_primary_layers_extra', 'skin_secondary_layers', 'skin_secondary_layers_extra', 
 'super_copy_widget_type', 'tail_pos', 'tweak_axis', 'tweak_layers', 'tweak_layers_extra', 'use_head', 'use_tail', 
 'wgt_align_axis', 'wgt_offset']
dic_ = {}
active_object = bpy.context.active_object
if active_object.type == 'ARMATURE':
    active_pose_bone = bpy.context.active_pose_bone
    dic_['rigify_type'] = active_pose_bone.rigify_type
    rigify_parameters = active_pose_bone.rigify_parameters
    for attr in rigify_atrr:
            if  hasattr(rigify_parameters, attr):
                dic_[attr] = getattr(rigify_parameters, attr)
print(dic_)
```
先のスクリプトの**rigify_type_settings**の辞書に何を記述すれば目的の設定になるのか調べるのに使えるかと思います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/998d9853-2118-dcce-f66f-f7f405cd8d85.png)


私もテスト中の内容になりますが　一通り形になったので記事にしてみました
何かの参考になれば幸いです。