first step spline animation

This commit is contained in:
jrkb 2025-06-04 21:28:08 +02:00
parent 7de8fcc5d1
commit 58e0df3427
2 changed files with 152 additions and 4 deletions

View file

@ -2040,13 +2040,27 @@ def on_depsgraph_update(scene, depsgraph):
elif butils.is_text_object_legit(u.id.original): elif butils.is_text_object_legit(u.id.original):
# must be duplicate # must be duplicate
link_text_object_with_new_text_properties(u.id.original, scene) link_text_object_with_new_text_properties(u.id.original, scene)
# butils.prepare_text(
# text_properties.font_name,
# text_properties.face_name,
# text_properties.text,
# )
elif ( elif (
butils.is_text_object_legit(u.id.original) butils.is_text_object_legit(u.id.original)
and len(u.id.original.users_collection) > 0 and len(u.id.original.users_collection) > 0
): ):
# must be a new thing, maybe manually created or so # must be a new thing, maybe manually created or so
link_text_object_with_new_text_properties(u.id.original, scene) link_text_object_with_new_text_properties(u.id.original, scene)
# butils.prepare_text(
# text_properties.font_name,
# text_properties.face_name,
# text_properties.text,
# )
butils.clean_text_properties() butils.clean_text_properties()
try:
butils.set_text_on_curve(text_properties)
except:
pass
update_active_text_index() update_active_text_index()
unlock_depsgraph_updates() unlock_depsgraph_updates()

142
butils.py
View file

@ -217,6 +217,118 @@ def calc_bezier_length(bezier_point_1, bezier_point_2, resolution=20):
return length return length
def get_hook_modifiers(blender_object: bpy.types.Object):
return [m for m in blender_object.modifiers if m.type == "HOOK"]
class BezierSplinePoint:
def __init__(
self,
co: mathutils.Vector,
handle_left: mathutils.Vector,
handle_right: mathutils.Vector,
):
self.co: mathutils.Vector = co
self.handle_left: mathutils.Vector = handle_left
self.handle_right: mathutils.Vector = handle_right
class BezierSpline:
def __init__(
self,
n: int,
use_cyclic_u: bool,
resolution_u: int,
):
self.bezier_points = [BezierSplinePoint] * n
self.use_cyclic_u: int = use_cyclic_u
self.resolution_u: int = resolution_u
self.beziers: []
self.lengths: [float]
self.total_length: float
def calc_length(self, resolution) -> float:
# ignore resolution when accessing length to imitate blender function
print(f"{self.total_length=}")
return self.total_length
class BezierData:
def __init__(self, n):
self.splines = [BezierSpline] * n
class BezierCurve:
def __init__(self, blender_curve: bpy.types.Object, resolution_factor=1.0):
self.data = BezierData(len(blender_curve.data.splines))
i = 0
hooks = get_hook_modifiers(blender_curve)
print(f"{blender_curve.name=} =============================================")
for si, blender_spline in enumerate(blender_curve.data.splines):
self.data.splines[si] = BezierSpline(
len(blender_spline.bezier_points),
blender_spline.use_cyclic_u,
blender_spline.resolution_u,
)
for pi, blender_bezier_point in enumerate(blender_spline.bezier_points):
self.data.splines[si].bezier_points[pi] = BezierSplinePoint(
blender_bezier_point.co,
blender_bezier_point.handle_left,
blender_bezier_point.handle_right,
)
print(pi)
for hook in hooks:
hook_co = False
hook_handle_left = False
hook_handle_right = False
for vi in hook.vertex_indices:
if vi == i * 3:
hook_handle_left = True
elif vi == i * 3 + 1:
hook_co = True
elif vi == i * 3 + 2:
hook_handle_right = True
if hook_co:
location = (
blender_curve.matrix_world.inverted()
@ hook.object.matrix_world.translation
)
print(f"co {location=}")
self.data.splines[si].bezier_points[pi].co = (
self.data.splines[si]
.bezier_points[pi]
.co.lerp(location, hook.strength)
)
# if hook_handle_left:
# location = (
# hook.object.matrix_world.translation
# - blender_curve.matrix_world.translation
# ) + mathutils.Vector((-1, 0, 0))
# print(f"handle_left {location=}")
# self.data.splines[si].bezier_points[pi].handle_left = (
# self.data.splines[si]
# .bezier_points[pi]
# .handle_left.lerp(location, hook.strength)
# )
# if hook_handle_right:
# location = (
# hook.object.matrix_world.translation
# - blender_curve.matrix_world.translation
# )
# self.data.splines[si].bezier_points[pi].handle_right = (
# self.data.splines[si]
# .bezier_points[pi]
# .handle_right.lerp(location, hook.strength)
# )
i += 1
(
self.data.splines[si].beziers,
self.data.splines[si].lengths,
self.data.splines[si].total_length,
) = get_real_beziers_and_lengths(self.data.splines[si], resolution_factor)
print(f"total length {self.data.splines[si].total_length}")
def get_real_beziers_and_lengths(bezier_spline_obj, resolution_factor): def get_real_beziers_and_lengths(bezier_spline_obj, resolution_factor):
beziers = [] beziers = []
lengths = [] lengths = []
@ -277,8 +389,14 @@ def calc_point_on_bezier_spline(
# if the bezier points sit on each other we have same issue # if the bezier points sit on each other we have same issue
# but that is then to be fixed in the bezier # but that is then to be fixed in the bezier
if p.handle_left == p.co and len(bezier_spline_obj.bezier_points) > 1: if p.handle_left == p.co and len(bezier_spline_obj.bezier_points) > 1:
beziers, lengths, total_length = get_real_beziers_and_lengths( beziers, lengths, total_length = (
bezier_spline_obj, resolution_factor get_real_beziers_and_lengths(bezier_spline_obj, resolution_factor)
if not isinstance(bezier_spline_obj, BezierSpline)
else (
bezier_spline_obj.beziers,
bezier_spline_obj.lengths,
bezier_spline_obj.total_length,
)
) )
travel_point = calc_point_on_bezier(beziers[0][1], beziers[0][0], 0.001) travel_point = calc_point_on_bezier(beziers[0][1], beziers[0][0], 0.001)
travel = travel_point.normalized() * distance travel = travel_point.normalized() * distance
@ -291,8 +409,14 @@ def calc_point_on_bezier_spline(
else: else:
return location return location
beziers, lengths, total_length = get_real_beziers_and_lengths( beziers, lengths, total_length = (
bezier_spline_obj, resolution_factor get_real_beziers_and_lengths(bezier_spline_obj, resolution_factor)
if not isinstance(bezier_spline_obj, BezierSpline)
else (
bezier_spline_obj.beziers,
bezier_spline_obj.lengths,
bezier_spline_obj.total_length,
)
) )
iterated_distance = 0 iterated_distance = 0
@ -336,6 +460,8 @@ def calc_point_on_bezier_curve(
output_spline_index=False, output_spline_index=False,
resolution_factor=1.0, resolution_factor=1.0,
): ):
# bezier_curve = BezierCurve(bezier_curve_obj)
# curve = bezier_curve.data
curve = bezier_curve_obj.data curve = bezier_curve_obj.data
# Loop through all splines in the curve # Loop through all splines in the curve
@ -343,6 +469,7 @@ def calc_point_on_bezier_curve(
for i, spline in enumerate(curve.splines): for i, spline in enumerate(curve.splines):
resolution = int(spline.resolution_u * resolution_factor) resolution = int(spline.resolution_u * resolution_factor)
length = spline.calc_length(resolution=resolution) length = spline.calc_length(resolution=resolution)
print(f"{utils.LINE()} {length=}")
if total_length + length > distance or i == len(curve.splines) - 1: if total_length + length > distance or i == len(curve.splines) - 1:
if output_spline_index and output_tangent: if output_spline_index and output_tangent:
# return value from c_p_o_b_s is a tuple # return value from c_p_o_b_s is a tuple
@ -1704,7 +1831,11 @@ def set_text_on_curve(
# global lock_depsgraph_update_n_times # global lock_depsgraph_update_n_times
# starttime = time.perf_counter_ns() # starttime = time.perf_counter_ns()
if text_properties is None:
return False
mom = text_properties.text_object mom = text_properties.text_object
if mom is None:
return False
if mom.type != "CURVE": if mom.type != "CURVE":
return False return False
if len(mom.users_collection) < 1: if len(mom.users_collection) < 1:
@ -1812,6 +1943,9 @@ def set_text_on_curve(
location, tangent, spline_index = calc_point_on_bezier_curve( location, tangent, spline_index = calc_point_on_bezier_curve(
mom, applied_advance, True, True mom, applied_advance, True, True
) )
# location, tangent, spline_index = calc_point_on_bezier_curve(
# mom_hooked, applied_advance, True, True
# )
# check if we are on a new line # check if we are on a new line
if spline_index != previous_spline_index: if spline_index != previous_spline_index: