diff options
author | Owl <isaclien9752@gmail.com> | 2025-08-27 23:54:31 -0400 |
---|---|---|
committer | Owl <isaclien9752@gmail.com> | 2025-08-27 23:54:31 -0400 |
commit | f4ff299e4e073b71495a3e2a385fa96d65fb6f80 (patch) | |
tree | 02ccd603b6f3907d108abd3d3d76ecdb1235b14a /bck_export.py | |
parent | ea2eeb7d18869bb19773782289dca325c14776d0 (diff) | |
download | blenxy-f4ff299e4e073b71495a3e2a385fa96d65fb6f80.tar.gz blenxy-f4ff299e4e073b71495a3e2a385fa96d65fb6f80.zip |
rotations people, rotations...
Diffstat (limited to 'bck_export.py')
-rw-r--r-- | bck_export.py | 125 |
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) |