initial code for follow curve

This commit is contained in:
Pullusb
2022-11-04 18:45:37 +01:00
parent 4622aa4520
commit 336d1b264c
4 changed files with 222 additions and 3 deletions
+145
View File
@@ -956,3 +956,148 @@ def iterate_selector(zone, attr, state, info_attr = None, active_access='active'
info = getattr(active_item, info_attr)
return info, bottom
# -----------------
### Curve handle
# -----------------
def create_curve(location=(0,0,0), direction=(1,0,0), name='curve_path', enter_edit=True, context=None):
'''Create curve at provided location and direction vector'''
## option to create nurbs instaed of bezier ?
context = context or bpy.context
## using ops (dirty)
# bpy.ops.curve.primitive_bezier_curve_add(radius=1, enter_editmode=enter_edit, align='WORLD', location=location, scale=(1, 1, 1))
# curve = context.object
# curve.name = 'curve_path'
# # fast straighten
# bpy.ops.curve.handle_type_set(type='VECTOR')
# bpy.ops.curve.handle_type_set(type='ALIGNED')
# bpy.ops.transform.translate(value=(1, 0, 0), orient_type='LOCAL',
# orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='LOCAL',
# constraint_axis=(True, False, False), mirror=True, use_proportional_edit=False)
## using data
curve_data = bpy.data.curves.new(name, 'CURVE') # ('CURVE', 'SURFACE', 'FONT')
curve_data.dimensions = '3D'
curve_data.use_path = True
curve = bpy.data.objects.new(name, curve_data)
spl = curve_data.splines.new('BEZIER') # ('POLY', 'BEZIER', 'NURBS')
spl.bezier_points.add(1) # One point already exists
for i in range(2):
spl.bezier_points[i].handle_left_type = 'VECTOR' # ('FREE', 'VECTOR', 'ALIGNED', 'AUTO')
spl.bezier_points[i].handle_right_type = 'VECTOR'
spl.bezier_points[1].co = direction
# Back to aligned mode
for i in range(2):
spl.bezier_points[i].handle_right_type = spl.bezier_points[i].handle_left_type = 'ALIGNED'
# Select second point
spl.bezier_points[1].select_control_point = True
spl.bezier_points[1].select_left_handle = True
spl.bezier_points[1].select_right_handle = True
# link
context.scene.collection.objects.link(curve)
# curve object settings
curve.location = location
curve.show_in_front = True
# enter edit
if enter_edit and context.mode == 'OBJECT':
curve.select_set(True)
context.view_layer.objects.active = curve
bpy.ops.object.mode_set(mode='EDIT', toggle=False) # EDIT_CURVE
## set viewport overlay visibility for better view
if context.space_data.type == 'VIEW_3D':
context.space_data.overlay.show_curve_normals = True
context.space_data.overlay.normals_length = 0.2
return curve
def get_direction_vector_from_enum(string) -> Vector:
orient_vectors = {
'FORWARD_X' : Vector((1,0,0)),
'FORWARD_Y' : Vector((0,1,0)),
'FORWARD_Z' : Vector((0,0,1)),
'TRACK_NEGATIVE_X' : Vector((-1,0,0)),
'TRACK_NEGATIVE_Y' : Vector((0,-1,0)),
'TRACK_NEGATIVE_Z' : Vector((0,0,-1))
}
return orient_vectors[string]
def orentation_track_from_vector(input_vector) -> str:
'''return closest world track orientation name from passed vector direction'''
orient_vectors = {
'FORWARD_X' : Vector((1,0,0)),
'FORWARD_Y' : Vector((0,1,0)),
'FORWARD_Z' : Vector((0,0,1)),
'TRACK_NEGATIVE_X' : Vector((-1,0,0)),
'TRACK_NEGATIVE_Y' : Vector((0,-1,0)),
'TRACK_NEGATIVE_Z' : Vector((0,0,-1))
}
orient = None
min_angle = 10000
for track, v in orient_vectors.items():
angle = input_vector.angle(v)
if angle < min_angle:
min_angle = angle
orient = track
return orient
def create_follow_path_constraint(ob, curve, follow_curve=False):
'''return create constraint'''
# # Clear bone follow path constraint
exiting_fp_constraints = [c for c in ob.constraints if c.type == 'FOLLOW_PATH']
for c in exiting_fp_constraints:
ob.constraints.remove(c)
# loc = ob.matrix_world @ ob.matrix.to_translation()
if ob.location != (0,0,0):
old_loc = ob.location
ob.location = (0,0,0)
print(f'ob moved from {old_loc} to (0,0,0) to counter follow curve offset')
const = ob.constraints.new('FOLLOW_PATH')
const.target = curve
if follow_curve:
const.use_curve_follow = True
return const
## on_bones:
# prefs = get_addon_prefs()
# root_name = prefs.tgt_bone
# root = ob.pose.bones.get(root_name)
# if not root:
# return ('ERROR', f'posebone {root_name} not found in armature {ob.name} check addon preferences to change name')
# # Clear bone follow path constraint
# exiting_fp_constraints = [c for c in root.constraints if c.type == 'FOLLOW_PATH']
# for c in exiting_fp_constraints:
# root.constraints.remove(c)
# # loc = ob.matrix_world @ root.matrix.to_translation()
# if root.name == ('world', 'root') and root.location != (0,0,0):
# old_loc = root.location
# root.location = (0,0,0)
# print(f'root moved from {old_loc} to (0,0,0) to counter follow curve offset')
# const = root.constraints.new('FOLLOW_PATH')
# const.target = curve
# # axis only in this case, should be in addon to prefs
# ## determine which axis to use... maybe found orientation in world space from matrix_basis ?
# root_world_base_direction = root.bone.matrix_local @ get_direction_vector_from_enum(bpy.context.scene.anim_cycle_settings.forward_axis)
# const.forward_axis = orentation_track_from_vector(root_world_base_direction) # 'TRACK_NEGATIVE_Y' # bpy.context.scene.anim_cycle_settings.forward_axis # 'FORWARD_X'
# print('const.forward_axis: ', const.forward_axis)
# const.use_curve_follow = True
# return curve, const