# Preview renders. blender -b ../CaptainsQuarters.blend --python render_previews.py -- [views...] [--samples N] [--res N] [--clay] # Does not save the .blend; it only moves the studio camera from view to view. import bpy, os, sys, math from mathutils import Vector HERE = os.path.dirname(os.path.abspath(__file__)) OUT = os.path.join(os.path.dirname(HERE), 'previews') os.makedirs(OUT, exist_ok=True) argv = sys.argv[sys.argv.index('--') + 1:] if '--' in sys.argv else [] def opt(name, default): if name in argv: i = argv.index(name); v = argv[i + 1]; del argv[i:i + 2] return type(default)(v) return default SAMPLES = opt('--samples', 128) RES = opt('--res', 1200) PREFIX = opt('--prefix', 'CQ_') CLAY = '--clay' in argv if CLAY: argv.remove('--clay') VIEWS = { # name: (camera, target, lens mm, hide) 'ref': ((0.50, -1.55, 1.28), (-2.30, 1.30, 1.02), 28, ()), 'bunk': ((-0.95, -0.55, 1.18), (-2.10, 1.80, 0.95), 32, ()), 'room_a': ((3.25, -1.95, 1.65), (-1.60, 0.90, 0.95), 16, ()), 'room_b': ((-3.30, -1.95, 1.65), (2.00, 0.80, 0.95), 16, ()), 'desk': ((0.20, -1.30, 1.45), (2.10, 1.30, 1.05), 26, ()), 'door': ((2.60, 0.60, 1.55), (-1.30, -2.20, 1.00), 20, ()), 'chair': ((-1.35, -1.75, 1.05), (-2.75, -0.50, 0.42), 35, ()), 'top': ((0.0, -0.55, 9.0), (0.0, -0.549, 0.0), 30, ('SM_CQ_Ceiling',)), } sc = bpy.context.scene sc.render.engine = 'CYCLES' cy = sc.cycles cy.samples = SAMPLES cy.use_denoising = True cy.max_bounces = 8 cy.diffuse_bounces = 4 cy.glossy_bounces = 4 cy.transparent_max_bounces = 8 try: prefs = bpy.context.preferences.addons['cycles'].preferences dev = None for t in ('OPTIX', 'HIP', 'CUDA', 'ONEAPI'): try: prefs.compute_device_type = t prefs.get_devices() gp = [d for d in prefs.devices if d.type == t] if gp: for d in prefs.devices: d.use = (d.type == t) dev = t break except Exception: pass cy.device = 'GPU' if dev else 'CPU' print('CYCLES DEVICE', dev) except Exception as e: print('device setup failed', e) sc.render.resolution_x = RES sc.render.resolution_y = RES sc.render.film_transparent = False sc.view_settings.view_transform = 'AgX' try: sc.view_settings.look = 'AgX - Medium High Contrast' except Exception: pass sc.view_settings.exposure = 0.0 # camera, lights and world are the file's own studio set (build_quarters.studio) cam = sc.objects['CQ_Cam'] cam_d = cam.data sc.camera = cam if CLAY: m = bpy.data.materials.new('CLAY') try: m.use_nodes = True except Exception: pass b = next(n for n in m.node_tree.nodes if n.type == 'BSDF_PRINCIPLED') b.inputs['Base Color'].default_value = (0.55, 0.55, 0.55, 1) b.inputs['Roughness'].default_value = 0.6 for ob in sc.objects: if ob.type == 'MESH' and not ob.name.startswith('UCX_'): for i, s in enumerate(ob.material_slots): if s.material and 'Light' not in s.material.name and 'Window' not in s.material.name and 'Glass' not in s.material.name: s.material = m for ob in sc.objects: if ob.name.startswith('UCX_'): ob.hide_render = True names = argv or list(VIEWS) for n in names: loc, tgt, lens, hide = VIEWS[n] cam.location = loc d = Vector(tgt) - Vector(loc) cam.rotation_euler = d.to_track_quat('-Z', 'Y').to_euler() cam_d.lens = lens for ob in sc.objects: if ob.type == 'MESH' and not ob.name.startswith('UCX_'): ob.hide_render = ob.name in hide sc.render.filepath = os.path.join(OUT, PREFIX + n + ('_clay' if CLAY else '') + '.png') bpy.ops.render.render(write_still=True) print('RENDERED', sc.render.filepath)