import subprocess import bpy import os import sys from mathutils import Vector def clear_scene(): bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False) def import_model(model_path): ext = os.path.splitext(model_path)[1].lower() if ext == ".obj": bpy.ops.wm.obj_import(filepath=model_path) elif ext in [".glb", ".gltf"]: bpy.ops.import_scene.gltf(filepath=model_path) else: raise ValueError(f"Unsupported format: {ext}") def get_scene_bbox(): objs = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH'] if not objs: raise RuntimeError("No mesh objects found") min_corner = Vector((float("inf"), float("inf"), float("inf"))) max_corner = Vector((float("-inf"), float("-inf"), float("-inf"))) for obj in objs: for v in obj.bound_box: world_v = obj.matrix_world @ Vector(v) min_corner.x = min(min_corner.x, world_v.x) min_corner.y = min(min_corner.y, world_v.y) min_corner.z = min(min_corner.z, world_v.z) max_corner.x = max(max_corner.x, world_v.x) max_corner.y = max(max_corner.y, world_v.y) max_corner.z = max(max_corner.z, world_v.z) return min_corner, max_corner def normalize_model(): min_corner, max_corner = get_scene_bbox() center = (min_corner + max_corner) / 2 size = max(max_corner.x - min_corner.x, max(max_corner.y - min_corner.y, max_corner.z - min_corner.z)) objs = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH'] for obj in objs: obj.location -= center if size > 0: scale = 2.0 / size for obj in objs: obj.scale *= scale bpy.context.view_layer.update() def add_camera(): bpy.ops.object.camera_add(location=(2.5, -2.5, 2.0)) cam = bpy.context.active_object direction = Vector((0, 0, 0)) - cam.location cam.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler() bpy.context.scene.camera = cam def add_light(): bpy.ops.object.light_add(type='SUN', location=(5, -5, 8)) bpy.context.active_object.data.energy = 3.0 bpy.ops.object.light_add(type='AREA', location=(3, -3, 3)) area = bpy.context.active_object area.data.energy = 3000 area.data.size = 5 def setup_render(output_path, resolution=1024): scene = bpy.context.scene scene.render.engine = 'CYCLES' scene.cycles.samples = 128 scene.render.filepath = output_path scene.render.image_settings.file_format = 'PNG' scene.render.resolution_x = resolution scene.render.resolution_y = resolution scene.render.film_transparent = True def parse_args(): argv = sys.argv argv = argv[argv.index("--") + 1:] if "--" in argv else [] if len(argv) < 2: raise ValueError("Usage: blender -b -P render_model.py -- model_path output_path") return argv[0], argv[1] def get_static_model_image(): model_path, output_path = parse_args() clear_scene() import_model(model_path) normalize_model() add_camera() add_light() setup_render(output_path) bpy.ops.render.render(write_still=True) print(f"Saved to {output_path}") if __name__ == "__main__": get_static_model_image()