""" scene_setup.py -------------- One-shot scene initialisation: camera, area light, world background, render engine, and default playlist. Call ``setup_scene()`` once after ``register()`` (typically from ``__main__`` or a startup hook). """ from __future__ import annotations import bpy from .constants import ( CAMERA_LOCATION, CAMERA_ROTATION, LIGHT_LOCATION, LIGHT_ENERGY, ) from .materials import prewarm_materials_and_blends def setup_scene() -> None: """Configure the Blender scene for knot animation playback.""" scene = bpy.context.scene # ── Timeline ───────────────────────────────────────────────────────────── scene.frame_start = 1 scene.frame_end = 600 scene.render.fps = 24 # ── Render engine ──────────────────────────────────────────────────────── scene.render.engine = 'CYCLES' scene.cycles.samples = 64 # ── Remove default objects ─────────────────────────────────────────────── for name in ("Cube", "Light", "Camera"): obj = bpy.data.objects.get(name) if obj: bpy.data.objects.remove(obj, do_unlink=True) # ── Camera ─────────────────────────────────────────────────────────────── cam_data = bpy.data.cameras.new("KnotCamera") cam_data.lens = 50 cam_obj = bpy.data.objects.new("KnotCamera", cam_data) cam_obj.location = CAMERA_LOCATION cam_obj.rotation_euler = CAMERA_ROTATION scene.collection.objects.link(cam_obj) scene.camera = cam_obj # ── Area Light ─────────────────────────────────────────────────────────── light_data = bpy.data.lights.new("KnotLight", type='AREA') light_data.energy = LIGHT_ENERGY light_data.size = 3.0 light_obj = bpy.data.objects.new("KnotLight", light_data) light_obj.location = LIGHT_LOCATION scene.collection.objects.link(light_obj) # ── World background: dark gradient ────────────────────────────────────── world = scene.world if world is None: world = bpy.data.worlds.new("KnotWorld") scene.world = world bg_node = world.node_tree.nodes.get("Background") if bg_node: bg_node.inputs["Color"].default_value = (0.02, 0.02, 0.05, 1.0) bg_node.inputs["Strength"].default_value = 0.2 # ── Default playlist ───────────────────────────────────────────────────── # NOTE: An empty CollectionProperty is falsy in Python; use len() to test. if len(scene.knot_list) == 0: bpy.ops.knot.populate() # also calls prewarm_materials_and_blends() else: prewarm_materials_and_blends(scene) # ensure shaders exist for existing list print("[KnotScript] Scene setup complete.")