From eb1592468ead076e0a9762add2eb36f098389654 Mon Sep 17 00:00:00 2001 From: raccoon Date: Sun, 16 Mar 2025 19:59:52 +0500 Subject: [PATCH] Blender driver functions for animation bake --- blender_driver_func.py | 80 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 blender_driver_func.py diff --git a/blender_driver_func.py b/blender_driver_func.py new file mode 100644 index 0000000..d035cb2 --- /dev/null +++ b/blender_driver_func.py @@ -0,0 +1,80 @@ +from mathutils import * +from math import * +import bpy + + +def angle_to_length(angle: float, target: float = 1.0) -> float: + """ + Converts input angle to distance between two points in imaginary isosceles triangle with default angle of 180deg(!). + The distance is clamped to the target value. + + :param angle: Input angle (in radians) + :type angle: float + :param target: Desired distance between end points, defaults to 1.0 + :type target: float, optional + :return: The distance between two points + :rtype: float + """ + if angle > 0: + return (target * 0.5 * sin(pi - angle)) / sin(angle * 0.5) # School trigonometry + else: + return target + + +def half_angle_to_length(angle: float, target: float = 1.0) -> float: + """ + Converts input angle to distance between two points in imaginary isosceles triangle with default angle of 90deg. + The distance is clamped to the target value. + + :param angle: Input angle (in radians) + :type angle: float + :param target: Desired distance between end points, defaults to 1.0 + :type target: float, optional + :return: The distance between two points + :rtype: float + """ + side = sqrt(pow(target, 2) * 0.5) # Length of imaginary triangle's side + angle = abs(pi * 0.5 - angle) # Default angle is 90deg + return (side * sin(angle)) / sin((pi - angle) * 0.5) + + +def angle_compensation(angle: float) -> float: + side_len = sqrt(pow(pi * 0.5, 2) * 0.5) # Length of imaginary triangle's side + distance = 0.5 # Distance to which move bone to + + angle = abs(pi - angle) + + # Compensate non-linear input angle + if angle > 0: + comp_angle = (side_len * 0.5 * sin(angle)) / sin(angle * 0.5) + else: + comp_angle = side_len + + return (sqrt(pow(tan(comp_angle), 2) + 1) - 1) * distance + + +def half_angle_compensation(angle: float) -> float: + side = sqrt(pow(pi * 0.25, 2) * 0.5) # Length of imaginary triangle's side + angle = abs(angle) + final_angle = (side * sin(angle)) / sin((pi - angle) * 0.5) # Width of imaginary triangle's base + return sqrt(pow(tan(final_angle), 2) + 1) - 1 # What the fuck?? + + +def test_compensation(angle: float) -> float: + side = sqrt(pow(pi * 0.5, 2) * 0.5) # Triangle's side is now a desired output angle in radians + angle = abs(pi - angle) # Rotate default angle to 180deg + return angle_to_length(angle, side) + + +def test_half_compensation(angle: float) -> float: + side = pi * 0.25 + angle = abs(pi * 0.5 + angle) # Rotate default angle to 90deg + return half_angle_to_length(angle, side) + + +bpy.app.driver_namespace["angle_to_length"] = angle_to_length +bpy.app.driver_namespace["half_angle_to_length"] = half_angle_to_length +bpy.app.driver_namespace["angle_compensation"] = angle_compensation +bpy.app.driver_namespace["half_angle_compensation"] = half_angle_compensation +bpy.app.driver_namespace["test_compensation"] = test_compensation +bpy.app.driver_namespace["test_half_compensation"] = test_half_compensation