Created
March 11, 2020 14:07
-
-
Save green224/fe689f5b39081a0d4a8374204f3e9ef0 to your computer and use it in GitHub Desktop.
モデルを、NLAトラックごとに分離して出力するアドオン
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
アニメーションを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