カーブ(スプライン)の選択頂点にフックモディファイアを設定する

Blenderのカーブオブジェクトに対して動きを付ける場合フックモディファイアを使用することが多いですが
チャットの話題でポイントに対してスクリプトでフックを付けたいという話題があったので
検索結果を参考に作ってみました
![23031901.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/ac63858b-84d3-57a6-052a-2d3f2e0b3409.gif)

アクティブスプラインの選択頂点のみが対象です

まずはエンプティを作成してフックするスクリプト
```py
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
```

さらにこれを元に選択頂点位置にボーンを作成したフックさせるスクリプト
```py
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)
```

何かの参考になれば幸いです