Swapping geometry at render time

I have two blend files. One has a sphere in it and the other one has a cube. The one with the cube is open. Is it possible, only at render time, to get the sphere from the other file and swap the cube for it? I don’t want to link the sphere, as an object or a collection. I just want to swap it at render time. The sphere should never be in my cube file in any ways. Maybe using a pre-render script? Could this help? bpy.app.handlers.render_pre

I’d bet against it, although I could be wrong! If you are lucky, you might be able to toggle a visible=True / visible = False . . . . but I would not bet any hard cash on it, ha ha

You’re on the right track. This should be quite trivial to setup by registering a couple of callbacks to the different event handlers.

For the initial swap, it would probably be either render_pre or render_init. Then a function to swap back on both render_cancel and render_complete (maybe render_post?)
I think there are examples of registering event handlers in the text editor.

Though it would depend on the workflow, I’d perform the swap with manipulating a collection reference, or toggling visibility. Visibility swapping being the messier of the two.

2 Likes

I’ll ask our programmer to give it a shot. I had a short exchange with Brecht, Cycles’ creator and he told me it would not be possible but they are working on something related to Alembic/USD that could do that. But I don’t think it’s going to be ready soon. We’ll see.

1 Like

That’s good to know. I have been frustrated with the lack of alembic attribute support and cycles’ limitations lately.

you can append geometry from another blend file and swap the geometry on bpy.app.handlers.render_init and restore the geometry on bpy.app.handlers.render_cancel or bpy.app.handlers.render_complete

here some prove of concept

import bpy
from bpy.types import Mesh, Scene

original_geometry: Mesh = None

def prepare_render(scene: Scene, context: object) -> None:
    global original_geometry

    # append geometry from another blend file
    # https://docs.blender.org/api/current/bpy.types.BlendDataLibraries.html#bpy.types.BlendDataLibraries.load
    with bpy.data.libraries.load("C:\\Users\\user\\Documents\\boxy.blend", link=False, relative=False) as (data_from, data_to):
        data_to.meshes = [name for name in data_from.meshes if name == "Sphere"]

    # get object
    cube = bpy.data.objects["Cube"]
    # store geometry to original_geometry
    original_geometry = cube.data
    # swap geometry
    cube.data = bpy.data.meshes["Sphere"]

def restore_render(scene: Scene, context: object) -> None:
    global original_geometry

    # get object
    cube = bpy.data.objects["Cube"]
    # get current geometry to delete
    geometry_to_delete = cube.data
    # swap geometry
    cube.data = original_geometry
    # delete geometry from current blend file
    bpy.data.meshes.remove(geometry_to_delete, do_unlink=True, do_id_user=True, do_ui_user=True)

# init handler
bpy.app.handlers.render_init.append(prepare_render)
bpy.app.handlers.render_cancel.append(restore_render)
bpy.app.handlers.render_complete.append(restore_render)
1 Like

THIS IS AWESOME!!! Thank you so much! We’ll take it from here. You made my day!

1 Like

How hard would it be to modify this script so that it goes through every objects in the scene, finds the ones that are call “(whatever the name) lo” and swap them for (the same name) hi", considering that all these objects are referenced in the scene, and could be from different files?

The reason I’m asking is that there’s an addon I found here (proxy tool) that will generate point clouds of geometry, only show that on screen but at render it will swap the point cloud for the hi res geo. The problem is that even if you only see the point cloud on screen, which is way faster than the geo, the geo itself is in memory. But when you save a file that has been converted with that addon, in it, you have access to both the point cloud and the hi res mesh and they are called for example “foo lo” and “foo hi”. So if I could link the lo version in my layout file and run the script, it would swap the hi res at render time only, which is my goal. I’m trying to emulate the workflow in Katana, Arnold or Renderman where you can deal with gigantic scenes without taking too much ram (except for rendering).

Yes, I know about the proxify addon but it’s not what I’m looking for.

Here’s a sphere that have been converted as a point cloud if someone wants to give it a shot.

sphere.blend (914.8 KB)

my solution… really working well. :slight_smile: :slight_smile:

2 Likes

How does it work? Addon?

Oh! You are using mesh cache… interesting. I’ll check it out. (I just realized that it’s the same thing you showed on devtalk. I’m super busy these days. I can’t keep up. Cheers!

Do you need to assign the material manually? Alembic doesn’t support Blender shaders, to my knowledge.

same material from original mesh… blender export facesets to alembic file, this facesets are used to assign shader.

workflow:

  1. create/import highpoly mesh
  2. create proxys versions
  3. export all to alembic file
  4. create ‘1 vertex only’ mesh container/standin object with same shaders from original object.
  5. add 2 mesh sequence cache modifiers to standin obj and load alembic file

Quite interesting! Thanks for sharing! :slight_smile: