"""Studio for the sliding door's pictures: camera, lights, world, a floor plane. Not exported (collection 'Studio'). render(view, path, engine='CYCLES', samples=96, res=(1600, 1000))""" import bpy, math from mathutils import Vector STUDIO = "Studio" VIEWS = { # name: (location, look-at, lens) "front34": ((-3.9, -6.4, 2.3), (0.15, 0.0, 1.50), 40), "front": ((0.0, -7.6, 1.7), (0.0, 0.0, 1.55), 44), "open34": ((-2.6, -5.2, 2.0), (0.1, 0.0, 1.35), 42), "lock": ((-0.7, -1.9, 1.42), (0.0, -0.03, 1.21), 55), "leafL": ((-1.3, -2.9, 1.5), (-0.25, -0.03, 1.25), 48), "console": ((-0.9, -3.1, 1.7), (-2.13, -0.2, 1.30), 45), "right": ((0.7, -3.6, 1.9), (2.13, -0.05, 1.45), 42), "top": ((0.4, -3.0, 3.5), (0.0, -0.1, 2.70), 42), "back": ((2.4, 4.8, 1.9), (0.0, 0.3, 1.35), 38), "side": ((-5.2, -1.6, 1.6), (0.0, 0.0, 1.30), 40), } def studio_coll(): c = bpy.data.collections.get(STUDIO) if c is None: c = bpy.data.collections.new(STUDIO) bpy.context.scene.collection.children.link(c) return c def light(name, kind, loc, rot, energy, size=1.0, color=(1, 1, 1)): ob = bpy.data.objects.get(name) if ob is None: ld = bpy.data.lights.new(name, kind) ob = bpy.data.objects.new(name, ld) studio_coll().objects.link(ob) ob.location = loc ob.rotation_euler = rot ob.data.energy = energy ob.data.color = color if kind == 'AREA': ob.data.size = size return ob def floor(): ob = bpy.data.objects.get("PDS_StudioFloor") if ob is None: me = bpy.data.meshes.new("PDS_StudioFloor") me.from_pydata([(-8, -8, 0), (8, -8, 0), (8, 0.3, 0), (-8, 0.3, 0)], [], [(0, 1, 2, 3)]) m = bpy.data.materials.new("M_StudioFloor") m.use_nodes = True b = m.node_tree.nodes.get("Principled BSDF") b.inputs["Base Color"].default_value = (0.12, 0.125, 0.13, 1) b.inputs["Roughness"].default_value = 0.35 me.materials.append(m) ob = bpy.data.objects.new("PDS_StudioFloor", me) studio_coll().objects.link(ob) return ob def setup(): sc = bpy.context.scene cam = bpy.data.objects.get("PDS_Camera") if cam is None: cam = bpy.data.objects.new("PDS_Camera", bpy.data.cameras.new("PDS_Camera")) studio_coll().objects.link(cam) sc.camera = cam light("PDS_Key", 'AREA', (-3.0, -4.5, 4.0), (math.radians(50), 0, math.radians(-35)), 900, 3.0, (1.0, 0.97, 0.93)) light("PDS_Fill", 'AREA', (4.5, -4.0, 2.2), (math.radians(68), 0, math.radians(48)), 380, 4.0, (0.9, 0.95, 1.0)) light("PDS_Top", 'AREA', (0.0, -1.8, 4.6), (0, 0, 0), 320, 5.0) light("PDS_Red", 'POINT', (-3.4, -2.0, 2.4), (0, 0, 0), 120, 1.0, (1.0, 0.12, 0.05)) light("PDS_Back", 'AREA', (1.5, 4.5, 3.2), (math.radians(-50), 0, math.radians(160)), 500, 3.0, (0.95, 0.97, 1.0)) # lights the ship side for the back view floor() w = sc.world or bpy.data.worlds.new("World") sc.world = w w.use_nodes = True bg = w.node_tree.nodes.get("Background") bg.inputs[0].default_value = (0.30, 0.32, 0.35, 1) bg.inputs[1].default_value = 0.5 sc.view_settings.view_transform = 'AgX' sc.view_settings.look = 'None' return cam def aim(cam, view): loc, tgt, lens = VIEWS[view] cam.location = loc d = Vector(tgt) - Vector(loc) cam.rotation_euler = d.to_track_quat('-Z', 'Y').to_euler() cam.data.lens = lens cam.data.clip_start = 0.05 def render(view, path, engine='CYCLES', samples=96, res=(1600, 1000)): sc = bpy.context.scene cam = setup() aim(cam, view) if engine.startswith('BLENDER_EEVEE'): for eid in ('BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'): try: sc.render.engine = eid break except TypeError: continue try: sc.eevee.taa_render_samples = samples except Exception: pass else: sc.render.engine = engine sc.render.resolution_x, sc.render.resolution_y = res sc.render.resolution_percentage = 100 if engine == 'CYCLES': sc.cycles.samples = samples sc.cycles.use_denoising = True try: prefs = bpy.context.preferences.addons['cycles'].preferences prefs.compute_device_type = 'HIP' prefs.get_devices() for d in prefs.devices: d.use = d.type == 'HIP' sc.cycles.device = 'GPU' except Exception: sc.cycles.device = 'CPU' sc.render.filepath = path sc.render.image_settings.file_format = 'PNG' bpy.ops.render.render(write_still=True) return path