Blenderのカーブオブジェクトに対して動きを付ける場合フックモディファイアを使用することが多いですが
チャットの話題でポイントに対してスクリプトでフックを付けたいという話題があったので
検索結果を参考に作ってみました
アクティブスプラインの選択頂点のみが対象です
まずはエンプティを作成してフックするスクリプト
import bpy
context = bpy.context
curve = context.active_object
# カーブの変換マトリクス
matrix_ = curve.matrix_world
# アクティブスプラインを対象に
spline = curve.data.splines.active
if spline.type == 'NURBS':
for i, point in enumerate(spline.points):
# 選択頂点のみフック作成
if point.select:
hook_mod = curve.modifiers.new(name='scripted hook', type='HOOK')
# フックのターゲットになるエンプティを作成
empty = bpy.data.objects.new("empty_%s" % i, None )
context.scene.collection.objects.link( empty )
empty.location = matrix_ @ point.co.to_3d()
# モディファイアを設定
hook_mod.center = point.co.to_3d()
hook_mod.vertex_indices_set([i])
bpy.context.evaluated_depsgraph_get()
hook_mod.object = empty
elif spline.type == 'BEZIER':
for i, point in enumerate(spline.bezier_points):
# 選択頂点のみフック作成
if point.select_control_point:
hook_mod = curve.modifiers.new(name='scripted hook', type='HOOK')
# フックのターゲットになるエンプティを作成
empty = bpy.data.objects.new("empty_%s" % i, None )
context.scene.collection.objects.link( empty )
empty.location = matrix_ @ point.co.to_3d()
# モディファイアを設定
hook_mod.center = point.co.to_3d()
hook_mod.vertex_indices_set([i*3, i*3+1, i*3+2])
bpy.context.evaluated_depsgraph_get()
hook_mod.object = empty
さらにこれを元に選択頂点位置にボーンを作成したフックさせるスクリプト
import bpy
from mathutils import Vector
context = bpy.context
curve = context.active_object
# カーブの変換マトリクス
matrix_ = curve.matrix_world
# アクティブスプラインを対象に
spline = curve.data.splines.active
def add_arature(context, arm_name, point_list, pos_list):
ref_active = context.active_object
# アーマチュアオブジェクトを作成
arm = bpy.data.armatures.new(arm_name)
arm_obj = bpy.data.objects.new(arm_name, arm)
bpy.context.collection.objects.link(arm_obj)
# アーマチュアの原点をカーブと合わせる
arm_obj.location = curve.location
# アクティブオブジェクトの変更
context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
edit_bones = arm_obj.data.edit_bones
bone_list = []
# 指定位置にボーンを作成
for i, pos in enumerate(pos_list):
bone = edit_bones.new('bone_%s' % i )
bone.head = pos
bone.tail = pos + Vector((0.0, 0.0, 0.5))
bone_list.append(bone.name)
bpy.ops.object.mode_set(mode='OBJECT')
# アクティブオブジェクトを戻す
context.view_layer.objects.active = ref_active
return(arm_obj, bone_list)
# ボーンにフック
def add_hook_mod_bone(obj, arm_obj, bone, hook_center, vertex_indices):
# モディファイアを付与
hook_mod = obj.modifiers.new(name = bone, type='HOOK')
hook_mod.center = hook_center
# 対象の頂点id
hook_mod.vertex_indices_set(vertex_indices)
bpy.context.evaluated_depsgraph_get()
hook_mod.object = arm_obj
hook_mod.subtarget = bone
if spline.type == 'NURBS':
point_list = [ i for i,p in enumerate(spline.points) if p.select ]
pos_list = [ spline.points[i].co.to_3d() for i in point_list ]
elif spline.type == 'BEZIER':
point_list = [i for i,p in enumerate(spline.bezier_points) if p.select_control_point]
pos_list = [ spline.bezier_points[i].co.to_3d() for i in point_list ]
# アーマチュアオブジェクトを作成
arm_name = "Hook"
[arm_obj, bone_list] = add_arature(context, arm_name, point_list, pos_list)
# 選択頂点をボーンにフック
for i, index_ in enumerate(point_list):
hook_center = pos_list[i]
if spline.type == 'NURBS':
vertex_indices = [index_ ]
elif spline.type == 'BEZIER':
vertex_indices = [index_ *3, index_ *3+1, index_ *3+2]
add_hook_mod_bone(curve, arm_obj, bone_list[i], hook_center, vertex_indices)
何かの参考になれば幸いです