Layer animation in Blender 2.5 using Python API

For a few months now I am working on the integration of a simulator into Blender. Once run, this simulator outputs a series of meshes, each representing the state of the simulated environment at a specific point in time.

Importing the meshes in Blender 2.5 went fairly easy, but now I want to turn these into an animation. In a prototype plugin I have built earlier for 2.49b, I ‘turned meshes on and off’ by moving them to a separate layer for every frame. However, I am unclear how to do this in 2.5. I have figured out how to do it manually in the UI, but I want the plugin to do it for me.

Does anybody have a clue how I would go about this?

there still is no way to do this with layer-settings in 2.5
but you may use this newer feature, Link:
> http://blenderartists.org/forum/showpost.php?p=1545031&postcount=4
this works manually to switch off/on objects for some frame-ranges,
to change the value from an script, check the data-browser of 2.5

anyone know for 2.5 how to generate and save a rendered-frame from python-script?
I checked the api, but could not find a working way.

btw how did you write the plugin generally? Im finding it hard to find any information with regards to developing blender. Everything on the homepage is really old…

i call it “trial and error” … ;-[


import bpy

for i in range(1,20):
    print("frame:%d"%i)
    bpy.context.scene.set_frame(i)
    #difference between ? INVOKE_AREA.. 
    bpy.ops.screen.render("INVOKE_AREA", animation=False, layer="RenderLayer")
    #bpy.ops.screen.render(animation=False, layer="RenderLayer")
    fname="/tmp/out%d.jpg"%i
    print(fname)
    #oops, this saves ... but Rendering Image and this breaks ...
    # miracles of multitasking, multithreading blender25
    # how to wait for the finish of render and save then ..?
    bpy.data.images['Render Result'].save(path=fname)

!!! take care, this breaks my blender-2.5 svn version and i have to kill
the “no-more-responding” blender program ( … typing: killall -SIGHUP blender)
– i should make a hotkey for this …
What works is the walking thru the frames and rendering and saving the
render-result into jpg-s — BUT what not works is all together in the right
sequence …

Anyone some hints?

How where is this property in code? I have looked in object and object.data, but cant find it. Also, how do I add an FCurve entry for this property from code? I am able to create an Action object using bpy.data.actions.new(“ActionName”), but do not know how to add new FCurves to this object.

To answer my own initial question:

You can use the keyframe_insert-method of the StructRNA you want to animate to insert a keyframe for the current frame. An example:

sphere = bpy.data.objects['Sphere']
scene = bpy.data.scenes[0]

def layer_set(frame, layer):
    # Move to the correct frame
    scene.set_frame(frame)
    # Set the objects visibility in the layer
    sphere.layers[1] = layer
    # Set the current status of the layers property at index 1 as a keyframe
    # for properties that have no index, the 2nd argument can be omitted
    sphere.keyframe_insert("layers", 1)

layer_set(1, False)
layer_set(10, True)
layer_set(20, False)

Test-dr, I am still interested in this ‘Restrict Render []’ property, as it seems to be the proper way to do this kind of animation.

@Spyke:

it is called “Restrict Render”
and i dont know how to insert a FCurve(IPO)-Entry with python-script.

check it like this:
fire up blender25 and with the default scene there is the default Cube
in the Console you can check the setting:

bpy.data.objects[‘Cube’].restrict_render
>>> False

You find the clickable-Button for the Cube object in the
Outliner -> Datablocks -> Objects -> Cube and there it is called “Restrict Render”
With the mouse-pointer over this button (default is not pressed = False - yes this thing
has a negative logik) press Key-i and you have created a FCurve with entry for this setting and the current frame.
Now change the current frame to 10 and do it again.
Change the current frame to 11 and press the Restrict Render Button and insert again with Key-i the state of this button at this frame 11.
Lookup the FCurve and you find the curve with the points at the framenumbers.
If you now run a render over all frames, the Cube will be rendered up to frame 10 and
will not render from frame 11 on.
You can insert more “Restrict Render” entries at other framenumbers too.

update:
but have made no more tests, there is a way to set the FCurve-Entry for this option


bpy.data.objects['Cube'].keyframe_insert("restricted_render", True)

inserts the FCurve-Point for the setting of this option at the current framenumber.
It seems to work…

this is working, the default blender-25 scene with its default Cube


def restrict_render_test():
    ob = bpy.data.objects['Cube']
    scene = bpy.context.scene
    scene.set_frame(1)
    ob.restrict_render = False
    ob.keyframe_insert("restrict_render", True)
    scene.set_frame(10)
    ob.keyframe_insert("restrict_render", True)
    scene.set_frame(11)
    ob.restrict_render = True
    ob.keyframe_insert("restrict_render", True)
    scene.set_frame(20)
    ob.keyframe_insert("restrict_render", True)
    scene.set_frame(21)
    ob.restrict_render = False
    ob.keyframe_insert("restrict_render", True)


restrict_render_test()

then running the render will render the cube not on the frames from 11 to 20.

Excellent, Test-dr. I have modified my plugin to use restrict_render and restrict_view, so I can now preview the animation even before rendering (this was not possible when I used layering for some reason).

Hi there,
Does this work in 2.49b? I am rather uncomfortable with 2.5 =(

thanks for this thread, I am doing a project with similar needs in mind. I have a a bunch of txt files that I need to import into an animation: each text file represents a point in time of some 50 or so metaballs.

for each text file I want generate a metaball at the coordinates (x,y,z), and then set restrict_render and restrict_view for certain frames. Once I generate a ball (because there will be a lot of them I cannot say what the name will be) how do I get the ball to set viewing constraints for itself if I don’t know the name of the metaball?

sorry for the novice question.

Hi there,
Does this work in 2.49b? I am rather uncomfortable with 2.5 =(

thanks for this thread, I am doing a project with similar needs in mind. I have a a bunch of txt files that I need to import into an animation: each text file represents a point in time of some 50 or so metaballs.

for each text file I want generate a metaball at the coordinates (x,y,z), and then set restrict_render and restrict_view for certain frames. Once I generate a ball (because there will be a lot of them I cannot say what the name will be) how do I get the ball to set viewing constraints for itself if I don’t know the name of the metaball?

sorry for the novice question.

*I apologize for the duplicate post and spam. I don’t know how to delete posts.

@Spyke:

Excellent, Test-dr. I have modified my plugin to use restrict_render and restrict_view, so I can now preview the animation even before rendering (this was not possible when I used layering for some reason).

can you show me how to do this?

Thanks

ah, I have had some success:


import bpy

def restrict_render_test():
    ob = bpy.data.objects['Cube'] # I want to replace 'Cube' with GetSelected()?
    scene = bpy.context.scene
    scene.set_frame(1)
    ob.restrict_render = False
    ob.restrict_view= False
    ob.keyframe_insert("restrict_render", True)
    ob.keyframe_insert("restrict_view", True)
    scene.set_frame(10)
    ob.keyframe_insert("restrict_render", True)
    ob.keyframe_insert("restrict_view", True)
    scene.set_frame(11)
    ob.restrict_render = True
    ob.restrict_view = True
    ob.keyframe_insert("restrict_render", True)
    ob.keyframe_insert("restrict_view", True)
    scene.set_frame(20)
    ob.keyframe_insert("restrict_render", True)
    ob.keyframe_insert("restrict_view", True)
    scene.set_frame(21)
    ob.restrict_render = False
    ob.restrict_render = False
    ob.keyframe_insert("restrict_render", True)
    ob.keyframe_insert("restrict_view", True)

restrict_render_test()

I still want to replace ob = bpy.data.objects[‘Cube’] with getting the currently selected object. Anybody know how to do this? I am not familiar with the 2.5 API, especially with bpy and all. Or if someone could tell me how to convert to 2.49b syntax that would be just as great.

Thanks

ob = bpy.context.active_object

thanks Crouch!

As you can see from my spam posts above (again, sorry) I’d like to be able to run the script in 2.49. I did some modification, but what do I substitute with ob.keyframe_insert(“restrictDisplay”, True)?


import Blender
from Blender import * # for good measure!
import bpy

def restrictRenderandView_test():
    ob = Blender.Object.GetSelected() 
    Blender.Set("curframe",1)
    ob.restrictRender = False
    ob.restrictDisplay= False
    ob.keyframe_insert("restrictRender", True)
    ob.keyframe_insert("restrictDisplay", True)
    Blender.Set("curframe",10)
    ob.keyframe_insert("restrictRender", True)
    ob.keyframe_insert("restrictDisplay", True)
    Blender.Set("curframe",11)
    ob.restrictRender = True
    ob.restrictDisplay = True
    ob.keyframe_insert("restrictRender", True)
    ob.keyframe_insert("restrictDisplay", True)
    Blender.Set("curframe",20)
    ob.keyframe_insert("restrictRender", True)
    ob.keyframe_insert("restrictDisplay", True)
    Blender.Set("curframe",21)
    ob.restrictRender = False
    ob.restrictRender = False
    ob.keyframe_insert("restrictRender", True)
    ob.keyframe_insert("restrictDisplay", True)

restrictRenderandView_test()


again it generates a whole mass of errors :frowning:
thanks a whole bunch!
-ejang

@ejang,
sorry, but i think you going the wrong way … wrong direction
if you want to do it in Blender 2.4x.
What you may want is an object appear, hide for some part
of an animation, for a range of rendered frames.
There was always the method to move the object out of sight,
but that did need to change the location in one single frame
and is not nice for animation, if one need it as a reference object
or for other purpose.
In 2.4x one would move the object to a different layer (thats the key-m
in object-mode) and would animate this along a frame-range with key-i,
insert key-frame. This did not work the same in blender 2.5 and therefore
we might use the different way, like above.
Needless to say, in blender 2.4x you have to set the layer not to be rendered
for all the objects in this layer, that should disappear.
And last, even if there would be a way to port this code-part back to blender
2.4x, sorry i would not do it … i would not put any time in it
but you are free to try it.

One last point: there is a bpy-variable to query the version of the running blender-system.
One could use this to code a python-script, that will run in both versions, but it would need a lot of those “try: … except:…” parts in it and because blender 2.5 is still changing (evolution) there would be always the need to modify again and again and
than check again for the old code-parts with old blender-version…

Hi test-dr,

that’s too bad :frowning:
but thank you so much for the info! I had not known that the blender python systems were so different. I was trying to string together code to form a larger script, and it includes an off import script of some kind as well as a modified multiple mesh import script. I guess that since I already don’t know the API very well (not to mention the 2.5 API!) it would be in my best interests to do my animation sequence in 2.4x

so below is my pseudocode: instead of the handy ‘restrict render’ function, I will just position a camera in one layer and shift the meshes from layer 2 (not visible) into layer 1 at the appropriate time frames.


Variables:
N = number of files to be imported, from 1, 2, ... N-1, N
M =  this will be the frames between different meshes.
A, B, C = X, Y, and Z median offset values to correct the badly positioned files. 
Input: multiple .off files.

# Import meshes, each file will be set layer and IPO keys along the way.

set current frame to frame 1
for each file N,
	import the file to layer 2
	add A, B, and C from coordinates of each object.
	Apply render settings and materials are assigned to the N imported files
	
	set current frame to frame (M*N-(M-1)) (if there are 3 frames per object, then the second one will appear in the 4th frame ← I hate math )  
	change to layer 1
	insert layer keyframe
# Now move the layer away.
	set current frame to frame N+ M (frames between different meshes)
	change to layer 2
	insert layer keyframe for layer 2 at frame N+1

I can’t get the syntax to work correctly; can someone show me the appropriate code for inserting layer keyframes, moving to another layer, and going to another frame. I really appreciate your help!

thanks,
ejang

[bump] hello, my code is still not working, any updates?
I don’t understand the syntax of moving a selected object to another layer, or how to insert layer keyframes, or how to change frames - I cannot find any examples …
I really appreciate your help!
ejang

I like the article, but that from the article I know maybe we can be good friends

@ejang:
like i said, i will not spend any further thoughts about this in blender 2.4x
you should more often use the search-function in the forum and
look whats already there (you need to know for what you are looking)

an example of setting layer-visibility for older blender was (one example)
in my signature (link to my python-animation-tryouts)
here
> http://blenderartists.org/forum/showpost.php?p=1065462&postcount=4
is the part in the code, you need to check the lines about


                newobj.ipo[Ipo.OB_LAYER].append((frame, FootPrintVisable))
                newobj.ipo[Ipo.OB_LAYER].append((1, FootPrintInvisable))
                # if the footprints should disappear after some time
                #newobj.ipo[Ipo.OB_LAYER].append((frame+Offset, FootPrintInvisable))    

i used only “red colored footsteps” to mark the walking way …