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",
30 "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
31 "Scripts/Import-Export/BVH_Importer_Exporter"
33 "support": 'OFFICIAL',
34 "category": "Import-Export",
39 if "import_bvh" in locals():
40 importlib
.reload(import_bvh
)
41 if "export_bvh" in locals():
42 importlib
.reload(export_bvh
)
45 from bpy
.props
import (
52 from bpy_extras
.io_utils
import (
55 orientation_helper_factory
,
60 ImportBVHOrientationHelper
= orientation_helper_factory("ImportBVHOrientationHelper", axis_forward
='-Z', axis_up
='Y')
63 class ImportBVH(bpy
.types
.Operator
, ImportHelper
, ImportBVHOrientationHelper
):
64 """Load a BVH motion capture file"""
65 bl_idname
= "import_anim.bvh"
66 bl_label
= "Import BVH"
67 bl_options
= {'REGISTER', 'UNDO'}
70 filter_glob
= StringProperty(default
="*.bvh", options
={'HIDDEN'})
72 target
= EnumProperty(
74 ('ARMATURE', "Armature", ""),
75 ('OBJECT', "Object", ""),
78 description
="Import target type",
82 global_scale
= FloatProperty(
84 description
="Scale the BVH by this value",
85 min=0.0001, max=1000000.0,
86 soft_min
=0.001, soft_max
=100.0,
89 frame_start
= IntProperty(
91 description
="Starting frame for the animation",
94 use_fps_scale
= BoolProperty(
97 "Scale the framerate from the BVH to the current scenes, "
98 "otherwise each BVH frame maps directly to a Blender frame"
102 update_scene_fps
= BoolProperty(
103 name
="Update Scene FPS",
105 "Set the scene framerate to that of the BVH file (note that this "
106 "nullifies the 'Scale FPS' option, as the scale will be 1:1)"
110 update_scene_duration
= BoolProperty(
111 name
="Update Scene Duration",
112 description
="Extend the scene's duration to the BVH duration (never shortens the scene)",
115 use_cyclic
= BoolProperty(
117 description
="Loop the animation playback",
120 rotate_mode
= EnumProperty(
122 description
="Rotation conversion",
124 ('QUATERNION', "Quaternion",
125 "Convert rotations to quaternions"),
126 ('NATIVE', "Euler (Native)",
127 "Use the rotation order defined in the BVH file"),
128 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
129 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
130 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
131 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
132 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
133 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
138 def execute(self
, context
):
139 keywords
= self
.as_keywords(
147 global_matrix
= axis_conversion(
148 from_forward
=self
.axis_forward
,
149 from_up
=self
.axis_up
,
152 keywords
["global_matrix"] = global_matrix
154 from . import import_bvh
155 return import_bvh
.load(context
, report
=self
.report
, **keywords
)
158 class ExportBVH(bpy
.types
.Operator
, ExportHelper
):
159 """Save a BVH motion capture file from an armature"""
160 bl_idname
= "export_anim.bvh"
161 bl_label
= "Export BVH"
163 filename_ext
= ".bvh"
164 filter_glob
= StringProperty(
169 global_scale
= FloatProperty(
171 description
="Scale the BVH by this value",
172 min=0.0001, max=1000000.0,
173 soft_min
=0.001, soft_max
=100.0,
176 frame_start
= IntProperty(
178 description
="Starting frame to export",
181 frame_end
= IntProperty(
183 description
="End frame to export",
186 rotate_mode
= EnumProperty(
188 description
="Rotation conversion",
190 ('NATIVE', "Euler (Native)",
191 "Use the rotation order defined in the BVH file"),
192 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
193 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
194 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
195 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
196 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
197 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
201 root_transform_only
= BoolProperty(
202 name
="Root Translation Only",
203 description
="Only write out translation channels for the root bone",
208 def poll(cls
, context
):
210 return obj
and obj
.type == 'ARMATURE'
212 def invoke(self
, context
, event
):
213 self
.frame_start
= context
.scene
.frame_start
214 self
.frame_end
= context
.scene
.frame_end
216 return super().invoke(context
, event
)
218 def execute(self
, context
):
219 if self
.frame_start
== 0 and self
.frame_end
== 0:
220 self
.frame_start
= context
.scene
.frame_start
221 self
.frame_end
= context
.scene
.frame_end
223 keywords
= self
.as_keywords(ignore
=("check_existing", "filter_glob"))
225 from . import export_bvh
226 return export_bvh
.save(context
, **keywords
)
229 def menu_func_import(self
, context
):
230 self
.layout
.operator(ImportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
233 def menu_func_export(self
, context
):
234 self
.layout
.operator(ExportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
238 bpy
.utils
.register_module(__name__
)
240 bpy
.types
.INFO_MT_file_import
.append(menu_func_import
)
241 bpy
.types
.INFO_MT_file_export
.append(menu_func_export
)
245 bpy
.utils
.unregister_module(__name__
)
247 bpy
.types
.INFO_MT_file_import
.remove(menu_func_import
)
248 bpy
.types
.INFO_MT_file_export
.remove(menu_func_export
)
251 if __name__
== "__main__":