1
$\begingroup$

Hey there Blender Community,

I'm trying to figure out the optimal way to use Blender's physics engine to perform simulations and access the information from each frame of the simulation for various other purposes. The idea, ultimately, is to be able to loop through the frames of the animation once the simulation is complete and get information about an object's location, for example, after a rigid body collision.

I was able to successfully accomplish something like this with the following method:

def analyze_scene():
    scene = bpy.data.scenes['Scene'].frame_end
    object = bpy.data.objects[object]
    frameInfo = []
    for frame in range(1, scene.frame_end):
        scene.frame_current = frame
        bpy.ops.ptcache.bake_all(bake=False)
        frameInfo.append({"name": object.name, "frame": frame,
            "translation": object.matrix_world.translation})

    return frameInfo

(Note: There may be an error in this code, but it's just an outline of what I'm doing).

The issue with this is having to call "update all to frame" (bake_all) with every frame. Is there a better way of doing this that isn't so computationally expensive? I've experimented with Scene.update() to no avail.

My thanks in advance for any assistance.

$\endgroup$
3
$\begingroup$

You don't need to call bpy.ops.ptcache.bake_all() for every frame, as it runs the simulation for every frame.

Just move the call to bake_all() above your loop, just after setting frame_current to frame_end :

def analyze_scene():
    scene = bpy.data.scenes['Scene']
    object = bpy.data.objects[object]
    frameInfo = []
    scene.frame_current = scene.frame_end
    bpy.ops.ptcache.bake_all(bake=False)

    for frame in range(1, scene.frame_end):
        scene.frame_current = frame
        frameInfo.append({"name": object.name, "frame": frame,
            "translation": object.matrix_world.translation})

    return frameInfo

This should run many times faster, with the code you've given, you were running a simulation of all frames for each frame between 1 and frame_end.

EDIT : If you just want to iterate through the frames, you don't need to bake anything, just change the current frame with scene.frame_set(frame) instead of scene.frame_current = frame. As long as you do this with an incrementing frame, Blender will compute the keypoints for each frame. For example :

def analyze_scene():
    scene = bpy.data.scenes['Scene']
    object = bpy.data.objects[object]
    frameInfo = []

    for frame in range(scene.frame_start,
                       scene.frame_end,
                       scene.frame_step):
        scene.frame_set(frame)
        frameInfo.append({
            "name": object.name, "frame": frame,
            "translation": object.matrix_world.translation
        })

    return frameInfo

NOTE : You also had written scene = bpy.data.scenes['Scene'].frame_end in your code, I corrected it with scene = bpy.data.scenes['Scene'], I guess that is what you meant.

$\endgroup$
  • $\begingroup$ Thanks for the response, @pistache! I'll give this a try and let you know the results. $\endgroup$ – Colin Conwell May 30 '18 at 7:22
  • $\begingroup$ @ColinConwell : could you tell me if there's a problem with this solution ? or accept it ? (i'm just asking because my low reputation prohibits me from commenting anywhere on this site) $\endgroup$ – pistache Jun 20 '18 at 16:43
  • 1
    $\begingroup$ Apologies for the delay. Your solution does work! Thanks again. $\endgroup$ – Colin Conwell Jun 21 '18 at 17:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.