From f5fd80872aa8edb8f8217819f0c06cc7c974650c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 6 Oct 2018 12:39:20 +1000 Subject: [PATCH] Cleanup: BVH import/export - Use tuple unpacking. - Remove unused operator argument. --- io_anim_bvh/__init__.py | 224 +++++++++++++++++++++++--------------------- io_anim_bvh/export_bvh.py | 105 +++++++++++---------- io_anim_bvh/import_bvh.py | 231 +++++++++++++++++++++++++++------------------- 3 files changed, 312 insertions(+), 248 deletions(-) diff --git a/io_anim_bvh/__init__.py b/io_anim_bvh/__init__.py index 8a63fbbc..4a4983ff 100644 --- a/io_anim_bvh/__init__.py +++ b/io_anim_bvh/__init__.py @@ -26,10 +26,13 @@ bl_info = { "location": "File > Import-Export", "description": "Import-Export BVH from armature objects", "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/" - "Scripts/Import-Export/BVH_Importer_Exporter", + "wiki_url": ( + "http://wiki.blender.org/index.php/Extensions:2.6/Py/" + "Scripts/Import-Export/BVH_Importer_Exporter" + ), "support": 'OFFICIAL', - "category": "Import-Export"} + "category": "Import-Export", +} if "bpy" in locals(): import importlib @@ -40,18 +43,18 @@ if "bpy" in locals(): import bpy from bpy.props import ( - StringProperty, - FloatProperty, - IntProperty, - BoolProperty, - EnumProperty, - ) + StringProperty, + FloatProperty, + IntProperty, + BoolProperty, + EnumProperty, +) from bpy_extras.io_utils import ( - ImportHelper, - ExportHelper, - orientation_helper_factory, - axis_conversion, - ) + ImportHelper, + ExportHelper, + orientation_helper_factory, + axis_conversion, +) ImportBVHOrientationHelper = orientation_helper_factory("ImportBVHOrientationHelper", axis_forward='-Z', axis_up='Y') @@ -66,74 +69,85 @@ class ImportBVH(bpy.types.Operator, ImportHelper, ImportBVHOrientationHelper): filename_ext = ".bvh" filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'}) - target = EnumProperty(items=( + target = EnumProperty( + items=( ('ARMATURE', "Armature", ""), ('OBJECT', "Object", ""), - ), - name="Target", - description="Import target type", - default='ARMATURE') + ), + name="Target", + description="Import target type", + default='ARMATURE', + ) 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, - ) + 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 for the animation", - default=1, - ) + name="Start Frame", + description="Starting frame for the animation", + default=1, + ) use_fps_scale = BoolProperty( - name="Scale FPS", - description=("Scale the framerate from the BVH to the current scenes, " - "otherwise each BVH frame maps directly to a Blender frame"), - default=False, - ) + name="Scale FPS", + description=( + "Scale the framerate from the BVH to the current scenes, " + "otherwise each BVH frame maps directly to a Blender frame" + ), + default=False, + ) update_scene_fps = BoolProperty( - name="Update Scene FPS", - description="Set the scene framerate to that of the BVH file (note that this " - "nullifies the 'Scale FPS' option, as the scale will be 1:1)", - default=False - ) + name="Update Scene FPS", + description=( + "Set the scene framerate to that of the BVH file (note that this " + "nullifies the 'Scale FPS' option, as the scale will be 1:1)" + ), + default=False + ) update_scene_duration = BoolProperty( - name="Update Scene Duration", - description="Extend the scene's duration to the BVH duration (never shortens the scene)", - default=False, - ) + name="Update Scene Duration", + description="Extend the scene's duration to the BVH duration (never shortens the scene)", + default=False, + ) use_cyclic = BoolProperty( - name="Loop", - description="Loop the animation playback", - default=False, - ) + name="Loop", + description="Loop the animation playback", + default=False, + ) rotate_mode = EnumProperty( - name="Rotation", - description="Rotation conversion", - items=(('QUATERNION', "Quaternion", - "Convert rotations to quaternions"), - ('NATIVE', "Euler (Native)", - "Use the rotation order defined in the BVH file"), - ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"), - ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"), - ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"), - ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"), - ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"), - ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"), - ), - default='NATIVE', - ) + name="Rotation", + description="Rotation conversion", + items=( + ('QUATERNION', "Quaternion", + "Convert rotations to quaternions"), + ('NATIVE', "Euler (Native)", + "Use the rotation order defined in the BVH file"), + ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"), + ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"), + ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"), + ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"), + ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"), + ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"), + ), + default='NATIVE', + ) def execute(self, context): - keywords = self.as_keywords(ignore=("axis_forward", - "axis_up", - "filter_glob", - )) + keywords = self.as_keywords( + ignore=( + "axis_forward", + "axis_up", + "filter_glob", + ) + ) - global_matrix = axis_conversion(from_forward=self.axis_forward, - from_up=self.axis_up, - ).to_4x4() + global_matrix = axis_conversion( + from_forward=self.axis_forward, + from_up=self.axis_up, + ).to_4x4() keywords["global_matrix"] = global_matrix @@ -148,46 +162,47 @@ class ExportBVH(bpy.types.Operator, ExportHelper): filename_ext = ".bvh" filter_glob = StringProperty( - default="*.bvh", - options={'HIDDEN'}, - ) + 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, - ) + 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", - default=0, - ) + name="Start Frame", + description="Starting frame to export", + default=0, + ) frame_end = IntProperty( - name="End Frame", - description="End frame to export", - default=0, - ) + name="End Frame", + description="End frame to export", + default=0, + ) rotate_mode = EnumProperty( - name="Rotation", - description="Rotation conversion", - items=(('NATIVE', "Euler (Native)", - "Use the rotation order defined in the BVH file"), - ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"), - ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"), - ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"), - ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"), - ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"), - ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"), - ), - default='NATIVE', - ) + name="Rotation", + description="Rotation conversion", + items=( + ('NATIVE', "Euler (Native)", + "Use the rotation order defined in the BVH file"), + ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"), + ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"), + ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"), + ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"), + ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"), + ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"), + ), + default='NATIVE', + ) root_transform_only = BoolProperty( - name="Root Translation Only", - description="Only write out translation channels for the root bone", - default=False, - ) + name="Root Translation Only", + description="Only write out translation channels for the root bone", + default=False, + ) @classmethod def poll(cls, context): @@ -208,7 +223,7 @@ class ExportBVH(bpy.types.Operator, ExportHelper): keywords = self.as_keywords(ignore=("check_existing", "filter_glob")) from . import export_bvh - return export_bvh.save(self, context, **keywords) + return export_bvh.save(context, **keywords) def menu_func_import(self, context): @@ -232,5 +247,6 @@ def unregister(): bpy.types.INFO_MT_file_import.remove(menu_func_import) bpy.types.INFO_MT_file_export.remove(menu_func_export) + if __name__ == "__main__": register() diff --git a/io_anim_bvh/export_bvh.py b/io_anim_bvh/export_bvh.py index ed80ed59..21225581 100644 --- a/io_anim_bvh/export_bvh.py +++ b/io_anim_bvh/export_bvh.py @@ -24,14 +24,15 @@ import bpy -def write_armature(context, - filepath, - frame_start, - frame_end, - global_scale=1.0, - rotate_mode='NATIVE', - root_transform_only=False, - ): +def write_armature( + context, + filepath, + frame_start, + frame_end, + global_scale=1.0, + rotate_mode='NATIVE', + root_transform_only=False, +): def ensure_rot_order(rot_order_str): if set(rot_order_str) != {'X', 'Y', 'Z'}: @@ -91,11 +92,11 @@ def write_armature(context, file.write("%sROOT %s\n" % (indent_str, bone_name)) file.write("%s{\n" % indent_str) - file.write("%s\tOFFSET %.6f %.6f %.6f\n" % (indent_str, loc.x * global_scale, loc.y * global_scale, loc.z * global_scale)) + file.write("%s\tOFFSET %.6f %.6f %.6f\n" % (indent_str, *(loc * global_scale))) if (bone.use_connect or root_transform_only) and bone.parent: - file.write("%s\tCHANNELS 3 %srotation %srotation %srotation\n" % (indent_str, rot_order_str[0], rot_order_str[1], rot_order_str[2])) + file.write("%s\tCHANNELS 3 %srotation %srotation %srotation\n" % (indent_str, *rot_order_str)) else: - file.write("%s\tCHANNELS 6 Xposition Yposition Zposition %srotation %srotation %srotation\n" % (indent_str, rot_order_str[0], rot_order_str[1], rot_order_str[2])) + file.write("%s\tCHANNELS 6 Xposition Yposition Zposition %srotation %srotation %srotation\n" % (indent_str, *rot_order_str)) if my_children: # store the location for the children @@ -111,7 +112,7 @@ def write_armature(context, file.write("%s\tEnd Site\n" % indent_str) file.write("%s\t{\n" % indent_str) loc = bone.tail_local - node_locations[bone_name] - file.write("%s\t\tOFFSET %.6f %.6f %.6f\n" % (indent_str, loc.x * global_scale, loc.y * global_scale, loc.z * global_scale)) + file.write("%s\t\tOFFSET %.6f %.6f %.6f\n" % (indent_str, *(loc * global_scale))) file.write("%s\t}\n" % indent_str) file.write("%s}\n" % indent_str) @@ -149,22 +150,34 @@ def write_armature(context, class DecoratedBone: __slots__ = ( - "name", # bone name, used as key in many places + # Bone name, used as key in many places. + "name", "parent", # decorated bone parent, set in a later loop - "rest_bone", # blender armature bone - "pose_bone", # blender pose bone - "pose_mat", # blender pose matrix - "rest_arm_mat", # blender rest matrix (armature space) - "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 - "prev_euler", # last used euler to preserve euler compability in between keyframes - "skip_position", # is the bone disconnected to the parent bone? + # Blender armature bone. + "rest_bone", + # Blender pose bone. + "pose_bone", + # Blender pose matrix. + "pose_mat", + # Blender rest matrix (armature space). + "rest_arm_mat", + # Blender rest batrix (local space). + "rest_local_mat", + # Pose_mat inverted. + "pose_imat", + # Rest_arm_mat inverted. + "rest_arm_imat", + # Rest_local_mat inverted. + "rest_local_imat", + # Last used euler to preserve euler compability in between keyframes. + "prev_euler", + # Is the bone disconnected to the parent bone? + "skip_position", "rot_order", "rot_order_str", - "rot_order_str_reverse", # needed for the euler order when converting from a matrix - ) + # Needed for the euler order when converting from a matrix. + "rot_order_str_reverse", + ) _eul_order_lookup = { 'XYZ': (0, 1, 2), @@ -173,7 +186,7 @@ def write_armature(context, 'YZX': (1, 2, 0), 'ZXY': (2, 0, 1), 'ZYX': (2, 1, 0), - } + } def __init__(self, bone_name): self.name = bone_name @@ -216,10 +229,7 @@ def write_armature(context, bones_decorated = [DecoratedBone(bone_name) for bone_name in serialized_names] # Assign parents - bones_decorated_dict = {} - for dbone in bones_decorated: - bones_decorated_dict[dbone.name] = dbone - + bones_decorated_dict = {dbone.name: dbone for dbone in bones_decorated} for dbone in bones_decorated: parent = dbone.rest_bone.parent if parent: @@ -227,7 +237,7 @@ def write_armature(context, del bones_decorated_dict # finish assigning parents - scene = bpy.context.scene + scene = context.scene frame_current = scene.frame_current file.write("MOTION\n") @@ -244,7 +254,7 @@ def write_armature(context, trans = Matrix.Translation(dbone.rest_bone.head_local) itrans = Matrix.Translation(-dbone.rest_bone.head_local) - if dbone.parent: + if dbone.parent: 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.to_translation() + (dbone.rest_bone.head_local - dbone.parent.rest_bone.head_local) @@ -272,20 +282,21 @@ def write_armature(context, print("BVH Exported: %s frames:%d\n" % (filepath, frame_end - frame_start + 1)) -def save(operator, context, filepath="", - frame_start=-1, - frame_end=-1, - global_scale=1.0, - rotate_mode="NATIVE", - root_transform_only=False, - ): - - write_armature(context, filepath, - frame_start=frame_start, - frame_end=frame_end, - global_scale=global_scale, - rotate_mode=rotate_mode, - root_transform_only=root_transform_only, - ) +def save( + context, filepath="", + frame_start=-1, + frame_end=-1, + global_scale=1.0, + rotate_mode="NATIVE", + root_transform_only=False, +): + write_armature( + context, filepath, + frame_start=frame_start, + frame_end=frame_end, + global_scale=global_scale, + rotate_mode=rotate_mode, + root_transform_only=root_transform_only, + ) return {'FINISHED'} diff --git a/io_anim_bvh/import_bvh.py b/io_anim_bvh/import_bvh.py index df733a73..a12ef0cc 100644 --- a/io_anim_bvh/import_bvh.py +++ b/io_anim_bvh/import_bvh.py @@ -28,22 +28,41 @@ from mathutils import Vector, Euler, Matrix class BVH_Node: __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, loc 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', # Convenience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 or channels[2]!=-1) - 'has_rot', # Convenience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 or channels[5]!=-1) - 'index', # index from the file, not strictly needed but nice to maintain order - 'temp', # use this for whatever you want - ) + # Bvh joint name. + 'name', + # BVH_Node type or None for no parent. + 'parent', + # A list of children of this type.. + 'children', + # Worldspace rest location for the head of this node. + 'rest_head_world', + # Localspace rest location for the head of this node. + 'rest_head_local', + # Worldspace rest location for the tail of this node. + 'rest_tail_world', + # Worldspace rest location for the tail of this node. + 'rest_tail_local', + # List of 6 ints, -1 for an unused channel, + # otherwise an index for the BVH motion data lines, + # loc triple then rot triple. + 'channels', + # 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', + # Same as above but a string 'XYZ' format.. + 'rot_order_str', + # 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. + 'anim_data', + # Convenience function, bool, same as: (channels[0] != -1 or channels[1] != -1 or channels[2] != -1). + 'has_loc', + # Convenience function, bool, same as: (channels[3] != -1 or channels[4] != -1 or channels[5] != -1). + 'has_rot', + # Index from the file, not strictly needed but nice to maintain order. + 'index', + # Use this for whatever you want. + 'temp', + ) _eul_order_lookup = { (None, None, None): 'XYZ', # XXX Dummy one, no rotation anyway! @@ -53,7 +72,7 @@ class BVH_Node: (1, 2, 0): 'YZX', (2, 0, 1): 'ZXY', (2, 1, 0): 'ZYX', - } + } def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order, index): self.name = name @@ -73,16 +92,18 @@ class BVH_Node: self.children = [] - # list of 6 length tuples: (lx,ly,lz, rx,ry,rz) - # even if the channels aren't used they will just be zero - # + # List of 6 length tuples: (lx, ly, lz, rx, ry, rz) + # even if the channels aren't used they will just be zero. self.anim_data = [(0, 0, 0, 0, 0, 0)] def __repr__(self): - return ("BVH name: '%s', rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)" % - (self.name, - self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z, - self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)) + return ( + "BVH name: '%s', rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)" % ( + self.name, + *self.rest_head_world, + *self.rest_head_world, + ) + ) def sorted_nodes(bvh_nodes): @@ -107,7 +128,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): # Create hierarchy as empties if file_lines[0][0].lower() == 'hierarchy': - #print 'Importing the BVH Hierarchy for:', file_path + # print 'Importing the BVH Hierarchy for:', file_path pass else: raise Exception("This is not a BVH file") @@ -121,8 +142,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): lineIdx = 0 # An index for the file. while lineIdx < len(file_lines) - 1: - #... - if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint': + if file_lines[lineIdx][0].lower() in {'root', 'joint'}: # Join spaces into 1 word with underscores joining it. if len(file_lines[lineIdx]) > 2: @@ -134,7 +154,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): # Make sure the names are unique - Object names will match joint names exactly and both will be unique. name = file_lines[lineIdx][1] - #print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1]) + # print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1]) lineIdx += 2 # Increment to the next line (Offset) rest_head_local = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * global_scale @@ -185,16 +205,18 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): # If we have another child then we can call ourselves a parent, else bvh_nodes_serial.append(bvh_node) - # Account for an end node - if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is sometimes a name after 'End Site' but we will ignore it. - lineIdx += 2 # Increment to the next line (Offset) + # Account for an end node. + # There is sometimes a name after 'End Site' but we will ignore it. + if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': + # Increment to the next line (Offset) + lineIdx += 2 rest_tail = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * global_scale bvh_nodes_serial[-1].rest_tail_world = bvh_nodes_serial[-1].rest_head_world + rest_tail bvh_nodes_serial[-1].rest_tail_local = bvh_nodes_serial[-1].rest_head_local + rest_tail - # Just so we can remove the Parents in a uniform way - End has kids - # so this is a placeholder + # Just so we can remove the parents in a uniform way, + # the end has kids so this is a placeholder. bvh_nodes_serial.append(None) if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}'] @@ -208,15 +230,16 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion': lineIdx += 1 # Read frame count. if (len(file_lines[lineIdx]) == 2 and - file_lines[lineIdx][0].lower() == 'frames:'): + file_lines[lineIdx][0].lower() == 'frames:'): bvh_frame_count = int(file_lines[lineIdx][1]) lineIdx += 1 # Read frame rate. - if (len(file_lines[lineIdx]) == 3 and + if ( + len(file_lines[lineIdx]) == 3 and file_lines[lineIdx][0].lower() == 'frame' and - file_lines[lineIdx][1].lower() == 'time:'): - + file_lines[lineIdx][1].lower() == 'time:' + ): bvh_frame_time = float(file_lines[lineIdx][2]) lineIdx += 1 # Set the cursor to the first frame @@ -227,7 +250,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): # Remove the None value used for easy parent reference del bvh_nodes[None] - # Dont use anymore + # Don't use anymore del bvh_nodes_serial # importing world with any order but nicer to maintain order @@ -237,7 +260,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): while lineIdx < len(file_lines): line = file_lines[lineIdx] for bvh_node in bvh_nodes_list: - #for bvh_node in bvh_nodes_serial: + # for bvh_node in bvh_nodes_serial: lx = ly = lz = rx = ry = rz = 0.0 channels = bvh_node.channels anim_data = bvh_node.anim_data @@ -279,7 +302,7 @@ def read_bvh(context, file_path, rotate_mode='XYZ', global_scale=1.0): bvh_node.rest_tail_local = bvh_node.rest_head_local + bvh_node.children[0].rest_head_local else: # allow this, see above - #if not bvh_node.children: + # if not bvh_node.children: # raise Exception("bvh node has no end and no children. bad file") # Removed temp for now @@ -364,16 +387,17 @@ def bvh_node_dict2objects(context, bvh_name, bvh_nodes, rotate_mode='NATIVE', fr return objects -def bvh_node_dict2armature(context, - bvh_name, - bvh_nodes, - bvh_frame_time, - rotate_mode='XYZ', - frame_start=1, - IMPORT_LOOP=False, - global_matrix=None, - use_fps_scale=False, - ): +def bvh_node_dict2armature( + context, + bvh_name, + bvh_nodes, + bvh_frame_time, + rotate_mode='XYZ', + frame_start=1, + IMPORT_LOOP=False, + global_matrix=None, + use_fps_scale=False, +): if frame_start < 1: frame_start = 1 @@ -521,7 +545,7 @@ def bvh_node_dict2armature(context, for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) - #print("bvh_frame_time = %f, dt = %f, num_frame = %d" + # print("bvh_frame_time = %f, dt = %f, num_frame = %d" # % (bvh_frame_time, dt, num_frame])) for i, bvh_node in enumerate(bvh_nodes_list): @@ -537,7 +561,7 @@ def bvh_node_dict2armature(context, bvh_loc = bvh_node.anim_data[frame_i + skip_frame][:3] bone_translate_matrix = Matrix.Translation( - Vector(bvh_loc) - bvh_node.rest_head_local) + Vector(bvh_loc) - bvh_node.rest_head_local) location[frame_i] = (bone_rest_matrix_inv * bone_translate_matrix).to_translation() @@ -549,7 +573,7 @@ def bvh_node_dict2armature(context, for frame_i in range(num_frame): keyframe_points[frame_i].co = \ - (time[frame_i], location[frame_i][axis_i]) + (time[frame_i], location[frame_i][axis_i]) if bvh_node.has_rot: data_path = None @@ -580,7 +604,7 @@ def bvh_node_dict2armature(context, rotate[frame_i] = bone_rotation_matrix.to_quaternion() else: rotate[frame_i] = bone_rotation_matrix.to_euler( - pose_bone.rotation_mode, prev_euler) + pose_bone.rotation_mode, prev_euler) prev_euler = rotate[frame_i] # For each Euler angle x, y, z (or Quaternion w, x, y, z). @@ -591,7 +615,7 @@ def bvh_node_dict2armature(context, for frame_i in range(0, num_frame): keyframe_points[frame_i].co = \ - (time[frame_i], rotate[frame_i][axis_i]) + (time[frame_i], rotate[frame_i][axis_i]) for cu in action.fcurves: if IMPORT_LOOP: @@ -607,28 +631,30 @@ def bvh_node_dict2armature(context, return arm_ob -def load(context, - filepath, - *, - target='ARMATURE', - rotate_mode='NATIVE', - global_scale=1.0, - use_cyclic=False, - frame_start=1, - global_matrix=None, - use_fps_scale=False, - update_scene_fps=False, - update_scene_duration=False, - report=print - ): - +def load( + context, + filepath, + *, + target='ARMATURE', + rotate_mode='NATIVE', + global_scale=1.0, + use_cyclic=False, + frame_start=1, + global_matrix=None, + use_fps_scale=False, + update_scene_fps=False, + update_scene_duration=False, + report=print +): import time t1 = time.time() print("\tparsing bvh %r..." % filepath, end="") - bvh_nodes, bvh_frame_time, bvh_frame_count = read_bvh(context, filepath, - rotate_mode=rotate_mode, - global_scale=global_scale) + bvh_nodes, bvh_frame_time, bvh_frame_count = read_bvh( + context, filepath, + rotate_mode=rotate_mode, + global_scale=global_scale, + ) print("%.4f" % (time.time() - t1)) @@ -637,9 +663,12 @@ def load(context, # Broken BVH handling: guess frame rate when it is not contained in the file. if bvh_frame_time is None: - report({'WARNING'}, "The BVH file does not contain frame duration in its MOTION " - "section, assuming the BVH and Blender scene have the same " - "frame rate") + report( + {'WARNING'}, + "The BVH file does not contain frame duration in its MOTION " + "section, assuming the BVH and Blender scene have the same " + "frame rate" + ) bvh_frame_time = scene.render.fps_base / scene.render.fps # No need to scale the frame rate, as they're equal now anyway. use_fps_scale = False @@ -652,8 +681,7 @@ def load(context, use_fps_scale = False if update_scene_duration: - _update_scene_duration(context, report, bvh_frame_count, bvh_frame_time, frame_start, - use_fps_scale) + _update_scene_duration(context, report, bvh_frame_count, bvh_frame_time, frame_start, use_fps_scale) t1 = time.time() print("\timporting to blender...", end="") @@ -661,21 +689,23 @@ def load(context, bvh_name = bpy.path.display_name_from_filepath(filepath) if target == 'ARMATURE': - bvh_node_dict2armature(context, bvh_name, bvh_nodes, bvh_frame_time, - rotate_mode=rotate_mode, - frame_start=frame_start, - IMPORT_LOOP=use_cyclic, - global_matrix=global_matrix, - use_fps_scale=use_fps_scale, - ) + bvh_node_dict2armature( + context, bvh_name, bvh_nodes, bvh_frame_time, + rotate_mode=rotate_mode, + frame_start=frame_start, + IMPORT_LOOP=use_cyclic, + global_matrix=global_matrix, + use_fps_scale=use_fps_scale, + ) elif target == 'OBJECT': - bvh_node_dict2objects(context, bvh_name, bvh_nodes, - rotate_mode=rotate_mode, - frame_start=frame_start, - IMPORT_LOOP=use_cyclic, - # global_matrix=global_matrix, # TODO - ) + bvh_node_dict2objects( + context, bvh_name, bvh_nodes, + rotate_mode=rotate_mode, + frame_start=frame_start, + IMPORT_LOOP=use_cyclic, + # global_matrix=global_matrix, # TODO + ) else: report({'ERROR'}, "Invalid target %r (must be 'ARMATURE' or 'OBJECT')" % target) @@ -693,8 +723,11 @@ def _update_scene_fps(context, report, bvh_frame_time): # Broken BVH handling: prevent division by zero. if bvh_frame_time == 0.0: - report({'WARNING'}, "Unable to update scene frame rate, as the BVH file " - "contains a zero frame duration in its MOTION section") + report( + {'WARNING'}, + "Unable to update scene frame rate, as the BVH file " + "contains a zero frame duration in its MOTION section", + ) return scene = context.scene @@ -707,13 +740,17 @@ def _update_scene_fps(context, report, bvh_frame_time): scene.render.fps_base = 1.0 -def _update_scene_duration(context, report, bvh_frame_count, bvh_frame_time, frame_start, - use_fps_scale): +def _update_scene_duration( + context, report, bvh_frame_count, bvh_frame_time, frame_start, + use_fps_scale): """Extend the scene's duration so that the BVH file fits in its entirety.""" if bvh_frame_count is None: - report({'WARNING'}, "Unable to extend the scene duration, as the BVH file does not " - "contain the number of frames in its MOTION section") + report( + {'WARNING'}, + "Unable to extend the scene duration, as the BVH file does not " + "contain the number of frames in its MOTION section", + ) return # Not likely, but it can happen when a BVH is just used to store an armature. -- 2.11.4.GIT