5
$\begingroup$

I understand that it's possible to keyframe visibility, and that might have to be at least part of the solution. However, I intend to create many objects at once, with a script to generate them, so I can't think how to apply visibility keyframes, when I'd have so many objects which initially don't exist.

If it helps, here's the (messy) code I'm working with:

import bpy

CoList = []

def DeleteExisting():
    bpy.ops.object.select_all(action='TOGGLE')
    bpy.ops.object.delete(use_global=False)
    bpy.ops.object.select_all(action='TOGGLE')
    bpy.ops.object.delete(use_global=False)

DeleteExisting()

def Create_List(Width):
    for x in range(0,Width):
        CoList.append([x])
    for i in CoList:
        x = i[0]
        i.pop(0)
        for y in range(0,Width):
            i.append([x,y])
    return CoList

def Generate_Cubes(CoList):
    for x in CoList:
        for y in x:
            X_Value = y[0]
            Y_Value = y[1]
            while type(X_Value) == list:
                if type(X_Value) == list:
                    X_Value = X_Value[0]
                if type(Y_Value) == list:
                    Y_Value = Y_Value[0]
            bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(X_Value, Y_Value, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
            bpy.ops.transform.resize(value=(0.25, 0.25, 0.25), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)

for X in range(1,6):
    bpy.context.scene.frame_current = X
    Width = X+2
    DeleteExisting()
    CoList = Create_List(Width)
    Generate_Cubes(CoList)
    bpy.ops.object.select_all(action='TOGGLE')
    bpy.ops.object.select_all(action='TOGGLE')

This creates a grid of cubes, which looks like this:

And it also advances the current frame, however once an object is created, it exists on all frames, regardless of any keyframes that I know of. So how would I implement this so that objects only exist on the frame which they are created on?

$\endgroup$

2 Answers 2

2
$\begingroup$

Driver based method,

driving the hide property, simply hiding a cube if its "visframe" custom property is greater than the frame number. Creates a 10 x 10 grid of cubes where only one is visible on frame 1, 2 On frame 2, ... 100 on frame 100. Drive the hide_render property to render.

import bpy
context = bpy.context
scene = context.scene
bpy.ops.mesh.primitive_cube_add()
cube = context.active_object
cube.scale *= 0.25

for i in range(10):    
    x = 2 * i    
    for j in range(10):

        cube["visframe"] = 10 * i + j        
        # add a driver
        fcurve = cube.driver_add("hide_render")
        driver = fcurve.driver
        var = driver.variables.new()
        var.name = "vis"
        var.targets[0].id = cube
        var.targets[0].data_path = '["visframe"]'
        # scene.frame_current is defined as frame to driver namespace
        driver.expression = "vis >= frame" # show if cube["visframe"] > frame
        y = 2 * j
        cube.location.xy = (x, y)        
        cube = cube.copy()
        context.collection.objects.link(cube)
$\endgroup$
5
$\begingroup$

Each object has two properties called hide and hide_render - the first is viewport visibility and the second is render visibility.

To use python to set a keyframe for a property you set the value, then use keyframe_insert(data_path, frame=f) to keyframe it. So if you only want to object visible on one frame, you make it visible and set a keyframe on the relevant frame, then hide it and add a keyframe for the previous and next frame.

import bpy

# clear any existing objects
for o in bpy.data.objects:
    o.hide = False
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()

grid_size = 7
# the default cube is 2 units wide, add another .2 for gap
spacing = 2.2

for x in range(grid_size):
    for y in range(grid_size):
        f = (x*grid_size) + y
        bpy.ops.mesh.primitive_cube_add (location=(x*spacing, y*spacing, 0))
        obj = bpy.context.active_object
        # key as visible on the current frame
        obj.keyframe_insert('hide',frame=f)
        obj.keyframe_insert('hide_render',frame=f)
        # hide it
        obj.hide = True
        obj.hide_render = True
        # key as hidden on the previous frame
        obj.keyframe_insert('hide',frame=f-1)
        obj.keyframe_insert('hide_render',frame=f-1)
        # key as hidden on the next frame
        obj.keyframe_insert('hide',frame=f+1)
        obj.keyframe_insert('hide_render',frame=f+1)
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .