
[Blender][script]選択中のチャンネルでフィルターする(グラフエディタ、ドープシート)
グラフエディタとドープシートで選択中のチャンネルを検索フィルターに入力します。
複数オブジェクト選択対応。
複数チャンネル選択には非対応。最初に選択したチャンネルが適用されます。
メニュ―バーのビューから実行。日本語と英語でメニュ―が分かれています。
import bpy
import re
def clean_channel_name(name):
""" 前後の [" "] を除去 """
return re.sub(r'^\["(.*)"\]$', r'\1', name)
def get_channel_label(channel, lang="JP"):
""" チャンネルの表示名を取得(日本語版と英語版) """
path = channel.data_path
index = channel.array_index
xyz_labels = ["X", "Y", "Z", "W"]
path_dict_jp = {
"location": "位置",
"rotation_euler": "オイラー角回転",
"rotation_quaternion": "クォータニオン回転",
"scale": "スケール",
"delta_location": "Δ位置",
"delta_rotation_euler": "Δオイラー角回転",
"delta_scale": "Δスケール",
"value": "値",
}
path_dict_eng = {
"location": "Location",
"rotation_euler": "Euler Rotation",
"rotation_quaternion": "Quaternion Rotation",
"scale": "Scale",
"delta_location": "Δ Location",
"delta_rotation_euler": "Δ Euler Rotation",
"delta_scale": "Δ Scale",
"value": "Value",
}
path_dict = path_dict_jp if lang == "JP" else path_dict_eng
for key in path_dict.keys():
if key in path:
return f"{xyz_labels[index]} {path_dict[key]}"
return clean_channel_name(path)
def set_channel_filter(lang="JP"):
""" 最初に選択されたチャンネルを検索フィルターに設定(日本語版と英語版) """
for area in bpy.context.screen.areas:
if area.type in {'DOPESHEET_EDITOR', 'GRAPH_EDITOR'}:
space = area.spaces.active
if not hasattr(space, "dopesheet"):
continue
for obj in bpy.context.selected_objects:
if obj.animation_data and obj.animation_data.action:
for fc in obj.animation_data.action.fcurves:
if fc.select:
channel_name = get_channel_label(fc, lang)
with bpy.context.temp_override(area=area):
space.dopesheet.filter_text = channel_name
print(f"Filter set: {channel_name}")
return
print("No selected channels.")
def menu_func_jp(self, context):
self.layout.operator("anim.set_channel_filter_jp", text="Filter by Selected Channel(JP)")
def menu_func_eng(self, context):
self.layout.operator("anim.set_channel_filter_eng", text="Filter by Selected Channel(ENG)")
class ANIM_OT_SetChannelFilterJP(bpy.types.Operator):
"""選択したチャンネルを基準にフィルターを適用"""
bl_idname = "anim.set_channel_filter_jp"
bl_label = "Filter by Selected Channel(JP)"
def execute(self, context):
set_channel_filter("JP")
return {'FINISHED'}
class ANIM_OT_SetChannelFilterENG(bpy.types.Operator):
"""Apply filter based on selected channel"""
bl_idname = "anim.set_channel_filter_eng"
bl_label = "Filter by Selected Channel(ENG)"
def execute(self, context):
set_channel_filter("ENG")
return {'FINISHED'}
def register():
bpy.utils.register_class(ANIM_OT_SetChannelFilterJP)
bpy.utils.register_class(ANIM_OT_SetChannelFilterENG)
bpy.types.DOPESHEET_MT_view.append(menu_func_jp)
bpy.types.DOPESHEET_MT_view.append(menu_func_eng)
bpy.types.GRAPH_MT_view.append(menu_func_jp)
bpy.types.GRAPH_MT_view.append(menu_func_eng)
def unregister():
bpy.utils.unregister_class(ANIM_OT_SetChannelFilterJP)
bpy.utils.unregister_class(ANIM_OT_SetChannelFilterENG)
bpy.types.DOPESHEET_MT_view.remove(menu_func_jp)
bpy.types.DOPESHEET_MT_view.remove(menu_func_eng)
bpy.types.GRAPH_MT_view.remove(menu_func_jp)
bpy.types.GRAPH_MT_view.remove(menu_func_eng)
if __name__ == "__main__":
register()