def add_object_align_init(context, operator): """ Return a matrix using the operator settings and view context. :arg context: The context to use. :type context: :class:`bpy.types.Context` :arg operator: The operator, checked for location and rotation properties. :type operator: :class:`bpy.types.Operator` :return: the matrix from the context and settings. :rtype: :class:`mathutils.Matrix` """ from mathutils import Matrix, Vector, Euler properties = operator.properties if operator is not None else None space_data = context.space_data if space_data and space_data.type != 'VIEW_3D': space_data = None # location if operator and properties.is_property_set("location"): location = Matrix.Translation(Vector(properties.location)) else: location = Matrix.Translation(context.scene.cursor_location) if operator: properties.location = location.to_translation() # rotation view_align = (context.preferences.edit.object_align == 'VIEW') view_align_force = False if operator: if properties.is_property_set("view_align"): view_align = view_align_force = operator.view_align else: if properties.is_property_set("rotation"): # ugh, 'view_align' callback resets value = properties.rotation[:] properties.view_align = view_align properties.rotation = value del value else: properties.view_align = view_align if operator and (properties.is_property_set("rotation") and not view_align_force): rotation = Euler(properties.rotation).to_matrix().to_4x4() else: if view_align and space_data: rotation = space_data.region_3d.view_matrix.to_3x3().inverted() rotation.resize_4x4() else: rotation = Matrix() # set the operator properties if operator: properties.rotation = rotation.to_euler() return location @ rotation
def add_object_align_init(context, operator): """ Return a matrix using the operator settings and view context. :arg context: The context to use. :type context: :class:`bpy.types.Context` :arg operator: The operator, checked for location and rotation properties. :type operator: :class:`bpy.types.Operator` :return: the matrix from the context and settings. :rtype: :class:`mathutils.Matrix` """ from mathutils import Matrix, Vector, Euler properties = operator.properties if operator is not None else None space_data = context.space_data if space_data and space_data.type != 'VIEW_3D': space_data = None # location if operator and properties.is_property_set("location"): location = Matrix.Translation(Vector(properties.location)) else: location = Matrix.Translation(context.scene.cursor.location) if operator: properties.location = location.to_translation() # rotation view_align = (context.preferences.edit.object_align == 'VIEW') view_align_force = False if operator: if properties.is_property_set("view_align"): view_align = view_align_force = operator.view_align else: if properties.is_property_set("rotation"): # ugh, 'view_align' callback resets value = properties.rotation[:] properties.view_align = view_align properties.rotation = value del value else: properties.view_align = view_align if operator and (properties.is_property_set("rotation") and not view_align_force): rotation = Euler(properties.rotation).to_matrix().to_4x4() else: if view_align and space_data: rotation = space_data.region_3d.view_matrix.to_3x3().inverted() rotation.resize_4x4() else: rotation = Matrix() # set the operator properties if operator: properties.rotation = rotation.to_euler() return location @ rotation
def bvh_node_dict2armature(context, bvh_name, bvh_nodes, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, ): if frame_start < 1: frame_start = 1 # Add the new armature, scene = context.scene for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) # 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(): l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones couldbe zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) ZERO_AREA_BONES = [] for name, bvh_node in bvh_nodes.items(): # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes.values(): if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if not bvh_node.has_loc and\ bvh_node.parent and\ bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes.values(): bvh_node.temp = bvh_node.temp.name # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes.values(): 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 elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # 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(): 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] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) # Make a dict for fast access without rebuilding a list all the time. # KEYFRAME METHOD, SLOW, USE IPOS DIRECT # TODO: use f-point samples instead (Aligorith) if rotate_mode != 'QUATERNION': prev_euler = [Euler() for i in range(len(bvh_nodes))] # Animate the data, the last used bvh_node will do since they all have the same number of frames for frame_current in range(len(bvh_node.anim_data) - 1): # skip the first frame (rest frame) # print frame_current # if frame_current==40: # debugging # break scene.frame_set(frame_start + frame_current) # Dont neet to set the current frame for i, bvh_node in enumerate(bvh_nodes.values()): 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] if bvh_node.has_rot: # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. bone_rotation_matrix = Euler((rx, ry, rz), bvh_node.rot_order_str[::-1]).to_matrix().to_4x4() bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix if rotate_mode == 'QUATERNION': pose_bone.rotation_quaternion = bone_rotation_matrix.to_quaternion() else: euler = bone_rotation_matrix.to_euler(pose_bone.rotation_mode, prev_euler[i]) pose_bone.rotation_euler = euler prev_euler[i] = euler if bvh_node.has_loc: pose_bone.location = (bone_rest_matrix_inv * Matrix.Translation(Vector((lx, ly, lz)) - bvh_node.rest_head_local)).to_translation() if bvh_node.has_loc: pose_bone.keyframe_insert("location") if bvh_node.has_rot: if rotate_mode == 'QUATERNION': pose_bone.keyframe_insert("rotation_quaternion") else: pose_bone.keyframe_insert("rotation_euler") for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob
def bvh_node_dict2armature( context, bvh_name, bvh_nodes, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, ): if frame_start < 1: frame_start = 1 # Add the new armature, scene = context.scene for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob 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_list: l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones could be zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) ZERO_AREA_BONES = [] for bvh_node in bvh_nodes_list: # New editbone 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 # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes_list: if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if ((not bvh_node.has_loc) and (bvh_node.parent.temp.name not in ZERO_AREA_BONES) and (bvh_node.parent.rest_tail_local == bvh_node.rest_head_local)): bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes_list: bvh_node.temp = bvh_node.temp.name # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': 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 elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # 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_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] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) # Make a dict for fast access without rebuilding a list all the time. # KEYFRAME METHOD, SLOW, USE IPOS DIRECT # TODO: use f-point samples instead (Aligorith) if rotate_mode != 'QUATERNION': prev_euler = [Euler() for i in range(len(bvh_nodes))] # Animate the data, the last used bvh_node will do since they all have the same number of frames for frame_current in range(len(bvh_node.anim_data) - 1): # skip the first frame (rest frame) # print frame_current # if frame_current==40: # debugging # break scene.frame_set(frame_start + frame_current) # Dont neet to set the current frame 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] if bvh_node.has_rot: # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. bone_rotation_matrix = Euler( (rx, ry, rz), bvh_node.rot_order_str[::-1]).to_matrix().to_4x4() bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix if rotate_mode == 'QUATERNION': pose_bone.rotation_quaternion = bone_rotation_matrix.to_quaternion( ) else: euler = bone_rotation_matrix.to_euler( pose_bone.rotation_mode, prev_euler[i]) pose_bone.rotation_euler = euler prev_euler[i] = euler if bvh_node.has_loc: pose_bone.location = ( bone_rest_matrix_inv * Matrix.Translation( Vector((lx, ly, lz)) - bvh_node.rest_head_local)).to_translation() if bvh_node.has_loc: pose_bone.keyframe_insert("location") if bvh_node.has_rot: if rotate_mode == 'QUATERNION': pose_bone.keyframe_insert("rotation_quaternion") else: pose_bone.keyframe_insert("rotation_euler") for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob