Scripted keyframes and bezier curve movement.

scripting keyframes isn’t too difficult, maybe a little weird at first. Luckily the rotobezier addon seems to have paved the way for us mortals :slight_smile:


 Obj = context.active_object
        
        Mode = False
        if context.mode != 'OBJECT':
            Mode = not Mode
            bpy.ops.object.editmode_toggle()
        Data = Obj.data
        
        for Spline in Data.splines:
            if Spline.type == 'BEZIER':
                for CV in Spline.bezier_points:
                    if context.window_manager.key_points:
                        CV.keyframe_insert('co')
                        CV.keyframe_insert('handle_left')
                        CV.keyframe_insert('handle_right')
                    if context.window_manager.key_radius:
                        CV.keyframe_insert('radius')
                    if context.window_manager.key_tilt:
                        CV.keyframe_insert('tilt')
                    
            elif Spline.type == 'NURBS':
                for CV in Spline.points:
                    if context.window_manager.key_points:
                        CV.keyframe_insert('co')
                    if context.window_manager.key_radius:
                        CV.keyframe_insert('radius')
                    if context.window_manager.key_tilt:
                        CV.keyframe_insert('tilt')

so the most basic form of scripted keyframing would be something like this :



import bpy
from mathutils import Vector

# initial state
listOfVectors = [((0,0,0,1)),((1,0,0,1)),((1,1,0,1)),((0,1,0,1))]

# all states.
shapes = [  [((0,0,0,1)),((1,0,0,1)),((1,1,0,1)),((0,1,0,1))],
            [((0,0,0,1)),((2,0,0,1)),((1,1,0,1)),((0,1,0,1))],
            [((0,0,0,1)),((1,0,0,1)),((1,2,0,1)),((0,1,0,1))],
            [((0,0,0,1)),((1,0,0,1)),((1,1,0,1)),((-1,1,0,1))]
            ]


def print_divider():
    print()
    print("="*40)

            
# turn tuple list into vector list.
def vectorize_list(shapes):
    shapes_as_vectors = []
    for shape in shapes:
        shape_points = []
        for i in shape:
            shape_points.append(Vector(i))
        shapes_as_vectors.append(shape_points)    
    return shapes_as_vectors



# create a spline curve from a number of points
def MakePolyFace(objname, curvename, cList):
    curvedata = bpy.data.curves.new(name=curvename, type='CURVE')
    curvedata.dimensions = '2D'

    objectdata = bpy.data.objects.new(objname, curvedata)
    objectdata.location = (0,0,0) #object origin
    bpy.context.scene.objects.link(objectdata)

    polyline = curvedata.splines.new('POLY')
    polyline.points.add(len(cList)-1)

    for num in range(len(cList)):
        polyline.points[num].co = (cList[num])
        
    polyline.order_u = len(polyline.points)-1  
    polyline.use_endpoint_u = True
    polyline.use_cyclic_u = True 


MakePolyFace("NameOfMyCurveObject", "NameOfMyCurve", listOfVectors)

# set shape to active, and select it
bpy.context.scene.objects.active = bpy.data.objects["NameOfMyCurveObject"]
polyface = bpy.context.active_object
polyface.select = True


bpy.ops.object.mode_set(mode = 'EDIT')
shapes = vectorize_list(shapes)

frame_num = 0

Spline = polyface.data.splines[0]
for shape in shapes:
    bpy.context.scene.frame_set(frame_num)
    iterator = 0
    for coord in Spline.points:
        coord.co = shape[iterator]
        coord.keyframe_insert('co')
    
        iterator += 1 
    
    frame_num += 1

please excuse the hodge-podge of it all.

explanation :
This places a keyframe for each coordinate of a ‘POLY’ curve, here i’ve given it 4 different states on 4 consecutive frames.

the import now creates shapes and keyframes them according to their frame data. still a bit rough but it’s a start! https://github.com/zeffii/AE--afterfx--Mocha-shape-import

So, i’m not very confident in my ability to approximate an XSpline under all conditions described here. BSpline should be pretty straightforward.

Wow, thanks for sharing! I should probably try them out! :stuck_out_tongue: