4

I have a animation where one object moves through the 3D space. How can I get the location of this object which it has at a specific frame?

I tried something like this:

obj = bpy.context.active_object
ol = obj.location

# set current frame to 1
bpy.context.scene.frame_current = 1

pos_1 = (ol.x, ol.y, ol.z)

# set current frame to 5
bpy.context.scene.frame_current = 5
pos_5 = (ol.x, ol.y, ol.z)

# set current frame to 10
bpy.context.scene.frame_current = 10
pos_10 = (ol.x, ol.y, ol.z)

# set current frame back to 1
bpy.context.scene.frame_current = 1

print('Frame 1 {0}, id: {1}'.format(pos_1, id(pos_1)))
print('Frame 5 {0}, id: {1}'.format(pos_5, id(pos_5)))
print('Frame 10 {0}, id: {1}'.format(pos_10, id(pos_10)))

But the output for all Frames is the same except for the id's. So, how can I get the position of an object at a specific frame?

Miguellissimo
  • 1,355
  • 2
  • 16
  • 29

2 Answers2

7

Try using frame_set() instead of directly setting the current frame:

import bpy

obj = bpy.context.active_object
ol = obj.location

# set current frame to 1
bpy.context.scene.frame_set(1)

pos_1 = (ol.x, ol.y, ol.z)

# set current frame to 5
bpy.context.scene.frame_set(5)
pos_5 = (ol.x, ol.y, ol.z)

# set current frame to 10
bpy.context.scene.frame_set(10)
pos_10 = (ol.x, ol.y, ol.z)

# set current frame back to 1
bpy.context.scene.frame_set(1)

print('Frame 1 {0}, id: {1}'.format(pos_1, id(pos_1)))
print('Frame 5 {0}, id: {1}'.format(pos_5, id(pos_5)))
print('Frame 10 {0}, id: {1}'.format(pos_10, id(pos_10)))

Directly setting the current frame does not update all the animated values and re-evaluate drivers, etc. so the object position is not updated.
Using frame_set() will update everything, so the location is printed as expected.

gandalf3
  • 157,169
  • 58
  • 601
  • 1,133
1

The "cleanest" answer is to look into the obj.animation_data.action.fcurves list to find the ones with data_path=="location" and use

loc[fc.array_index] = fc.evaluate(frame)

to evaluate them. Things get tricker if you have NLAs or drivers. It makes me wish the animation_data property had an evaluate(data_path, frame) method.

Then again, you might be able to just bpy.context.scene.update() after each frame_current= in your original version.

Mutant Bob
  • 9,243
  • 2
  • 29
  • 55
  • When I look into obj.animation_data.action.fcurves list I find multiple items with data_path == 'location'. It seems that for each channel (x, y, z) there is one item in the list. Is there a way to distinguish which channel corresponds to which axes? – Miguellissimo Aug 07 '14 at 21:43
  • Yes, you distinguish them using fc.array_index. I guess I didn't explain why I did that in my code example. – Mutant Bob Aug 08 '14 at 14:45
  • 3
    Cleanest depends on your purpose, While fast and useful in some cases - this wont take a lot of things into account, Parenting, constraints, drivers, physics sim. – ideasman42 Aug 08 '14 at 16:44