Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2012-03-12 20:04:00 +0400
committerCampbell Barton <ideasman42@gmail.com>2012-03-12 20:04:00 +0400
commit25b31e5b7d911d57996042a10f9e3cf645d07b93 (patch)
tree6c2db98105ac772abec1df0e60931185a3a95760 /io_anim_bvh
parentba4b4635e7646999a02ea2e837a9371d379508f5 (diff)
maintain order from import to export (secondlife expects bone order to be maintained).
also use less confusing bone rotation matrix -> euler conversion on export.
Diffstat (limited to 'io_anim_bvh')
-rw-r--r--io_anim_bvh/export_bvh.py16
-rw-r--r--io_anim_bvh/import_bvh.py68
2 files changed, 49 insertions, 35 deletions
diff --git a/io_anim_bvh/export_bvh.py b/io_anim_bvh/export_bvh.py
index 977c36f5..fcddb63c 100644
--- a/io_anim_bvh/export_bvh.py
+++ b/io_anim_bvh/export_bvh.py
@@ -54,13 +54,11 @@ def write_armature(context,
for bone in arm.bones:
children[bone.name] = []
+ # keep bone order from armature, no sorting, not esspential but means
+ # we can maintain order from import -> export which secondlife incorrectly expects.
for bone in arm.bones:
children[getattr(bone.parent, "name", None)].append(bone.name)
- # sort the children
- for children_list in children.values():
- children_list.sort()
-
# bone name list in the order that the bones are written
serialized_names = []
@@ -157,7 +155,8 @@ def write_armature(context,
"skip_position", # is the bone disconnected to the parent bone?
"rot_order",
"rot_order_str",
- )
+ "rot_order_str_reverse", # needed for the euler order when converting from a matrix
+ )
_eul_order_lookup = {
'XYZ': (0, 1, 2),
@@ -177,6 +176,7 @@ def write_armature(context,
self.rot_order_str = ensure_rot_order(self.pose_bone.rotation_mode)
else:
self.rot_order_str = rotate_mode
+ self.rot_order_str_reverse = self.rot_order_str[::-1]
self.rot_order = DecoratedBone._eul_order_lookup[self.rot_order_str]
@@ -192,7 +192,7 @@ def write_armature(context,
self.rest_local_imat = self.rest_local_mat.inverted()
self.parent = None
- self.prev_euler = Euler((0.0, 0.0, 0.0), self.rot_order_str)
+ self.prev_euler = Euler((0.0, 0.0, 0.0), self.rot_order_str_reverse)
self.skip_position = ((self.rest_bone.use_connect or root_transform_only) and self.rest_bone.parent)
def update_posedata(self):
@@ -246,12 +246,12 @@ def write_armature(context,
loc = mat_final.to_translation() + dbone.rest_bone.head
# keep eulers compatible, no jumping on interpolation.
- rot = mat_final.to_3x3().inverted().to_euler(dbone.rot_order_str, dbone.prev_euler)
+ rot = mat_final.to_euler(dbone.rot_order_str_reverse, dbone.prev_euler)
if not dbone.skip_position:
file.write("%.6f %.6f %.6f " % (loc * global_scale)[:])
- file.write("%.6f %.6f %.6f " % (-degrees(rot[dbone.rot_order[0]]), -degrees(rot[dbone.rot_order[1]]), -degrees(rot[dbone.rot_order[2]])))
+ file.write("%.6f %.6f %.6f " % (degrees(rot[dbone.rot_order[0]]), degrees(rot[dbone.rot_order[1]]), degrees(rot[dbone.rot_order[2]])))
dbone.prev_euler = rot
diff --git a/io_anim_bvh/import_bvh.py b/io_anim_bvh/import_bvh.py
index 0022cc8c..110ee83e 100644
--- a/io_anim_bvh/import_bvh.py
+++ b/io_anim_bvh/import_bvh.py
@@ -28,20 +28,22 @@ from mathutils import Vector, Euler, Matrix
class BVH_Node(object):
__slots__ = (
- 'name', # bvh joint name
- 'parent', # BVH_Node type or None for no parent
- 'children', # a list of children of this type.
- 'rest_head_world', # worldspace rest location for the head of this node
- 'rest_head_local', # localspace rest location for the head of this node
- 'rest_tail_world', # worldspace rest location for the tail of this node
- 'rest_tail_local', # worldspace rest location for the tail of this node
- 'channels', # list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
- 'rot_order', # a triple of indices as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
- 'rot_order_str', # same as above but a string 'XYZ' format.
- 'anim_data', # a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz), euler rotation ALWAYS stored xyz order, even when native used.
- 'has_loc', # Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
- 'has_rot', # Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
- 'temp') # use this for whatever you want
+ 'name', # bvh joint name
+ 'parent', # BVH_Node type or None for no parent
+ 'children', # a list of children of this type.
+ 'rest_head_world', # worldspace rest location for the head of this node
+ 'rest_head_local', # localspace rest location for the head of this node
+ 'rest_tail_world', # worldspace rest location for the tail of this node
+ 'rest_tail_local', # worldspace rest location for the tail of this node
+ 'channels', # list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
+ 'rot_order', # a triple of indices as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
+ 'rot_order_str', # same as above but a string 'XYZ' format.
+ 'anim_data', # a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz), euler rotation ALWAYS stored xyz order, even when native used.
+ 'has_loc', # Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
+ 'has_rot', # Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
+ 'index', # index from the file, not strictly needed but nice to maintain order
+ 'temp', # use this for whatever you want
+ )
_eul_order_lookup = {(0, 1, 2): 'XYZ',
(0, 2, 1): 'XZY',
@@ -51,7 +53,7 @@ class BVH_Node(object):
(2, 1, 0): 'ZYX',
}
- def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order):
+ def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order, index):
self.name = name
self.rest_head_world = rest_head_world
self.rest_head_local = rest_head_local
@@ -61,6 +63,7 @@ class BVH_Node(object):
self.channels = channels
self.rot_order = tuple(rot_order)
self.rot_order_str = BVH_Node._eul_order_lookup[self.rot_order]
+ self.index = index
# convenience functions
self.has_loc = channels[0] != -1 or channels[1] != -1 or channels[2] != -1
@@ -80,6 +83,12 @@ class BVH_Node(object):
self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)
+def sorted_nodes(bvh_nodes):
+ bvh_nodes_list = list(bvh_nodes.values())
+ bvh_nodes_list.sort(key=lambda bvh_node: bvh_node.index)
+ return bvh_nodes_list
+
+
def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0):
# File loading stuff
# Open the file for importing
@@ -167,7 +176,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0):
else:
rest_head_world = my_parent.rest_head_world + rest_head_local
- bvh_node = bvh_nodes[name] = BVH_Node(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order)
+ bvh_node = bvh_nodes[name] = BVH_Node(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order, len(bvh_nodes) - 1)
# If we have another child then we can call ourselves a parent, else
bvh_nodes_serial.append(bvh_node)
@@ -199,7 +208,9 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0):
# Dont use anymore
del bvh_nodes_serial
- bvh_nodes_list = bvh_nodes.values()
+ # importing world with any order but nicer to maintain order
+ # second life expects it, which isnt to spec.
+ bvh_nodes_list = sorted_nodes(bvh_nodes)
while lineIdx < len(file_lines):
line = file_lines[lineIdx]
@@ -228,13 +239,13 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0):
lineIdx += 1
# Assign children
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
bvh_node_parent = bvh_node.parent
if bvh_node_parent:
bvh_node_parent.children.append(bvh_node)
# Now set the tip of each bvh_node
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
if not bvh_node.rest_tail_world:
if len(bvh_node.children) == 0:
@@ -359,10 +370,12 @@ def bvh_node_dict2armature(context,
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+ bvh_nodes_list = sorted_nodes(bvh_nodes)
+
# Get the average bone length for zero length bones, we may not use this.
average_bone_length = 0.0
nonzero_count = 0
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length
if l:
average_bone_length += l
@@ -380,9 +393,10 @@ def bvh_node_dict2armature(context,
arm_ob.edit_bones.remove(arm_data.edit_bones[-1])
ZERO_AREA_BONES = []
- for name, bvh_node in bvh_nodes.items():
+ for bvh_node in bvh_nodes_list:
+
# New editbone
- bone = bvh_node.temp = arm_data.edit_bones.new(name)
+ bone = bvh_node.temp = arm_data.edit_bones.new(bvh_node.name)
bone.head = bvh_node.rest_head_world
bone.tail = bvh_node.rest_tail_world
@@ -401,7 +415,7 @@ def bvh_node_dict2armature(context,
ZERO_AREA_BONES.append(bone.name)
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
if bvh_node.parent:
# bvh_node.temp is the Editbone
@@ -417,7 +431,7 @@ def bvh_node_dict2armature(context,
# Replace the editbone with the editbone name,
# to avoid memory errors accessing the editbone outside editmode
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
bvh_node.temp = bvh_node.temp.name
# Now Apply the animation to the armature
@@ -429,7 +443,7 @@ def bvh_node_dict2armature(context,
pose_bones = pose.bones
if rotate_mode == 'NATIVE':
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
pose_bone = pose_bones[bone_name]
pose_bone.rotation_mode = bvh_node.rot_order_str
@@ -449,7 +463,7 @@ def bvh_node_dict2armature(context,
# Replace the bvh_node.temp (currently an editbone)
# With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv)
- for bvh_node in bvh_nodes.values():
+ for bvh_node in bvh_nodes_list:
bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
pose_bone = pose_bones[bone_name]
rest_bone = arm_data.bones[bone_name]
@@ -479,7 +493,7 @@ def bvh_node_dict2armature(context,
scene.frame_set(frame_start + frame_current)
# Dont neet to set the current frame
- for i, bvh_node in enumerate(bvh_nodes.values()):
+ for i, bvh_node in enumerate(bvh_nodes_list):
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp
lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current + 1]