auto_walk/OP_setup_curve_a_to_b.py

119 lines
4.0 KiB
Python

import bpy, re
from . import fn
## step 1 : Create the curve
# need to determine a specific acceleration envelope factor to go to end of curve
# (set on curves)
def remove_spacetime_keys(context=None):
if not context:
context = bpy.context
# remove all spacetime markers and walk collection
col_name = 'walk_markers'
walk_col = context.scene.collection.children.get(col_name)
if walk_col:
for o in reversed(walk_col.objects):
if o.name.startswith('spacetime_marker_'):
bpy.data.objects.remove(o)
bpy.data.collections.remove(walk_col)
class AW_OT_create_a_b_step(bpy.types.Operator):
bl_idname = "autowalk.create_a_b_step"
bl_label = "Create Two Points Curve"
bl_description = "Create a straight curve between two defined position and time"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
# first time ops is launched just set an empty (with market time)
# second time (if a mark empty exists determine a AB path to set curve)
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def create_marker(self, context):
m_name = f'spacetime_marker_{context.scene.frame_current}'
mark = bpy.data.objects.new(m_name, None)
mark.location = self.position
mark.empty_display_size = 2
self.walk_col.objects.link(mark)
return mark
def execute(self, context):
ob = context.object
prefs = fn.get_addon_prefs()
root_name = prefs.tgt_bone
root = ob.pose.bones.get(root_name)
self.position = (ob.matrix_world @ root.matrix).to_translation()
col_name = 'walk_markers'
self.walk_col = fn.get_col(col_name, create=True) # link in scene collection by default
markers = [o for o in self.walk_col.objects if o.type == 'EMPTY' and o.name.startswith('spacetime_marker_')]
if not markers:
self.create_marker(context)
return {"FINISHED"}
# Create the second marker and append to marker list
markers.append(self.create_marker(context))
markers.sort(key=lambda x: x.name) # sort by time (frame written in name)
a = markers[0].location
b = markers[1].location - a # remove a postion to get position in curve object space
a_frame = int(markers[0].name.split('_')[-1])
b_frame = int(markers[1].name.split('_')[-1])
# Set the curve and constraint
curve = fn.generate_curve(location=a, direction=b, name='curve_path', context=context)
settings = context.scene.anim_cycle_settings
settings.path_to_follow = curve
fn.create_follow_path_constraint(ob, curve)
# refresh evaluation so constraint shows up correctly
bpy.context.scene.frame_set(bpy.context.scene.frame_current)
# set offset animation ??? (but movement not in sync until action is retimed in NLA)
## remove all markers or keep for later reuse ?
remove_spacetime_keys(context=None)
# if speed calculation is done later need to know start and end frame...
# Set frame start and end
settings.start_frame = a_frame
settings.end_frame = b_frame
return {"FINISHED"}
class AW_OT_remove_a_b_step(bpy.types.Operator):
bl_idname = "autowalk.remove_a_b_step"
bl_label = "Remove First Position"
bl_description = "remove first point defining step"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
# Define what is first and last according to time
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
remove_spacetime_keys(context=None)
return {"FINISHED"}
classes=(
AW_OT_create_a_b_step,
AW_OT_remove_a_b_step,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
# if __name__ == "__main__":
# register()