bvh export

- write compatible eulers (no jumping as eulers change).
- write FPS.
- correct poll function incase bvh export is called without an armature.
This commit is contained in:
Campbell Barton 2011-01-01 10:38:28 +00:00
parent f932371d1e
commit e1f6dc5f73
2 changed files with 39 additions and 28 deletions

@ -69,8 +69,13 @@ class BvhExporter(bpy.types.Operator, ExportHelper):
filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
global_scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=1.0)
frame_start = IntProperty(name="Start Frame", description="Starting frame to export")
frame_end = IntProperty(name="End Frame", description="End frame to export")
frame_start = IntProperty(name="Start Frame", description="Starting frame to export", default=0)
frame_end = IntProperty(name="End Frame", description="End frame to export", default=0)
@classmethod
def poll(cls, context):
obj = context.object
return obj and obj.type == 'ARMATURE'
def invoke(self, context, event):
self.frame_start = context.scene.frame_start
@ -79,7 +84,13 @@ class BvhExporter(bpy.types.Operator, ExportHelper):
return super().invoke(context, event)
def execute(self, context):
if self.frame_start == 0 and self.frame_end == 0:
self.frame_start = context.scene.frame_start
self.frame_end = context.scene.frame_end
from . import export_bvh
import imp
imp.reload(export_bvh)
return export_bvh.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob")))

@ -25,7 +25,7 @@ import bpy
def _read(context, filepath, frame_start, frame_end, global_scale=1.0):
from mathutils import Matrix, Vector
from mathutils import Matrix, Vector, Euler
from math import degrees
file = open(filepath, "w")
@ -130,8 +130,9 @@ def _read(context, filepath, frame_start, frame_end, global_scale=1.0):
"rest_local_mat", # blender rest batrix (local space)
"pose_imat", # pose_mat inverted
"rest_arm_imat", # rest_arm_mat inverted
"rest_local_imat") # rest_local_mat inverted
"rest_local_imat", # rest_local_mat inverted
"prev_euler", # last used euler to preserve euler compability inbetween keyframes
)
def __init__(self, bone_name):
self.name = bone_name
self.rest_bone = arm.bones[bone_name]
@ -149,6 +150,7 @@ def _read(context, filepath, frame_start, frame_end, global_scale=1.0):
self.rest_local_imat = self.rest_local_mat.copy().invert()
self.parent = None
self.prev_euler = Euler((0.0, 0.0, 0.0))
def update_posedata(self):
self.pose_mat = self.pose_bone.matrix
@ -174,40 +176,38 @@ def _read(context, filepath, frame_start, frame_end, global_scale=1.0):
del bones_decorated_dict
# finish assigning parents
file.write("MOTION\n")
file.write("Frames: %d\n" % (frame_end - frame_start + 1))
file.write("Frame Time: %.6f\n" % 0.03)
scene = bpy.context.scene
triple = "%.6f %.6f %.6f "
file.write("MOTION\n")
file.write("Frames: %d\n" % (frame_end - frame_start + 1))
file.write("Frame Time: %.6f\n" % (1.0 / (scene.render.fps / scene.render.fps_base)))
for frame in range(frame_start, frame_end + 1):
scene.frame_set(frame)
obj.update(scene, 1,1,1)
scene.update()
for dbone in bones_decorated:
dbone.update_posedata()
for dbone in bones_decorated:
trans = Matrix.Translation(dbone.rest_bone.head_local)
itrans = Matrix.Translation(-dbone.rest_bone.head_local)
if dbone.parent:
trans = Matrix.Translation(dbone.rest_bone.head_local)
itrans = Matrix.Translation(-dbone.rest_bone.head_local)
mat2 = dbone.parent.rest_arm_mat * dbone.parent.pose_imat * dbone.pose_mat * dbone.rest_arm_imat
mat2 = itrans * mat2 * trans
myloc = mat2.translation_part() + (dbone.rest_bone.head_local - dbone.parent.rest_bone.head_local)
rot = mat2.copy().transpose().to_euler()
mat_final = dbone.parent.rest_arm_mat * dbone.parent.pose_imat * dbone.pose_mat * dbone.rest_arm_imat
mat_final = itrans * mat_final * trans
loc = mat_final.translation_part() + (dbone.rest_bone.head_local - dbone.parent.rest_bone.head_local)
else:
trans = Matrix.Translation(dbone.rest_bone.head_local)
itrans = Matrix.Translation(-dbone.rest_bone.head_local)
mat_final = dbone.pose_mat * dbone.rest_arm_imat
mat_final = itrans * mat_final * trans
loc = mat_final.translation_part() + dbone.rest_bone.head
mat2 = dbone.pose_mat * dbone.rest_arm_imat
mat2 = itrans * mat2 * trans
myloc = mat2.translation_part() + dbone.rest_bone.head_local
rot = mat2.copy().transpose().to_euler()
# keep eulers compatible, no jumping on interpolation.
rot = mat_final.rotation_part().invert().to_euler('XYZ', dbone.prev_euler)
file.write(triple % (myloc[0] * global_scale, myloc[1] * global_scale, myloc[2] * global_scale))
file.write(triple % (-degrees(rot[0]), -degrees(rot[1]), -degrees(rot[2])))
file.write("%.6f %.6f %.6f " % (loc * global_scale)[:])
file.write("%.6f %.6f %.6f " % (-degrees(rot[0]), -degrees(rot[1]), -degrees(rot[2])))
dbone.prev_euler = rot
file.write("\n")