import json import pathlib import sys import bpy def main() -> None: if "--" not in sys.argv or len(sys.argv[sys.argv.index("--") + 1:]) != 3: raise SystemExit("usage: blender --background --python render-server-job.py -- SOURCE OUTPUT SETTINGS_JSON") source_arg, output_arg, settings_arg = sys.argv[sys.argv.index("--") + 1:] source = pathlib.Path(source_arg).resolve() output = pathlib.Path(output_arg).resolve() settings_path = pathlib.Path(settings_arg).resolve() if not source.is_file() or source.stat().st_size < 1: raise RuntimeError("server render source is missing") bpy.ops.wm.open_mainfile(filepath=str(source), load_ui=False) scene = bpy.context.scene if scene is None: raise RuntimeError("server render scene is missing") settings = json.loads(settings_path.read_text(encoding="utf-8")) engine = settings["renderEngine"] scene.render.engine = "BLENDER_EEVEE" if engine == "BLENDER_EEVEE_NEXT" else engine frame = int(settings["frameStart"]) if frame != int(settings["frameEnd"]): raise RuntimeError("server render schema 1 requires a still frame") scene.render.resolution_x = int(settings["resolutionX"]) scene.render.resolution_y = int(settings["resolutionY"]) scene.render.resolution_percentage = int(settings["resolutionPercentage"]) if scene.render.engine == "BLENDER_CYCLES": scene.cycles.samples = int(settings["samples"]) elif scene.render.engine == "BLENDER_EEVEE": scene.eevee.taa_render_samples = int(settings["samples"]) scene.render.image_settings.file_format = "PNG" if settings["outputMime"] == "image/png" else "OPEN_EXR" scene.render.film_transparent = bool(settings["transparent"]) scene.frame_set(frame) scene.render.filepath = str(output) scene.render.use_file_extension = True bpy.ops.render.render(write_still=True) if not output.is_file() or output.stat().st_size < 1: raise RuntimeError("server render produced no output") print(f"server-render-ok frame={frame} output={output} bytes={output.stat().st_size}") main()