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])
def eulerRotate(x,y,z, rot_order):
# 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
# 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 = (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
@ -187,7 +186,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# 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.
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_local = bvh_nodes_serial[-1].rest_head_local + rest_tail
@ -235,22 +234,12 @@ 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]])
if ROT_MODE != 'NATIVE':
rx, ry, rz = eulerRotate(rx, ry, rz, bvh_node.rot_order)
# Make interpolation not cross between 180d, thjis fixes sub frame interpolation and time scaling.
# 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
rx, ry, rz = eulerRotate(radians(rx), radians(ry), radians(rz), bvh_node.rot_order)
else:
rx, ry, rz = radians(rx), radians(ry), radians(rz)
# Done importing motion data #
anim_data.append( (lx, ly, lz, rx, ry, rz) )
anim_data.append((lx, ly, lz, rx, ry, rz))
lineIdx += 1
# Assign children
@ -267,7 +256,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# could just fail here, but rare BVH files have childless nodes
bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world)
bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local)
elif len(bvh_node.children)==1:
elif len(bvh_node.children) == 1:
bvh_node.rest_tail_world = Vector(bvh_node.children[0].rest_head_world)
bvh_node.rest_tail_local = bvh_node.rest_head_local + bvh_node.children[0].rest_head_local
else:
@ -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'
# Removed temp for now
rest_tail_world = Vector(0, 0, 0)
rest_tail_local = Vector(0, 0, 0)
rest_tail_world = Vector(0.0, 0.0, 0.0)
rest_tail_local = Vector(0.0, 0.0, 0.0)
for bvh_node_child in bvh_node.children:
rest_tail_world += bvh_node_child.rest_head_world
rest_tail_local += bvh_node_child.rest_head_local
@ -333,15 +322,15 @@ def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME= 1, IMPORT_LOOP
# 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)):
Blender.Set('curframe', current_frame+IMPORT_START_FRAME)
Blender.Set('curframe', current_frame + IMPORT_START_FRAME)
for bvh_node in bvh_nodes.values():
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
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
@ -473,7 +462,7 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
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 = eul_order_lookup[tuple(bvh_node.rot_order)]
pose_bone.rotation_mode = eul_order_lookup[tuple(bvh_node.rot_order)]
elif ROT_MODE=='XYZ':
print(2)
@ -521,6 +510,9 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
# KEYFRAME METHOD, SLOW, USE IPOS DIRECT
# 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
for current_frame in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
# print current_frame
@ -529,20 +521,23 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
# break
# 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
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:
bone_rotation_matrix= Euler(radians(rx), radians(ry), radians(rz)).to_matrix()
bone_rotation_matrix.resize4x4()
if ROT_MODE=='QUATERNION':
pose_bone.rotation_quaternion= (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix).to_quat()
bone_rotation_matrix = Euler(rx, ry, rz).to_matrix().resize4x4()
bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix
if ROT_MODE == 'QUATERNION':
pose_bone.rotation_quaternion = bone_rotation_matrix.to_quat()
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:
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()
if bvh_node.has_loc:
pose_bone.keyframe_insert("location")
@ -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.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
for cu in action.fcurves:
if IMPORT_LOOP:
pass # 2.5 doenst have cyclic now?
else:
for cu in action.fcurves:
for bez in cu.keyframe_points:
bez.interpolation = 'CONSTANT'
for bez in cu.keyframe_points:
bez.interpolation = 'LINEAR'
return arm_ob