diff options
Diffstat (limited to 'my_functions.py')
-rw-r--r-- | my_functions.py | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/my_functions.py b/my_functions.py new file mode 100644 index 0000000..1f76b82 --- /dev/null +++ b/my_functions.py @@ -0,0 +1,389 @@ +''' +file that contains some functions that I don't +want to re-write on each individual .py file +''' + +import bpy, math, re +from mathutils import Matrix + + +################################################ +# show message on screen for errors or warnnings +# copied this code from a page I saw it in :) +################################################ +def show_message(message = "", title = "Message Box", icon = 'INFO'): +# + def draw(self, context): + self.layout.label(text=message) + + bpy.context.window_manager.popup_menu(draw, title = title, icon = icon) +# + + +####################################### +# calc_scale_matrix function +# function to build the scale matrix +# +# x_scale (float) --> scaling in X axis +# y_scale (float) --> scaling in Y axis +# z_scale (float) --> scaling in Z axis +####################################### +def calc_scale_matrix(x_scale, y_scale, z_scale): +# + scale_matrix = Matrix(( [x_scale, 0, 0, 0], + [0, y_scale, 0, 0], + [0, 0, z_scale, 0], + [0, 0, 0, 1] + )) + + return scale_matrix +# + + +################################################### +# calc_rotation_matrix function +# function to calculate the rotation matrix +# for a Extrinsic Euler XYZ system +# +# x_angle (float) --> rot angle in X axis (radians) +# y_angle (float) --> rot angle in Y axis (radians) +# z_angle (float) --> rot angle in > axis (radians) +################################################### +def calc_rotation_matrix(x_angle, y_angle, z_angle): +# + x_rot_mat = Matrix(([1, 0, 0, 0], + [0, math.cos(x_angle), -math.sin(x_angle), 0], + [0, math.sin(x_angle), math.cos(x_angle), 0], + [0, 0, 0, 1])) + + y_rot_mat = Matrix(([math.cos(y_angle), 0, math.sin(y_angle), 0], + [0, 1, 0, 0], + + [-math.sin(y_angle), 0, math.cos(y_angle), 0], + [0, 0, 0, 1])) + + z_rot_mat = Matrix(([math.cos(z_angle), -math.sin(z_angle), 0, 0], + [math.sin(z_angle), math.cos(z_angle), 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1])) + + return z_rot_mat * y_rot_mat * x_rot_mat +# + + +################################################# +# calc_translation_matrix function +# function to build the translation matrix +# +# x_translation (float) --> translation in X axis +# y_translation (float) --> translation in Y axis +# z_translation (float) --> translation in Z axis +################################################# +def calc_translation_matrix(x_translation, y_translation, z_translation): +# + translation_matrix = Matrix(( [1, 0, 0, x_translation], + [0, 1, 0, y_translation], + [0, 0, 1, z_translation], + [0, 0, 0, 1] + )) + + return translation_matrix +# + + + +############################################################## +# interpolate function +# used to find a value in an inte +rval with the specified mode. +# So that it is clear that the values are points that have 2 +# coordinates I will treat the input as they are (x,y) points +# the function will either return m_x or m_y depending on +# which of the middle point value + +s is provided to the function +# (set None to the variable going to be returned by the +# function). Smooth will use the Cubic Hermite Spline +# interpolation method and will be the one using the point's +# derivatives/tangent. +# +# IMPORTANT (FOR SMOOTH INTERPOLA +TION): +# +# As I don't really have information on how to define +# tangent-out or tangent in/out interpolation (as JAE has +# already done those calculations) I will use the same +# interpolation method to both tangent-out or tangent in/out +# CSV files. If someone knows about this better please open +# an issue on blenxy's repository +# +# l_x (float) --> left point X axis component +# l_y (float) --> left point Y axis component +# r_x (float) --> right point X axis component +# r_y (float) --> right point Y axis component +# m_x (float) --> middle point X axis component +# m_y (float) --> middle point Y axis component +# interp_type (string) --> "linear" for linear interpolation +# "smooth" for smooth interpolation +############################################################## +def interpolate(l_x, l_y, r_x, r_y, m_x, m_y, interp_type): +# + # variable to be returned + result = 0 + + ############################################## + # if right point does not exist (special case) + # return l_y as the interpolation result + if (r_x == None or r_y == None): + result = l_y + return result + + ############################### + # m_x is the one to be returned + if (m_x == None): + if (interp_type == "linear"): + m_x = (((r_x - l_x) / (r_y - l_y)) * (m_y - r_y)) + r_x + result = m_x + + else: # interpolation type is "smooth" + + + ############################### + # m_y is the one to be returned + if (m_y == None): + if (interp_type == "linear"): + m_y = (((r_y - l_y) / (r_x - l_x)) * (m_x - r_x)) + r_y + result = m_y + + return result +# + + +#################################################################### +# find_left_right function +# find the values and positions of the elements at the left and the +# right of the element in position pos on the anim_array +# elements will be used in the interpolate() function later +# +# anim_array (array of floats) --> anim property frame array its +# length must the animation length +# pos (int) --> position of the animation property value to be +# later interpolated in the anim_array array +#################################################################### +def find_left_right(anim_array, pos): +# + ############################# + # create left/right variables + l_val = 0 + l_val_pos = 0 + r_val = 0 + r_val_pos = 0 + + ##################################### + # find near left value (has to exist) + # read array from right to left + for i in range(len(anim_array), -1, -1): + # + # skip elements at the right of + # pos in anim_array + if (i >= pos): + continue + + # left value is found + if (anim_array[i] != None): + l_val = anim_array[i] + l_val_pos = i + break + # + + ############## + # special case + ############## + # if pos is the last element position on + # the array r_val and r_val_pos do not exist + if (pos == (len(anim_array) - 1)): + return [l_val_pos, l_val, None, None] + + ######################################### + # find near right value (might not exist) + # read array from left to right + for i in range(len(anim_array)): + # + # skip elements at the left of + # pos in anim_array + if (i <= pos): + continue + + # right value is found + if (anim_array[i] != None): + r_val = anim_array[i] + r_val_pos = i + break + + # if no value is found at the end of + # the anim_array r_val and r_val_pos do not exist + # (value does not change between the left value + # found and the end of the animation) + if (i == (len(anim_array) - 1)): + return [l_val_pos, l_val, None, None] + # + + # if all values are found, return them + return [l_val_pos, l_val, r_val_pos, r_val] +# + + +####################################################### +# convert_angle_to_180 function +# function used by the convert_anim_rot_to_180 function +# to convert a single angle in its representation on +# the -180/+180 degree range (angles passed to the +# function that are already in this range will be +# returned without conversion) +# +# angle (float) --> angle to convert to the -180/+180 +# degree range (angle is expected to +# be in degrees) +####################################################### +def convert_angle_to_180(angle): +# + # check if the angle really needs to be processed + # i.e. is already inside the -180/+180 degree range + if (angle >= -180 and angle <= 180): + return angle + + # convert it otherwise + + # check if it is positive or negative + # and set the opposite direction of the angle + # if the angle is > 0 then its mesurement is clockwise (opposite is counter-clockwise) + # if the angle is < 0 then its mesurement is counter-clockwise (opposite is clockwise) + if (angle > 0): + opposite_spin_dir = -1 + else: # it is negative + opposite_spin_dir = 1 + + # decrease the angle by 360 degrees until it + # is in the -180/+180 degree interval + while (abs(angle) > 180): + angle = angle + (opposite_spin_dir * 360) + + return angle +# + + +############################################################### +# convert_anim_rot_to_180 function +# used to re-calculate a rotation animation on an axis +# so that angles used lay in between -180/180 degrees +# done to avoid rotation animation data loss when extracting +# said angles from a transformation matrix +# this function calls the convert_angle_to_180() function +# at the end of the function csv_keyframe_numbers is updated +# with the new frames to be injected into the animation +# +# example: +# +# Original keyframes: +# Frame 0 Frame 21 (2 keyframes) +# 0º 360º +# +# Processed keyframes: +# Frame 0 Frame 10 Frame 11 Frame 21 (4 keyframes) +# 0º 171.4º -171.5º 0º +# +# rot_array (array of floats) --> bone rotation animation data +# for a single axis +# csv_keyframe_numbers (array of ints) --> original keyframes +# of the animation +# +# Note: function will have problems interpreting keyframes with +# high rotation diferences if the number of frames in +# between said keyframes in lower than 2 times the spins +# done in between those keyframe angles (thinking a fix) +############################################################### +def convert_rot_anim_to_180(rot_array, csv_keyframe_numbers): +# + # temp rot array to store calculated values and keyframe position + rot_array_cp = [[], []] + + # find the frames in which rot_array has values defined + rot_array_kf = [] + for i in range(len(rot_array)): + if (rot_array[i] != None): + rot_array_kf.append(i) + + ########################################################################### + # loop through each consecutive pair of keyframes of the rot_array_kf array + for i in range(len(rot_array_kf) - 1): + # + # get left/right keyframe values and positions + l_kf_pos = rot_array_kf[i] + l_kf_val = rot_array[l_kf_pos] + r_kf_pos = rot_array_kf[i + 1] + r_kf_val = rot_array[r_kf_pos] + + # append l_kf_val to rot_array_cp (converted) + rot_array_cp[0].append(l_kf_pos) + rot_array_cp[1].append(convert_angle_to_180(l_kf_val)) + + # get the rotation direction + if (r_kf_val > l_kf_val): # clockwise + rot_direction = 1 + else: # counter-clockwise + rot_direction = -1 + + ############################################################## + # advance -180/+180 (depending on the rotation direction) + # and generate the middle keyframe values + # angle is fixed to the l_kf_val's closest 360 degree multiple + angle_val = l_kf_val - convert_angle_to_180(l_kf_val) + while (abs(r_kf_val - angle_val) > 180): + # + angle_val = angle_val + (rot_direction * 180) + + # find the frame (float) in which this value exists + angle_pos = interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, None, angle_val, "linear") + + ############################################ + # find the 2 frames (integer) that are lower + # and upper limits of this angle_pos + lower_frame = int(angle_pos) + upper_frame = int(angle_pos + 1) + + ############################################################### + # interpolate to find the values on lower_frame and upper_frame + lower_frame_value = convert_angle_to_180(interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, lower_frame, None, "linear")) + upper_frame_value = convert_angle_to_180(interpolate(l_kf_pos, l_kf_val, r_kf_pos, r_kf_val, upper_frame, None, "linear")) + + ################################ + # append results to rot_array_cp + + # keyframes + rot_array_cp[0].append(lower_frame) + rot_array_cp[0].append(upper_frame) + # values + rot_array_cp[1].append(lower_frame_value) + rot_array_cp[1].append(upper_frame_value) + # + # + + ########################################## + # add the new keyframe values to rot_array + # on their respective frame position + for i in range(len(rot_array_cp[0])): + rot_array[rot_array_cp[0][i]] = rot_array_cp[1][i] + + ####################################################### + # update the keyframes on csv_keyframe_numbers to store + # the calculated keyframes numbers from rot_array_cp[0] + # append those at the end of csv_keyframe_numbers + for i in range(len(rot_array_cp[0])): + value_found = False + for j in range(len(csv_keyframe_numbers)): + if (rot_array_cp[0][i] == csv_keyframe_numbers[j]): + value_found = True + break + if (value_found == False): + csv_keyframe_numbers.append(rot_array_cp[0][i]) +# |