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",
24 "blender": (2, 74, 0),
25 "location": "File > Import-Export",
26 "description": "Import-Export BVH from armature objects",
28 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
29 "Scripts/Import-Export/BVH_Importer_Exporter",
30 "support": 'OFFICIAL',
31 "category": "Import-Export"}
35 if "import_bvh" in locals():
36 importlib
.reload(import_bvh
)
37 if "export_bvh" in locals():
38 importlib
.reload(export_bvh
)
41 from bpy
.props
import (
48 from bpy_extras
.io_utils
import (
51 orientation_helper_factory
,
56 ImportBVHOrientationHelper
= orientation_helper_factory("ImportBVHOrientationHelper", axis_forward
='-Z', axis_up
='Y')
59 class ImportBVH(bpy
.types
.Operator
, ImportHelper
, ImportBVHOrientationHelper
):
60 """Load a BVH motion capture file"""
61 bl_idname
= "import_anim.bvh"
62 bl_label
= "Import BVH"
63 bl_options
= {'REGISTER', 'UNDO'}
66 filter_glob
= StringProperty(default
="*.bvh", options
={'HIDDEN'})
68 target
= EnumProperty(items
=(
69 ('ARMATURE', "Armature", ""),
70 ('OBJECT', "Object", ""),
73 description
="Import target type",
76 global_scale
= FloatProperty(
78 description
="Scale the BVH by this value",
79 min=0.0001, max=1000000.0,
80 soft_min
=0.001, soft_max
=100.0,
83 frame_start
= IntProperty(
85 description
="Starting frame for the animation",
88 use_fps_scale
= BoolProperty(
90 description
=("Scale the framerate from the BVH to the current scenes, "
91 "otherwise each BVH frame maps directly to a Blender frame"),
94 update_scene_fps
= BoolProperty(
95 name
="Update Scene FPS",
96 description
="Set the scene framerate to that of the BVH file (note that this "
97 "nullifies the 'Scale FPS' option, as the scale will be 1:1)",
100 update_scene_duration
= BoolProperty(
101 name
="Update Scene Duration",
102 description
="Extend the scene's duration to the BVH duration (never shortens the scene)",
105 use_cyclic
= BoolProperty(
107 description
="Loop the animation playback",
110 rotate_mode
= EnumProperty(
112 description
="Rotation conversion",
113 items
=(('QUATERNION', "Quaternion",
114 "Convert rotations to quaternions"),
115 ('NATIVE', "Euler (Native)",
116 "Use the rotation order defined in the BVH file"),
117 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
118 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
119 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
120 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
121 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
122 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
127 def execute(self
, context
):
128 keywords
= self
.as_keywords(ignore
=("axis_forward",
133 global_matrix
= axis_conversion(from_forward
=self
.axis_forward
,
134 from_up
=self
.axis_up
,
137 keywords
["global_matrix"] = global_matrix
139 from . import import_bvh
140 return import_bvh
.load(context
, report
=self
.report
, **keywords
)
143 class ExportBVH(bpy
.types
.Operator
, ExportHelper
):
144 """Save a BVH motion capture file from an armature"""
145 bl_idname
= "export_anim.bvh"
146 bl_label
= "Export BVH"
148 filename_ext
= ".bvh"
149 filter_glob
= StringProperty(
154 global_scale
= FloatProperty(
156 description
="Scale the BVH by this value",
157 min=0.0001, max=1000000.0,
158 soft_min
=0.001, soft_max
=100.0,
161 frame_start
= IntProperty(
163 description
="Starting frame to export",
166 frame_end
= IntProperty(
168 description
="End frame to export",
171 rotate_mode
= EnumProperty(
173 description
="Rotation conversion",
174 items
=(('NATIVE', "Euler (Native)",
175 "Use the rotation order defined in the BVH file"),
176 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
177 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
178 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
179 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
180 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
181 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
185 root_transform_only
= BoolProperty(
186 name
="Root Translation Only",
187 description
="Only write out translation channels for the root bone",
192 def poll(cls
, context
):
194 return obj
and obj
.type == 'ARMATURE'
196 def invoke(self
, context
, event
):
197 self
.frame_start
= context
.scene
.frame_start
198 self
.frame_end
= context
.scene
.frame_end
200 return super().invoke(context
, event
)
202 def execute(self
, context
):
203 if self
.frame_start
== 0 and self
.frame_end
== 0:
204 self
.frame_start
= context
.scene
.frame_start
205 self
.frame_end
= context
.scene
.frame_end
207 keywords
= self
.as_keywords(ignore
=("check_existing", "filter_glob"))
209 from . import export_bvh
210 return export_bvh
.save(self
, context
, **keywords
)
213 def menu_func_import(self
, context
):
214 self
.layout
.operator(ImportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
217 def menu_func_export(self
, context
):
218 self
.layout
.operator(ExportBVH
.bl_idname
, text
="Motion Capture (.bvh)")
222 bpy
.utils
.register_module(__name__
)
224 bpy
.types
.INFO_MT_file_import
.append(menu_func_import
)
225 bpy
.types
.INFO_MT_file_export
.append(menu_func_export
)
229 bpy
.utils
.unregister_module(__name__
)
231 bpy
.types
.INFO_MT_file_import
.remove(menu_func_import
)
232 bpy
.types
.INFO_MT_file_export
.remove(menu_func_export
)
234 if __name__
== "__main__":