Bake Motion Path

Hi, this is a script to easily get a 3D path from an object’s animation.
It’s just like baking the Motion Path. You can then modify the curve and load it again as a constraint, or maybe create a new object…

In C4D you are able to edit the animations as a path, directly in the viewport, and so in AE, well at least the position data… anyway, here’s my noob attempt to do something ‘similar’. It will add a point every frame through the playback range, like the Motion path does. You can change this at the beginning of the script.


import bpy
scene = bpy.context.scene

# step / start / end
paso = 1
inicio = scene.frame_start
fin = scene.frame_end
actual = scene.frame_current
puntos = list(range(inicio - 1, fin, paso))

recorrido = bpy.data.curves.new('recorrido','CURVE')
curva = bpy.data.objects.new('curva',recorrido)
bpy.context.scene.objects.link(curva)
recorrido.dimensions = '3D'
recorrido.use_fill_back = False
recorrido.use_fill_front = False
spline = recorrido.splines.new('BEZIER')
spline.bezier_points.add(len(puntos) - 1)

c = 0
ob = bpy.context.object

for n in puntos:
    scene.frame_set(n)
    matrix = ob.matrix_world.copy()
    nodo = spline.bezier_points[c]
    nodo.co = tuple(matrix.translation_part())
    nodo.handle_right_type='VECTOR'
    nodo.handle_left_type='VECTOR'
    c += 1

scene.frame_set(actual)

Cool, i was going to write something like this too. Will try it out soon, thanks!

I just try your script and it returned :
line 27 : ‘mathutils.Matrix’ objet has no attributs ‘translation_part’

do you have an example file plz ?

thx

this should work, but as this is an old script i will check again later…
anyway there is a new addon by Bart Crouch to do this the right way!

import bpy
scene = bpy.context.scene

step = 1
start = scene.frame_start
end = scene.frame_end
actual = scene.frame_current
puntos = list(range(start - 1, end, step))

recorrido = bpy.data.curves.new('recorrido','CURVE')
curva = bpy.data.objects.new('curva',recorrido)
bpy.context.scene.objects.link(curva)
recorrido.dimensions = '3D'
spline = recorrido.splines.new('BEZIER')
spline.bezier_points.add(len(puntos) - 1)

c = 0
ob = bpy.context.object

for n in puntos:
    scene.frame_set(n)
    matrix = ob.matrix_world.copy()
    nodo = spline.bezier_points[c]
    nodo.co = matrix.to_translation()
    nodo.handle_right_type='VECTOR'
    nodo.handle_left_type='VECTOR'
    c += 1

scene.frame_set(actual)

coooooooooool !
it works like a charm, bravo et merci !

update for 2.56?

This is really helpful, thanks.

nvm - works with newer SVN build. thanks!

you can get data from Blender’s calculated path -if the path exists- so script would be even simpler:


import bpy
ob = bpy.context.object
mp = ob.motion_path

if mp:
    path = bpy.data.curves.new('path','CURVE')
    curve = bpy.data.objects.new('Curve',path)
    bpy.context.scene.objects.link(curve)
    path.dimensions = '3D'
    spline = path.splines.new('BEZIER')
    spline.bezier_points.add(len(mp.points)-1)
    
    for x in range(len(mp.points)):
        o = spline.bezier_points[x]
        o.co = mp.points[x].co
        o.handle_right_type = 'AUTO'
        o.handle_left_type = 'AUTO'

change ‘AUTO’ to ‘VECTOR’ if that works better for you… have fun

I figured it would be fairly trivial, since the curve is already there.

Thanks.

Thank you so much liero!!! I was trying to find something like this to recreate a Tron Lightwall, so thank you for the script.

This is an awesome script, Liero! Thank you so much. It’s still helping people in 2018! A couple suggestions that could be great to expand this script would be the following:

  1. Have the script set the new curve’s origin to be the motion path object’s starting location (on the motion path’s start frame).

  2. The ability to overwrite a previous curve and maintain its name. This would be super useful: first select the object with an active motion path. Then shift-select the curve you want to overwrite. Run the script. The script will delete the old curve, create a new curve from the motion path, and use the name of the old curve. :slight_smile:

Thank you so much again for this incredibly useful tool. BTrace, though a great addon, currently will not trace the motion of an object if the motion is generated from a parent object, so your script is still the best solution for my intended usage. https://developer.blender.org/T53912 :slight_smile:

here is an blender 2.8x updated version

import bpy
ob = bpy.context.object
mp = ob.motion_path

if mp:
    path = bpy.data.curves.new('path','CURVE')
    curve = bpy.data.objects.new('Curve',path)
    bpy.context.scene.collection.objects.link(curve)
    path.dimensions = '3D'
    spline = path.splines.new('BEZIER')
    spline.bezier_points.add(len(mp.points)-1)
    
    for x in range(len(mp.points)):
        o = spline.bezier_points[x]
        o.co = mp.points[x].co
        o.handle_right_type = 'AUTO'
        o.handle_left_type = 'AUTO'
1 Like

Here’s an updated 2.8 version:
-works on every selected objects
-generate and kill the motion path (you have nothing to do before launching the script)
-generate a curve named based on the source object name + “_Path”
-based on the scene start and end frame

import bpy
scene = bpy.context.scene
start = scene.frame_start
end = scene.frame_end

sel = bpy.context.selected_objects

for ob in sel:
    #ob = bpy.context.object
    

    bpy.ops.object.paths_calculate(start_frame=start, end_frame=end)
    mp = ob.motion_path
    if mp:
        path = bpy.data.curves.new('path','CURVE')
        
        curve = bpy.data.objects.new('Curve',path)
        curve.name = ob.name+"_Path"
        bpy.context.scene.collection.objects.link(curve)
        path.dimensions = '3D'
        spline = path.splines.new('BEZIER')
        spline.bezier_points.add(len(mp.points)-1)
        
        for x in range(len(mp.points)):
            o = spline.bezier_points[x]
            o.co = mp.points[x].co
            o.handle_right_type = 'AUTO'
            o.handle_left_type = 'AUTO'

    bpy.ops.object.paths_clear()