Hmm, I was able to reassemble the tiles within Cinema 4D as well. Here's the script with reassembly.
Feel free to chime in if we should not be doing this (performance impact, does not work with different renderers etc)
import c4d
import os
doc: c4d.documents.BaseDocument
op: c4d.BaseObject | None
def main() -> None:
"""Renders the scene as a grid of tiles, then reassembles into the final image."""
# --- Configure these ---
tiles_x = 2
tiles_y = 2
output_dir = os.path.join(os.path.expanduser("~"), "Desktop", "tiles")
final_path = os.path.join(output_dir, "final_assembled.png")
# ------------------------
os.makedirs(output_dir, exist_ok=True)
base_rd = doc.GetActiveRenderData()
full_w = int(base_rd[c4d.RDATA_XRES])
full_h = int(base_rd[c4d.RDATA_YRES])
tile_w = full_w // tiles_x
tile_h = full_h // tiles_y
tile_bmps = {}
for ty in range(tiles_y):
for tx in range(tiles_x):
rd = base_rd.GetClone()
left = tx * tile_w
top_ = ty * tile_h
right = left + tile_w
bottom = top_ + tile_h
rd[c4d.RDATA_RENDERREGION] = True
rd[c4d.RDATA_RENDERREGION_LEFT] = left
rd[c4d.RDATA_RENDERREGION_TOP] = top_
rd[c4d.RDATA_RENDERREGION_RIGHT] = right
rd[c4d.RDATA_RENDERREGION_BOTTOM] = bottom
bmp = c4d.bitmaps.MultipassBitmap(full_w, full_h, c4d.COLORMODE_RGB)
bmp.AddChannel(True, True)
print(f"Rendering tile ({tx}, {ty}) region=({left},{top_})-({right},{bottom})")
result = c4d.documents.RenderDocument(
doc,
rd.GetData(),
bmp,
c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_SHOWERRORS,
)
if result != c4d.RENDERRESULT_OK:
print(f"Tile ({tx}, {ty}) failed with code: {result}")
return
# Crop tile — use same coords as region
tile_bmp = c4d.bitmaps.BaseBitmap()
tile_bmp.Init(tile_w, tile_h)
for y in range(tile_h):
for x in range(tile_w):
r, g, b = bmp.GetPixel(left + x, top_ + y)
tile_bmp.SetPixel(x, y, r, g, b)
tile_path = os.path.join(output_dir, f"tile_{tx}_{ty}.png")
tile_bmp.Save(tile_path, c4d.FILTER_PNG)
print(f"Saved {tile_path}")
tile_bmps[(tx, ty)] = tile_bmp
# --- Reassemble: place each tile at its matching position, no flip ---
print("Assembling final image...")
final_bmp = c4d.bitmaps.BaseBitmap()
final_bmp.Init(full_w, full_h)
for ty in range(tiles_y):
for tx in range(tiles_x):
tile_bmp = tile_bmps[(tx, ty)]
dst_x = tx * tile_w
dst_y = ty * tile_h
for y in range(tile_h):
for x in range(tile_w):
r, g, b = tile_bmp.GetPixel(x, y)
final_bmp.SetPixel(dst_x + x, dst_y + y, r, g, b)
final_bmp.Save(final_path, c4d.FILTER_PNG)
print(f"Saved assembled image to {final_path}")
c4d.bitmaps.ShowBitmap(final_bmp)
c4d.gui.MessageDialog(
f"Done! {tiles_x * tiles_y} tiles rendered and assembled.\n{final_path}"
)
if __name__ == "__main__":
main()