improved euler conversion, make sure new eulers are always compatible with the previous ones, means it doesnt result in bad interpolation.

This commit is contained in:
Campbell Barton 2010-02-21 10:30:39 +00:00
parent 5dd8d10336
commit dd04e25a14

@ -77,9 +77,8 @@ MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1])
MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]) MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
def eulerRotate(x,y,z, rot_order): def eulerRotate(x,y,z, rot_order):
# Clamp all values between 0 and 360, values outside this raise an error. # Clamp all values between 0 and 360, values outside this raise an error.
mats=[RotationMatrix(radians(x % 360), 3, 'X'), RotationMatrix(radians(y % 360),3,'Y'), RotationMatrix(radians(z % 360), 3, 'Z')] mats=[RotationMatrix(x, 3, 'X'), RotationMatrix(y, 3,'Y'), RotationMatrix(z, 3, 'Z')]
# print rot_order # print rot_order
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y # Standard BVH multiplication order, apply the rotation in the order Z,X,Y
@ -87,7 +86,7 @@ def eulerRotate(x,y,z, rot_order):
#eul = (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).to_euler() #eul = (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).to_euler()
eul = (MATRIX_IDENTITY_3x3*mats[rot_order[0]]*(mats[rot_order[1]]* (mats[rot_order[2]]))).to_euler() eul = (MATRIX_IDENTITY_3x3*mats[rot_order[0]]*(mats[rot_order[1]]* (mats[rot_order[2]]))).to_euler()
eul = math.degrees(eul.x), math.degrees(eul.y), math.degrees(eul.z) eul = eul.x, eul.y, eul.z
return eul return eul
@ -187,7 +186,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# Account for an end node # Account for an end node
if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it. if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset) lineIdx += 2 # Incriment to the next line (Offset)
rest_tail = Vector( GLOBAL_SCALE*float(file_lines[lineIdx][1]), GLOBAL_SCALE*float(file_lines[lineIdx][2]), GLOBAL_SCALE*float(file_lines[lineIdx][3])) 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_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 bvh_nodes_serial[-1].rest_tail_local = bvh_nodes_serial[-1].rest_head_local + rest_tail
@ -235,19 +234,9 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
rx, ry, rz = float(line[channels[3]]), float(line[channels[4]]), float(line[channels[5]]) rx, ry, rz = float(line[channels[3]]), float(line[channels[4]]), float(line[channels[5]])
if ROT_MODE != 'NATIVE': if ROT_MODE != 'NATIVE':
rx, ry, rz = eulerRotate(rx, ry, rz, bvh_node.rot_order) rx, ry, rz = eulerRotate(radians(rx), radians(ry), radians(rz), bvh_node.rot_order)
else:
# Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling. rx, ry, rz = radians(rx), radians(ry), radians(rz)
# Will go from (355d to 365d) rather then to (355d to 5d) - inbetween these 2 there will now be a correct interpolation.
while anim_data[-1][3] - rx > 180: rx+=360
while anim_data[-1][3] - rx < -180: rx-=360
while anim_data[-1][4] - ry > 180: ry+=360
while anim_data[-1][4] - ry < -180: ry-=360
while anim_data[-1][5] - rz > 180: rz+=360
while anim_data[-1][5] - rz < -180: rz-=360
# Done importing motion data # # Done importing motion data #
anim_data.append((lx, ly, lz, rx, ry, rz)) anim_data.append((lx, ly, lz, rx, ry, rz))
@ -276,8 +265,8 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# raise 'error, bvh node has no end and no children. bad file' # raise 'error, bvh node has no end and no children. bad file'
# Removed temp for now # Removed temp for now
rest_tail_world = Vector(0, 0, 0) rest_tail_world = Vector(0.0, 0.0, 0.0)
rest_tail_local = Vector(0, 0, 0) rest_tail_local = Vector(0.0, 0.0, 0.0)
for bvh_node_child in bvh_node.children: for bvh_node_child in bvh_node.children:
rest_tail_world += bvh_node_child.rest_head_world rest_tail_world += bvh_node_child.rest_head_world
rest_tail_local += bvh_node_child.rest_head_local rest_tail_local += bvh_node_child.rest_head_local
@ -339,9 +328,9 @@ def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP
lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame] lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame]
rest_head_local= bvh_node.rest_head_local rest_head_local= bvh_node.rest_head_local
bvh_node.temp.loc= rest_head_local.x+lx, rest_head_local.y+ly, rest_head_local.z+lz bvh_node.temp.loc= rest_head_local + Vector(lx, ly, lz)
bvh_node.temp.rot= radians(rx), radians(ry), radians(rz) bvh_node.temp.rot= rx, ry, rz
bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) # XXX invalid bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) # XXX invalid
@ -521,6 +510,9 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
# KEYFRAME METHOD, SLOW, USE IPOS DIRECT # KEYFRAME METHOD, SLOW, USE IPOS DIRECT
# TODO: use f-point samples instead (Aligorith) # TODO: use f-point samples instead (Aligorith)
if ROT_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 # Animate the data, the last used bvh_node will do since they all have the same number of frames
for current_frame in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame) for current_frame in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
# print current_frame # print current_frame
@ -529,17 +521,20 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
# break # break
# Dont neet to set the current frame # Dont neet to set the current frame
for bvh_node in bvh_nodes.values(): for i, bvh_node in enumerate(bvh_nodes.values()):
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv= bvh_node.temp
lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame + 1] lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame + 1]
if bvh_node.has_rot: if bvh_node.has_rot:
bone_rotation_matrix= Euler(radians(rx), radians(ry), radians(rz)).to_matrix() bone_rotation_matrix = Euler(rx, ry, rz).to_matrix().resize4x4()
bone_rotation_matrix.resize4x4() bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix
if ROT_MODE == 'QUATERNION': if ROT_MODE == 'QUATERNION':
pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix).to_quat() pose_bone.rotation_quaternion = bone_rotation_matrix.to_quat()
else: else:
pose_bone.rotation_euler= (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix).to_euler(pose_bone.rotation_mode) euler = bone_rotation_matrix.to_euler('XYZ', prev_euler[i]) # pose_bone.rotation_mode # TODO, XYZ default for now
pose_bone.rotation_euler = euler
prev_euler[i] = euler
if bvh_node.has_loc: if bvh_node.has_loc:
pose_bone.location= (bone_rest_matrix_inv * TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local)).translation_part() pose_bone.location= (bone_rest_matrix_inv * TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local)).translation_part()
@ -556,22 +551,12 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
# bpy.ops.anim.keyframe_insert_menu(type=-4) # XXX - -4 ??? # bpy.ops.anim.keyframe_insert_menu(type=-4) # XXX - -4 ???
bpy.ops.screen.frame_offset(delta=1) bpy.ops.screen.frame_offset(delta=1)
# First time, set the IPO's to linear
#XXX #TODO
if 0:
if current_frame == 0:
for ipo in action.getAllChannelIpos().values():
if ipo:
for cur in ipo:
cur.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
if IMPORT_LOOP:
cur.extend = Blender.IpoCurve.ExtendTypes.CYCLIC
else:
for cu in action.fcurves: for cu in action.fcurves:
if IMPORT_LOOP:
pass # 2.5 doenst have cyclic now?
for bez in cu.keyframe_points: for bez in cu.keyframe_points:
bez.interpolation = 'CONSTANT' bez.interpolation = 'LINEAR'
return arm_ob return arm_ob