4
$\begingroup$

Is it possible to store each animation frame as a new object? I searched quite a long time now on google and was wondering that I cannot find any information about this.

I just have a simple model with a simple pose animation and I'm looking for a way to get each frame stored as a new object, that I end up with maybe 100 objects "frame001", "frame002", "frame003", ...

I need this for a game engine that does not support bone animations, but I can fake such an animation by exporting this object (as a collada) and then setting only one of the "frame-objects" visible in this engine.


I tried to write a quick and dirty python script myself after some basic reading, but unfortunately the most important action (the conversion to a mesh) does not work:

import bpy

count=0

for x in range(bpy.data.scenes["Scene"].frame_start,bpy.data.scenes["Scene"].frame_end):
    bpy.ops.object.duplicate_move()

bpy.ops.object.select_all(action='DESELECT')

obs = bpy.data.objects
bpy.data.scenes["Scene"].frame_current=0        
for ob in obs:
    bpy.ops.object.select_all(action='DESELECT')
    if ob.type == 'MESH' and ob.name.startswith("model"):
        if count>0:
            ob.select=True
            bpy.ops.object.convert(target='MESH')
            bpy.data.scenes["Scene"].frame_current+=1
        count=count+1
$\endgroup$
  • $\begingroup$ I've added python to the tags since I think you'll need this. $\endgroup$ – MarcClintDion Nov 30 '14 at 11:29
  • $\begingroup$ I've tried that but the collada exporter always jumped to the last frame. $\endgroup$ – stacker Nov 30 '14 at 12:59
  • $\begingroup$ .obj animation export should work fine. Is this an option for you? $\endgroup$ – p2or Nov 30 '14 at 16:25
  • 1
    $\begingroup$ Blender has an exporter for "Lightwave Motion Designer (MDD)". If you can't use the file format the script may help $\endgroup$ – sambler Dec 1 '14 at 11:08
3
$\begingroup$

You should avoid operators whenever possible:

import bpy

scene = bpy.context.scene
frame_current = scene.frame_current

for f in range(scene.frame_start, scene.frame_end + 1):
    scene.frame_set(f)

    meshes = []
    for ob in scene.objects:
        if ob.type == 'MESH' and ob.name.startswith("model"):
            me = ob.to_mesh(scene, True, 'PREVIEW')
            meshes.append(me)

    # do something with the meshes (note: they aren't linked to anything)

    # Clean up mesh copies
    for me in meshes:
        bpy.data.meshes.remove(me)

scene.frame_set(frame_current)

This will apply modifiers to all mesh objects in the current scene that start with the name model. The resulting (new!) mesh datablocks can be used for export.

Note however, that you will have to create objects and link the meshes to them if you plan to call an export operator - they usually export all (selected) objects, not invisible mesh datablocks. You may wanna check out the exporter code and see if you can import the actual export routine to avoid that operator call and maybe even the object creation.


If you want to apply animation in a way, that there's one static object per frame of an animated model, you may use the following script:

import bpy

scene = bpy.context.scene
frame_current = scene.frame_current

r = range(scene.frame_start, scene.frame_end + 1)
l = len(str(len(r)))
obs = []

for f in r:
    scene.frame_set(f)

    for ob in scene.objects:
        if ob.type == 'MESH' and ob.name.startswith("model"):
            me = ob.to_mesh(scene, True, 'PREVIEW')
            me.transform(ob.matrix_world)
            new_ob = bpy.data.objects.new("%s_frame%0*i" % (ob.name, l, f), me)
            obs.append(new_ob)

scene.frame_set(frame_current)
for ob in obs:
    scene.objects.link(ob)
scene.update()

It applies modifiers as well as transformations (.matrix_world, so loc/rot/scale).

$\endgroup$
  • $\begingroup$ Excactly was I was looking for / trying to create! $\endgroup$ – daniel Dec 1 '14 at 11:47
  • $\begingroup$ Thank you for this very helpful answer! Is there a way to modify the script so that the object origins don't get left behind? Currently all my mesh data looks great, but I can't join the meshes as shape keys successfully because the origin point is offset by the animation. $\endgroup$ – Mentalist Jul 12 '17 at 14:39
  • $\begingroup$ @Mentalist: Take the code of the 2nd example above, remove the call to me.transform() and add new_ob.matrix_world = ob.matrix_world.copy() above obs.append(new_ob), that should do the trick (unless the object is parented to another object, I believe it would require some additional logic in that edge case). $\endgroup$ – CoDEmanX Jul 26 '17 at 21:10
1
$\begingroup$

Following is an example script that converts the mesh (animated by an armature) to separate objects. To keep the code simple, the assumption is that there is only one modifier (Armature) and the mesh was bound to armature using vertex groups. There are 5 frames of animation (frames 1, 2, 3, 4, 5)

import bpy

# Select the mesh that is animated by a keyframed armature in pose mode.
source_object = bpy.context.active_object

objects = []

for index in range(1, 6):
    bpy.ops.object.duplicate_move(
        OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, 
        TRANSFORM_OT_translate={"value":(0, 0, 0), 
                                "constraint_axis":(True, False, False)
                                }
    )

    objects.append(bpy.context.active_object)

for index in range(1, 6):
    bpy.context.scene.frame_set(index)

    override_context = bpy.context.copy()

    override_context['active_object'] = objects[index-1]
    override_context['object'] = objects[index-1]
    override_context['selected_objects'] = [objects[index-1]]

    bpy.ops.object.modifier_apply(override_context, apply_as='DATA', modifier='Armature')
    bpy.ops.object.vertex_group_remove(override_context, all=True)
    objects[index-1].select = False

bpy.context.scene.frame_set(1)
source_object.select = True
$\endgroup$

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.