Blender Advent Calendar 2020
https://qiita.com/advent-calendar/2020/blender
に空きが目立ったのもあって Twitterのタイムラインで話題を見かけた
既存のボーンに補助ボーンを作成するスクリプトを即興で書いてみました。
選択しているボーンと垂直に補助ボーンを作るスクリプト
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))
即興なので特に工夫もないけれど軽く解説すると
編集中のアーマーチュアのボーンをたどって 選択されているボーンで
ボーンの変換マトリクスを取得(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の2つがあって微妙に内容が違う
エディットモードのボーン編集は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']