1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 "name": "BioVision Motion Capture (BVH) format",
23 "author": "Campbell Barton",
25 "blender": (2, 74, 0),
26 "location": "File > Import-Export",
27 "description": "Import-Export BVH from armature objects",
29 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
30 "Scripts/Import-Export/BVH_Importer_Exporter",
31 "support": 'OFFICIAL',
32 "category": "Import-Export"}
36 if "import_bvh" in locals():
37 importlib
.reload(import_bvh
)
38 if "export_bvh" in locals():
39 importlib
.reload(export_bvh
)
42 from bpy
.props
import (
49 from bpy_extras
.io_utils
import (
57 @orientation_helper(axis_forward
='-Z', axis_up
='Y')
58 class ImportBVH(bpy
.types
.Operator
, ImportHelper
):
59 """Load a BVH motion capture file"""
60 bl_idname
= "import_anim.bvh"
61 bl_label
= "Import BVH"
62 bl_options
= {'REGISTER', 'UNDO'}
65 filter_glob
= StringProperty(default
="*.bvh", options
={'HIDDEN'})
67 target
= EnumProperty(items
=(
68 ('ARMATURE', "Armature", ""),
69 ('OBJECT', "Object", ""),
72 description
="Import target type",
75 global_scale
= FloatProperty(
77 description
="Scale the BVH by this value",
78 min=0.0001, max=1000000.0,
79 soft_min
=0.001, soft_max
=100.0,
82 frame_start
= IntProperty(
84 description
="Starting frame for the animation",
87 use_fps_scale
= BoolProperty(
89 description
=("Scale the framerate from the BVH to the current scenes, "
90 "otherwise each BVH frame maps directly to a Blender frame"),
93 update_scene_fps
= BoolProperty(
94 name
="Update Scene FPS",
95 description
="Set the scene framerate to that of the BVH file (note that this "
96 "nullifies the 'Scale FPS' option, as the scale will be 1:1)",
99 update_scene_duration
= BoolProperty(
100 name
="Update Scene Duration",
101 description
="Extend the scene's duration to the BVH duration (never shortens the scene)",
104 use_cyclic
= BoolProperty(
106 description
="Loop the animation playback",
109 rotate_mode
= EnumProperty(
111 description
="Rotation conversion",
112 items
=(('QUATERNION', "Quaternion",
113 "Convert rotations to quaternions"),
114 ('NATIVE', "Euler (Native)",
115 "Use the rotation order defined in the BVH file"),
116 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
117 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
118 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
119 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
120 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
121 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
126 def execute(self
, context
):
127 keywords
= self
.as_keywords(ignore
=("axis_forward",
132 global_matrix
= axis_conversion(from_forward
=self
.axis_forward
,
133 from_up
=self
.axis_up
,
136 keywords
["global_matrix"] = global_matrix
138 from . import import_bvh
139 return import_bvh
.load(context
, report
=self
.report
, **keywords
)
142 class ExportBVH(bpy
.types
.Operator
, ExportHelper
):
143 """Save a BVH motion capture file from an armature"""
144 bl_idname
= "export_anim.bvh"
145 bl_label
= "Export BVH"
147 filename_ext
= ".bvh"
148 filter_glob
= StringProperty(
153 global_scale
= FloatProperty(
155 description
="Scale the BVH by this value",
156 min=0.0001, max=1000000.0,
157 soft_min
=0.001, soft_max
=100.0,
160 frame_start
= IntProperty(
162 description
="Starting frame to export",
165 frame_end
= IntProperty(
167 description
="End frame to export",
170 rotate_mode
= EnumProperty(
172 description
="Rotation conversion",
173 items
=(('NATIVE', "Euler (Native)",
174 "Use the rotation order defined in the BVH file"),
175 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
176 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
177 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
178 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
179 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
180 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
184 root_transform_only
= BoolProperty(
185 name
="Root Translation Only",
186 description
="Only write out translation channels for the root bone",
191 def poll(cls
, context
):
193 return obj
and obj
.type == 'ARMATURE'
195 def invoke(self
, context
, event
):
196 self
.frame_start
= context
.scene
.frame_start
197 self
.frame_end
= context
.scene
.frame_end
199 return super().invoke(context
, event
)
201 def execute(self
, context
):
202 if self
.frame_start
== 0 and self
.frame_end
== 0:
203 self
.frame_start
= context
.scene
.frame_start
204 self
.frame_end
= context
.scene
.frame_end
206 keywords
= self
.as_keywords(ignore
=("check_existing", "filter_glob"))
208 from . import export_bvh
209 return export_bvh
.save(self
, context
, **keywords
)
212 def menu_func_import(self
, context
):
213 self
.layout
.operator(ImportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
216 def menu_func_export(self
, context
):
217 self
.layout
.operator(ExportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
221 bpy
.utils
.register_module(__name__
)
223 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
224 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
228 bpy
.utils
.unregister_module(__name__
)
230 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)
231 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
233 if __name__
== "__main__":