summaryrefslogtreecommitdiff
path: root/bck_export.py
diff options
context:
space:
mode:
Diffstat (limited to 'bck_export.py')
-rw-r--r--bck_export.py125
1 files changed, 118 insertions, 7 deletions
diff --git a/bck_export.py b/bck_export.py
index 16f6468..105106f 100644
--- a/bck_export.py
+++ b/bck_export.py
@@ -48,8 +48,8 @@ def export_bck_func(options, context):
bck_anim.bone_count = len(armature.data.bones)
for i in range(bck_anim.bone_count):
# append the bone component animation data
- bck_anim.anim_data.append(bck_funcs.smg_bck_anim.anim_data())
-
+ bck_anim.anim_data.append(bck_funcs.smg_bck_anim.anim_data())
+
# start getting the actual animation data
for i in range(len(armature.data.bones)):
data_bone = armature.data.bones[i] # correct bone index order
@@ -62,15 +62,93 @@ def export_bck_func(options, context):
bone_fcurves = [None, None, None, None, None, None, None, None, None]
# ^ sx, rx, tx, sy (24!), ry, ty, sz, rz and tz in that order (bck order)
bone_data_path_str = "pose.bones[\"%s\"]." % (data_bone.name)
+ foreign_fcurves = [None, None, None, None] # quaternions/axis angles have 4 components
+ temp_fcurves = [None, None, None]
+ # ^ for rotation mode conversion to euler selected order mode
+ # from different euler order, quaternion or axis angle
+
+ # detect the rotation mode string (it will be the rotation mode active on the bone)
+ bone_rot_mode_str = pose_bone.rotation_mode
+ if ("Z" in bone_rot_mode_str): # awful but fast check
+ bone_rot_mode_str = "rotation_euler"
+ elif (bone_rot_mode_str == "QUATERNION"):
+ bone_rot_mode_str = "rotation_quaternion"
+ elif (bone_rot_mode_str == "AXIS_ANGLE"):
+ bone_rot_mode_str = "rotation_axis_angle"
+
+ # now get the animation data
for fcurve in armature.animation_data.action.fcurves:
+ # scaling
if (fcurve.data_path == bone_data_path_str + "scale"):
bone_fcurves[int((3 * fcurve.array_index) + 0)] = fcurve
- elif (fcurve.data_path == bone_data_path_str + "rotation_euler"):
- bone_fcurves[int((3 * fcurve.array_index) + 1)] = fcurve
+ # rotation (Euler [all its combinations], Quaternions, Axis angle)
+ elif (fcurve.data_path == bone_data_path_str + bone_rot_mode_str):
+ # check if it is Euler in the euler order selected, if not, select the curves for later conversion
+ if (bone_rot_mode_str == "rotation_euler" and bone_rot_euler_order_str == options.euler_mode):
+ bone_fcurves[int((3 * fcurve.array_index) + 1)] = fcurve
+ else:
+ foreign_fcurves[fcurve.array_index] = fcurve
+ # translation
elif (fcurve.data_path == bone_data_path_str + "location"):
bone_fcurves[int((3 * fcurve.array_index) + 2)] = fcurve
- # generate all the animation points, interpolation stuff will be done later
+ # if there are foreign rotation modes used
+ # convert them to the euler order mode requested
+ # and assign those fcurves to the bone_fcurves list
+ # (this is tuff)
+ if (options.euler_mode != pose_bone.rotation_mode):
+ # generate the temp fcurves
+ for j in range(3):
+ temp_fcurves[j] = armature.animation_data.action.fcurves.new("temp_fcurves", j, "temp")
+ og_rot_values = [None, None, None, None] # to hold original data
+
+ # other euler order
+ if ("Z" in pose_bone.rotation_mode):
+ # go through all animation frames
+ for j in range(options.first_frame, options.anim_length):
+ # get the og data
+ for k in range(3):
+ og_rot_values[k] = foreign_fcurves[k].evaluate(j)
+ # compile into a matrix, get the desired angles from it in the new euler order
+ tmp = mathutils.Euler(og_rot_values[0:3], pose_bone.rotation_mode)
+ tmp = tmp.to_matrix().to_euler(options.euler_mode)
+ # assign the respective points to the temp fcurves
+ for k in range(3):
+ temp_fcurves[k].keyframe_points.insert(j, tmp[k])
+
+ # quaternions
+ elif (pose_bone.rotation_mode == "QUATERNION"):
+ # go through all animation frames
+ for j in range(options.first_frame, options.anim_length):
+ # get the og data
+ for k in range(4):
+ og_rot_values[k] = foreign_fcurves[k].evaluate(j)
+ # compile into a quaternion, get the desired angles from it in the new euler order
+ tmp = mathutils.Quaternion(og_rot_values).to_euler(options.euler_mode)
+ # assign the respective points to the temp fcurves
+ for k in range(3):
+ temp_fcurves[k].keyframe_points.insert(j, tmp[k])
+
+ # axis angle
+ elif (pose_bone.rotation_mode == "AXIS_ANGLE"):
+ # go through all animation frames
+ for j in range(options.first_frame, options.anim_length):
+ # get the og data
+ for k in range(4):
+ og_rot_values[k] = foreign_fcurves[k].evaluate(j)
+ # compile into a matrix, get the desired angles from it in the new euler order
+ tmp = mathutils.Matrix.Rotation(og_rot_values[0], 3, og_rot_values[1:]).to_euler(options.euler_mode)
+ # assign the respective points to the temp fcurves
+ for k in range(3):
+ temp_fcurves[k].keyframe_points.insert(j, tmp[k])
+
+ # assign the resulting fcurves to the bone_fcurves list
+ # rotation fcurves
+ for j in range(3):
+ bone_fcurves[int((j * 3) + 1)] = temp_fcurves[j]
+
+ # all the fcurves with the correct units were selected
+ # generate all the new animation points, interpolation stuff will be done later
# get the rest pose matrix
rest_mat = data_bone.matrix_local.copy()
@@ -100,18 +178,25 @@ def export_bck_func(options, context):
transl[int((k - 2) / 3)] = value
# convert the values to be respect to parent
- new_mat = rest_mat.copy() * math_funcs.calc_transf_mat(scale, rot, transl).copy()
+ new_mat = rest_mat.copy() * math_funcs.calc_transf_mat(scale, rot, transl,
+ options.euler_mode,
+ options.mult_order).copy()
for k in range(9):
value = None
# check which is the component to get
if (k == 0 or k == 3 or k == 6):
value = round(new_mat.to_scale()[int((k - 0) / 3)], options.rounding_vec[0])
elif (k == 1 or k == 4 or k == 7):
- value = round(new_mat.to_euler("XYZ")[int((k - 1) / 3)], options.rounding_vec[1])
+ value = round(new_mat.to_euler(options.euler_mode)[int((k - 1) / 3)], options.rounding_vec[1])
elif (k == 2 or k == 5 or k == 8):
value = round(100 * new_mat.to_translation()[int((k - 2) / 3)], options.rounding_vec[2])
# 100 times because of blenxy's coordinates
bck_anim.anim_data[i].comp[k].value.append(value)
+
+ # delete the temp_fcurves generated
+ for fcurve in temp_fcurves:
+ if (fcurve != None):
+ armature.animation_data.action.fcurves.remove(fcurve)
# got all the animation points
@@ -307,6 +392,32 @@ class export_bck(Operator, ExportHelper):
min = 0,
max = 9
)
+ euler_mode = EnumProperty(
+ name = "Euler order",
+ description = "Export rotation animations in the specified Euler angles order",
+ default = "XYZ",
+ items = (
+ ("XYZ", "XYZ", "X rotation first, Y rotation second, Z rotation last"),
+ ("XZY", "XZY", "X rotation first, Z rotation second, Y rotation last"),
+ ("YXZ", "YXZ", "Y rotation first, X rotation second, Z rotation last"),
+ ("YZX", "YZX", "Y rotation first, Z rotation second, X rotation last"),
+ ("ZXY", "ZXY", "Z rotation first, X rotation second, Y rotation last"),
+ ("ZYX", "ZYX", "Z rotation first, Y rotation second, X rotation last")
+ )
+ )
+ mult_order = EnumProperty(
+ name = "Scale/Rot/Transl mult order",
+ description = "Export animations in the specified matrix multiplication order",
+ default = "SRT",
+ items = (
+ ("TRS", "TRS", "Translation first, Rotation second, Scaling last"),
+ ("TSR", "TSR", "Translation first, Scaling second, Rotation last"),
+ ("RTS", "RTS", "Rotation first, Translation second, Scaling last"),
+ ("RST", "RST", "Rotation first, Scaling second, Translation last"),
+ ("STR", "STR", "Scaling first, Translation second, Rotation last"),
+ ("SRT", "SRT", "Scaling first, Rotation second, Translation last")
+ )
+ )
# what the importer actually does
def execute(self, context):
return export_bck_func(self, context)