Skip to content

Instantly share code, notes, and snippets.

@green224
Created March 11, 2020 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save green224/fe689f5b39081a0d4a8374204f3e9ef0 to your computer and use it in GitHub Desktop.
Save green224/fe689f5b39081a0d4a8374204f3e9ef0 to your computer and use it in GitHub Desktop.
モデルを、NLAトラックごとに分離して出力するアドオン
"""
アニメーションをFBX出力をするアドオン。
そのままのFBX出力では、ConstraintsやDriverを複数使用した場合に
反映が1フレーム遅延した結果、正常なモーションを出力できない事がある。
このアドオンでは、モーションをそれぞれ1フレーム目の姿勢で何度か再計算してから開始する事で、
なるべくいい感じにモーションが出力されるようにする。
使い方
1.File->Export Split Anim FBX を選択する
3.FBXが出力される。
注意
・出力対象のアニメーションは、NLAトラックのみ。
Actionは出力されないので、出力したいアニメーションはNLAトラック化すること。
・NLAトラックはミュートでもミュートで無くても全部出力される
"""
import bpy
import time
import os
from bpy.types import (
Operator,
Panel,
PropertyGroup,
OperatorFileListElement,
)
from bpy.props import (
BoolProperty,
PointerProperty,
StringProperty,
CollectionProperty,
FloatProperty,
EnumProperty,
IntProperty,
)
# プラグインに関する情報
bl_info = {
"name" : "Split FBX Exporter",
"author" : "Shu",
"version" : (0,2),
'blender': (2, 80, 0),
"location": "File > Import-Export",
"description" : "Export Splitted FBX",
"warning" : "",
"wiki_url" : "",
"tracker_url" : "",
"category" : "Import-Export"
}
#-------------------------------------------------------
# メニュー項目オペレータ
class ExpSplittedFBXOpe(Operator):
bl_idname = "export_scene.split_fbx"
bl_label = "Export Splitted Anim FBX"
bl_options = {'REGISTER'}
def execute(self, context):
if export(): return {'FINISHED'}
return {'CANCELLED'}
# 出力処理本体
def export():
print("[ExportFBX] Begin")
tgt_armature = None
for obj in bpy.data.objects:
if not obj :continue
if obj.type != 'ARMATURE':continue
tgt_armature = obj
break
# オリジナルArmatureのモードおよび、NLAトラックのミュート状態を記憶しておく
bpy.context.view_layer.objects.active = tgt_armature
old_mode = bpy.context.object.mode
bpy.ops.object.mode_set(mode='POSE')
old_tracks_mute = []
for track in tgt_armature.animation_data.nla_tracks:
old_tracks_mute.append(track.mute)
# シェイプキーのあるオブジェクトだけ選択
for obj in bpy.data.objects:
if not obj :continue
if obj.type != 'MESH':continue
if obj.data.shape_keys is not None: obj.select_set(True)
# アニメーションの選択フレームを1にする
bpy.context.scene.frame_set(1)
# アクションは非選択にしておく
bpy.context.object.animation_data.action = None
for track in tgt_armature.animation_data.nla_tracks:
track.mute = True
for track in tgt_armature.animation_data.nla_tracks:
track.mute = False
for i in tgt_armature.data.bones: i.select = True
bpy.context.view_layer.update()
for i in tgt_armature.data.bones: i.select = False
bpy.context.view_layer.update()
# bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# FBX出力
mdl_filepath = bpy.data.filepath
mdl_directory = os.path.dirname( mdl_filepath ) + "\\FBXs"
fbx_filepath = os.path.join( mdl_directory, track.name + ".fbx" )
exportFbxCore(fbx_filepath, True, True)
track.mute = True
# キーのないボーンのTransformをデフォルト状態にしておく
bpy.ops.pose.select_all(action='SELECT')
bpy.ops.pose.transforms_clear()
bpy.context.view_layer.update()
# 最後にメッシュだけ出力する
mdl_filepath = bpy.data.filepath
mdl_directory = os.path.dirname( mdl_filepath ) + "\\FBXs"
#mdl_filename = os.path.splitext(os.path.basename(mdl_filepath))[0] + ".fbx"
mdl_filename = subdirname = os.path.basename(os.path.dirname(mdl_filepath)) + ".fbx"
fbx_filepath = os.path.join( mdl_directory, mdl_filename )
exportFbxCore(fbx_filepath, False, False)
# オリジナルArmatureのモードおよびNLAトラックのミュート状態を復元する
bpy.context.view_layer.objects.active = tgt_armature
bpy.ops.object.mode_set(mode=old_mode)
for i,track in enumerate(tgt_armature.animation_data.nla_tracks):
track.mute = old_tracks_mute[i]
bpy.context.view_layer.update()
print("[ExportFBX] Complete")
return True
def exportFbxCore(filePath, export_anim, use_selection):
bpy.ops.export_scene.fbx(
filepath=filePath,
check_existing=False,
axis_up='Y',
axis_forward='-Z',
filter_glob="*.fbx",
use_selection=use_selection,
global_scale=1.0,
bake_space_transform=True,
object_types={'MESH', 'ARMATURE'},
use_mesh_modifiers=True,
mesh_smooth_type='OFF',
use_mesh_edges=False,
use_tspace=False,
use_custom_props=False,
add_leaf_bones=True,
primary_bone_axis='Y',
secondary_bone_axis='X',
use_armature_deform_only=True,
bake_anim=export_anim,
bake_anim_use_all_bones=True,
bake_anim_use_nla_strips=True,
bake_anim_use_all_actions=False,
bake_anim_step=1.0,
bake_anim_simplify_factor=1.0,
path_mode='AUTO',
embed_textures=False,
batch_mode='OFF',
use_metadata=True
)
#-------------------------------------------------------
# メニューを登録する関数
def menu_func(self, context):
self.layout.operator( ExpSplittedFBXOpe.bl_idname, text="Splitted FBX (.fbx)" )
classes = (
ExpSplittedFBXOpe,
)
# プラグインをインストールしたときの処理
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.TOPBAR_MT_file_export.append(menu_func)
# プラグインをアンインストールしたときの処理
def unregister():
bpy.types.TOPBAR_MT_file_export.remove(menu_func)
for cls in classes:
bpy.utils.unregister_class(cls)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment