I’m making an animation and I wrote a Python script to help improve the render times, but it’s not quite working.
My main character has a lot of detail, but the background is relatively simple. I want to render the background at a lower quality setting to save time and then add the main character on top in a separate layer. (I’m going to render a few hundred frames, so every little bit of optimization helps.)
What I’d like to do is isolate the main character and set a border around them, so I don’t waste time rendering the background. I was able to do that with a Python script: It loops over all vertices in a model, projects the coordinates into screen-space, and then finds a bounding box that contains those points.
If I run the function once it will set the border around the object, and if I add it to a scene update callback it will update the border every time I change the frame in the UI.
This almosts works, the only problem is that it doesn’t update when I’m rendering an animation. It will keep whatever border was set on the first frame. I can see that it triggers the scene update callback and sets the correct border, but something in the render settings is getting cached and not updating properly in between frames.
I guess I should start by asking: Is this even necessary? There’s not some feature built into Blender that I’m missing, is there?
Secondly, is it possible to do what I’m trying to do with a Python script? I’m looking for some way to refresh the render settings before it starts rendering.
(*It is possible to render each frame inside a Python loop, but my plan is to use a render farm service with their default animation rendering setup. I also don’t want to hide the background outright because it has to cast shadows and reflect onto the main character.)
Here is what the script looks like so far:
# Test scene for setting the render border for each frame in Python import bpy import bpy_extras.object_utils # Options UpdateFrames = 1 # UpdateBorder def UpdateBorder(camera, scene, object): # Update the render border to wrap around a single object print("\nUpdateBorder Frame "+str(scene.frame_current)) matrix = object.matrix_world mesh = object.data # Get matrix components (Blender 2.8) col0 = matrix.col col1 = matrix.col col2 = matrix.col col3 = matrix.col # Find a bounding box that fits around the vertices minX = 1 maxX = 0 minY = 1 maxY = 0 numVertices = len(object.data.vertices) for t in range(0, numVertices): co = mesh.vertices[t].co # Apply the object transformation # 2.79 version (doesn't work in 2.8 for some reason?) #pos = matrix * mesh.vertices[t].co # 2.8 version pos = (col0 * co.x) + (col1 * co.y) + (col2 * co.z) + col3 # Apply the perspective transformation pos = bpy_extras.object_utils.world_to_camera_view(scene, camera, pos) # Expand the bounding box if (pos.x < minX): minX = pos.x if (pos.y < minY): minY = pos.y if (pos.x > maxX): maxX = pos.x if (pos.y > maxY): maxY = pos.y # Print border to console render = scene.render pMinX = str(int(minX*render.resolution_x)) pMinY = str(int(minY*render.resolution_y)) pMaxX = str(int(maxX*render.resolution_x)) pMaxY = str(int(maxY*render.resolution_y)) print(" ("+pMinX+", "+pMinY+") - ("+pMaxX+", "+pMaxY+")") # Set the render border render.border_min_x = minX render.border_min_y = minY render.border_max_x = maxX render.border_max_y = maxY # Various things that don't fix the border problem #render.resolution_x = 1920 #render.resolution_y = 1080 #render.use_border = True #scene.update() #bpy.context.update() def UpdateFrame(scene): camera = bpy.data.objects['Camera'] object = bpy.data.objects['Cube'] UpdateBorder(camera, scene, object) print("Initializing") # Run the function for the first time (optional) scene = bpy.context.scene camera = bpy.data.objects['Camera'] object = bpy.data.objects['Cube'] UpdateBorder(camera, scene, object) # Set a callback for when the scene is rendered # (Other possible callback functions: render_pre, render_init, scene_update_pre, etc.) bpy.app.handlers.frame_change_post.clear() bpy.app.handlers.frame_change_post.append(UpdateFrame)
BorderTest.blend (643.4 KB)