Exemplo n.º 1
0
def animate_2d_automata(rule, nb_frames: 10, use_grease_pencil=True):
    nb_rows = 10
    nb_cols = 10
    gol = Automaton2D(nb_rows, nb_cols, rule, seed=11)

    FRAMES_SPACING = 1
    bpy.context.scene.frame_start = 0
    bpy.context.scene.frame_end = nb_frames * FRAMES_SPACING

    if use_grease_pencil:
        gp_layer = init_grease_pencil(clear_layer=True)
    else:
        obj_size = 0.7
        subdivisions = 2
        scale_factor = 0.2
        init_mat_color = (0.7, 0.1, 0.1)

        # obj_generator = lambda idx: automata_blender_utils.icosphere_generator(obj_size, subdivisions, idx[0], idx[1], 0)
        obj_generator = lambda idx: automata_blender_utils.cube_generator(
            obj_size, idx[0], idx[1], 0)

        obj_updater = lambda obj, grid, idx: automata_blender_utils.object_updater_hide(
            obj, grid[idx])
        # obj_updater = lambda obj, grid, idx: automata_blender_utils.object_updater_scale(obj, grid[idx],
        #                                                                                 scale_factor=scale_factor)
        # obj_updater = lambda obj, grid, idx: automata_blender_utils.object_updater_color_vector(
        # obj, grid[:, idx[0], idx[1]])

        delete_all()
        obj_grid = automata_blender_utils.create_grid(gol, obj_generator)
        # automata_blender_utils.init_materials(obj_grid, init_mat_color)

    gol.update()
    for frame in range(nb_frames):
        if use_grease_pencil:
            gp_frame = gp_layer.frames.new(frame * FRAMES_SPACING)
            for idx, val in np.ndenumerate(gol.grid):
                if val:
                    draw_square(gp_frame, (idx[0], idx[1], 0), 1)
        else:
            bpy.context.scene.frame_set(frame)
            automata_blender_utils.update_grid(obj_grid, gol, obj_updater)
        gol.update()
def main():
    NUM_FRAMES_CHANGE = 5
    NUM_FRAMES = 160
    PATH_DURATION = 100
    MIRROR_FRAME = 80
    bpy.context.scene.frame_start = 0
    bpy.context.scene.frame_end = NUM_FRAMES

    assert (NUM_FRAMES % NUM_FRAMES_CHANGE == 0)

    torus_major_segments = 70
    torus_minor_segments = 25
    torus_major_radius = 1
    torus_minor_radius = 0.25
    seed = 10
    obj_size = 0.015
    move_factor = 2

    delete_all()

    automata_blender_utils.cube_generator(obj_size, 0, 0, 0)
    cube = bpy.context.view_layer.objects.active

    print("-----------------------")
    print("Start creation process")

    # create Donut
    bpy.ops.mesh.primitive_torus_add(location=(0, 0, 0),
                                     major_radius=torus_major_radius,
                                     minor_radius=torus_minor_radius,
                                     abso_major_rad=1.,
                                     abso_minor_rad=1.,
                                     major_segments=torus_major_segments,
                                     minor_segments=torus_minor_segments)
    torus = bpy.context.view_layer.objects.active

    # duplicate object by donut faces
    cube.select = True
    torus.select = True
    bpy.ops.object.parent_set(type='VERTEX')
    bpy.context.object.dupli_type = 'FACES'
    bpy.ops.object.duplicates_make_real()

    obj_updater = lambda obj, grid, idx: object_updater_move(obj, grid[idx])

    # create GOL data
    rule_gol = {
        'neighbours_count_born': 3,
        'neighbours_maxcount_survive': 3,
        'neighbours_mincount_survive': 2,
    }
    gol = Automaton2D(nb_rows=torus_major_segments,
                      nb_cols=torus_minor_segments,
                      config=rule_gol,
                      seed=seed)
    gol.update()  # update gol to start with a cleaner grid
    gol_grid_cache = []

    # create GOL object grid by selected all previously created objects
    objs = [
        obj for name, obj in bpy.context.scene.objects.items()
        if name.startswith('Cube.')
    ]
    assert len(objs) == gol.grid.shape[0] * gol.grid.shape[1]

    #set_gol_to_glider(gol)

    # Add camera path and follow path action
    bpy.ops.curve.primitive_bezier_circle_add(radius=torus_major_radius,
                                              location=(0, 0, 0))
    cube.select = False
    torus.select = False
    bpy.data.objects['BezierCircle'].select = False
    #bpy.data.objects['BezierCircle'].data.path_duration = PATH_DURATION
    camera = bpy.data.objects['Camera']
    camera.select = True
    camera.location = (0, 0, 0)
    camera.rotation_euler = (0, 0, 0)
    camera.constraints.new(type='FOLLOW_PATH')
    follow_path = camera.constraints['Follow Path']
    follow_path.target = bpy.data.objects["BezierCircle"]
    follow_path.forward_axis = 'TRACK_NEGATIVE_Z'
    follow_path.up_axis = 'UP_Y'
    follow_path.use_curve_follow = True

    # Animate path. Doesn't seem to work because of wrong context
    #bpy.ops.constraint.followpath_path_animate(constraint="Follow Path", owner='OBJECT')

    camera.rotation_euler = (0, -0.25, 0)

    # Set objects on and off location by translating across object axes
    obj_grid = []
    trans_local_adjust = Vector((0.0, 0.0, obj_size + obj_size / 10))
    trans_local_move = Vector((0.0, 0.0, -obj_size * move_factor))
    for obj in objs:
        trans_world = obj.matrix_world.to_3x3() * trans_local_adjust
        obj.matrix_world.translation += trans_world
        original_loc = obj.location.copy()
        trans_world = obj.matrix_world.to_3x3() * trans_local_move
        obj.matrix_world.translation += trans_world
        translated_loc = obj.location.copy()
        obj_grid.append({
            'obj': obj,
            'original_loc': original_loc,
            'translated_loc': translated_loc
        })

    obj_grid = np.array(obj_grid).reshape(gol.grid.shape)

    for frame in range(0, NUM_FRAMES + 1):
        if frame % 10 == 0:
            print("Updating frame {}".format(frame))

        bpy.context.scene.frame_set(frame)
        # When reaching final frame, clear handlers
        if (frame % NUM_FRAMES_CHANGE) == 0:
            if frame < MIRROR_FRAME:
                gol_grid_cache.append(gol.grid)
            elif frame > MIRROR_FRAME:
                gol.grid = gol_grid_cache.pop()
        automata_blender_utils.update_grid(obj_grid, gol, obj_updater)
        if frame >= NUM_FRAMES:
            bpy.app.handlers.frame_change_pre.clear()
            bpy.context.scene.frame_set(0)

    print("-----------------------")