既存ボーンにスクリプトで補助ボーンを生やしてみる

Blender Advent Calendar 2020
https://qiita.com/advent-calendar/2020/blender
に空きが目立ったのもあって　Twitterのタイムラインで話題を見かけた
既存のボーンに補助ボーンを作成するスクリプトを即興で書いてみました。

選択しているボーンと垂直に補助ボーンを作るスクリプト

```Python:subbone.py
import bpy
import math
from mathutils import Vector, Matrix

context = bpy.context
obj = context.active_object
if context.mode == 'EDIT_ARMATURE':
    obj.update_from_editmode()
    edit_bones = obj.data.edit_bones
    for bone in edit_bones:
        if bone.select:
            #選択ボーンの変換マトリクス
            mat = bone.matrix
            tail_pos = bone.tail
            arm_1 = edit_bones.new('X_arm')
            arm_1.head = tail_pos
            arm_1.tail = mat @ Vector((1,bone.length,0)) 
            arm_2 = edit_bones.new('-X_arm')
            arm_2.head = tail_pos
            arm_2.tail = mat @ Vector((-1,bone.length,0)) 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/088d5ecb-215b-36e6-1035-d746c7370a1e.png)
即興なので特に工夫もないけれど軽く解説すると
編集中のアーマーチュアのボーンをたどって　選択されているボーンで
ボーンの変換マトリクスを取得（bone.matrix）
ただしこのマトリクスはボーンのヘッド部分を基準にするマトリクスになる

Blenderのボーンの座標軸はヘッドからテールを向いた方向が＋Y軸なので
X軸方向に好きな長さを入れて　Y軸にボーン長さを入れた座標にボーンのマトリクスをかけてやればテイルから垂直に伸びた座標になるというわけ。
（mat @ Vector((1,bone.length,0)) 　部分）
選択ボーンをと親子関係をつけた状態にしたければ　

```
arm_1.parent = bone
arm_2.parent = bone
```
とでも書き足せばいいらしい。


Blender2.8以降で　Vector, Matrixの演算の書き方が少しだけ変わっているので
2.7時代のコードを参照するときにはちょっと注意が必要かも？


### 個人的追記
ボーンの情報取得には　bones と　edit_bonesの２つがあって微妙に内容が違う
エディットモードのボーン編集はedit_bonesで　ポーズモードの方も含めた情報はbonesで取得するのか？

```
dir(obj.data.bones[0])
['AxisRollFromMatrix', 'MatrixFromAxisRoll', '__doc__', '__module__', '__slots__', 'bbone_curveinx', 'bbone_curveiny', 'bbone_curveoutx', 'bbone_curveouty', 'bbone_custom_handle_end', 'bbone_custom_handle_start', 'bbone_easein', 'bbone_easeout', 'bbone_handle_type_end', 'bbone_handle_type_start', 'bbone_rollin', 'bbone_rollout', 'bbone_scaleinx', 'bbone_scaleiny', 'bbone_scaleoutx', 'bbone_scaleouty', 'bbone_segments', 'bbone_x', 'bbone_z', 'bl_rna', 'children', 'convert_local_to_pose', 'envelope_distance', 'envelope_weight', 'evaluate_envelope', 'head', 'head_local', 'head_radius', 'hide', 'hide_select', 'inherit_scale', 'layers', 'length', 'matrix', 'matrix_local', 'name', 'parent', 'rna_type', 'select', 'select_head', 'select_tail', 'show_wire', 'tail', 'tail_local', 'tail_radius', 'use_connect', 'use_cyclic_offset', 'use_deform', 'use_endroll_as_inroll', 'use_envelope_multiply', 'use_inherit_rotation', 'use_inherit_scale', 'use_local_location', 'use_relative_parent']
dir(obj.data.edit_bones[0])
['__doc__', '__module__', '__slots__', 'align_orientation', 'align_roll', 'bbone_curveinx', 'bbone_curveiny', 'bbone_curveoutx', 'bbone_curveouty', 'bbone_custom_handle_end', 'bbone_custom_handle_start', 'bbone_easein', 'bbone_easeout', 'bbone_handle_type_end', 'bbone_handle_type_start', 'bbone_rollin', 'bbone_rollout', 'bbone_scaleinx', 'bbone_scaleiny', 'bbone_scaleoutx', 'bbone_scaleouty', 'bbone_segments', 'bbone_x', 'bbone_z', 'bl_rna', 'envelope_distance', 'envelope_weight', 'head', 'head_radius', 'hide', 'hide_select', 'inherit_scale', 'layers', 'length', 'lock', 'matrix', 'name', 'parent', 'rna_type', 'roll', 'select', 'select_head', 'select_tail', 'show_wire', 'tail', 'tail_radius', 'transform', 'use_connect', 'use_cyclic_offset', 'use_deform', 'use_endroll_as_inroll', 'use_envelope_multiply', 'use_inherit_rotation', 'use_inherit_scale', 'use_local_location', 'use_relative_parent']
```