忘却まとめ

Blenderの中級者・上級者向けの踏み込んだ情報や、アドオン・3DCGに関する情報を記事にします

スクリプトでキーフレームを高速に操作する【Blender / Python】

その他

投稿日:

下記のような、一般的なfor文(すべてのキーフレームのデータを見て1つずつ処理するやり方では、数が多いとどう調整しても遅い。

複数のポーズオブジェクトの、何百ものボーンの、何千ものキーフレームをfor文で一括操作すると、1秒などかなり気になるレベルで処理が遅くなる。

obj = bpy.context.object
for fc in obj.animation_data.action.fcurves:
    for ky in fc.keyframe_points:
        ky

foreach_get/set

コレクションデータで利用することができる、for文より数百倍高速な手段。
ただし、すべてのアイテムに対して実行する一括設定であり、指定のアイテムだけ設定することができない。

obj = bpy.context.object
for fc in obj.animation_data.action.fcurves:
    # データの入れ子となるダミーリスト。アイテムの個数分複製する。
    base_crds = [False] * len(fc.keyframe_points)
	fc.keyframe_points.foreach_get("select_control_point", base_crds) # 値を取得
	fc.keyframe_points.foreach_set("select_control_point", base_crds) # 値を設定

    # coのようなxとyで複数配列あるデータの場合は、その配列数分乗算する必要がある。
    base_crds = [False] * len(fc.keyframe_points) * 2 
    fc.keyframe_points.foreach_get("co", base_crds) # 状態を取得

coのようなxとyで複数配列あるデータの場合は、ダミーリストは、その配列数分乗算する必要がある。
その場合、XYがすべてまぜこぜになるので、for文で偶数の値だけ設定(if i % 2 == 0)したりする必要があるが、for文を使うと結局遅くなってしまう。これの回避方法がわからない。

内蔵オペレーターを利用する

あまりきれいなやり方ではないが、正直これが一番早い。

キーの選択範囲は、各種標準のキー選択機能を利用してキーを選択し、キーの移動は標準の移動機能を実行する。

タイムラインの表示に依存するが、ボーン選択を一時的に変えたり、Fカーブのロックを活用することで、対象を限定することは可能。

サンプル

カレントフレーム・範囲・前方の3種類から選んで、対象のキーフレームを選択し、移動するサンプルコード。

エディター変更を利用しているため、コンソールエディターで下記のコードを実行した場合はクラッシュするので注意。

import bpy

l = ["CURRENT","RANGE","FORWARD"]
target_type = l[2]
range_frame_start = 25
range_frame_end = 50
delta = 100



sc = bpy.context.scene

# show keys
old_view_key = sc.show_keys_from_selected_only
sc.show_keys_from_selected_only = True


# 一時的にタイムラインエディターに変更する
old_area_type = bpy.context.area.type
bpy.context.area.type = 'DOPESHEET_EDITOR'
bpy.context.area.ui_type = 'TIMELINE'

# all delselect
bpy.ops.action.select_all(action="DESELECT")

# カレントフレーム
if target_type == "CURRENT":
	bpy.ops.action.select_column(mode='CFRA')



# 指定の範囲
# 選択中のマーカーの間を選択を活用し、一時的にマーカーを作って選択し、一時マーカーを削除します
elif target_type == "RANGE":
	old_mark_sel = []
	for i in sc.timeline_markers:
		if i.select:
			old_mark_sel += [i]
		i.select = False

	item_start = sc.timeline_markers.new('LK_start', frame=range_frame_start)
	item_start.select = True
	item_end = sc.timeline_markers.new('LK_end', frame=range_frame_end)
	item_end.select = True

	bpy.ops.action.select_column(mode='MARKERS_BETWEEN') # マーカーの間を選択

	sc.timeline_markers.remove(item_start)
	sc.timeline_markers.remove(item_end)

	for i in old_mark_sel:
		i.select = True

# 現在のフレームの前方
elif target_type in {"FORWARD"}:
	bpy.ops.action.select_leftright(mode='RIGHT', extend=False)



# 移動
bpy.ops.transform.transform(mode='TIME_TRANSLATE',value=(delta, 0, 0, 0))


# エディターを元に戻す
# Switch editor
bpy.context.area.type = old_area_type
# restore show keys
old_view_key = sc.show_keys_from_selected_only

3Dモデルなどの制作依頼はこちら

-その他

Copyright© 忘却まとめ , 2022 All Rights Reserved Powered by STINGER.