Niemand heeft dit kantoor gemodelleerd. Geen muis, geen viewport, geen artiest: Python-scripts, geschreven door een AI-agent en uitgevoerd door Blender via de command line. Dezelfde code perste het hele decor daarna samen tot 6,6 MB, klein genoeg voor een webpagina. Hieronder het notitieboek, met de echte code.
Het probleem
Onze webexperiences vragen decors die naast een filmbeeld kunnen staan: zacht licht, geloofwaardige rommel, scherptediepte. Alleen moeten die decors op een telefoon draaien, aan 60 beelden per seconde. Cycles rekent minuten aan één beeld; de browser krijgt er 16 milliseconden voor. Die twee werelden praten niet met elkaar.
Ander gegeven: er is hier geen 3D-artiest. De studio, dat is een mens die beslist en een AI-agent die uitvoert. Blender zou dus niet geopend worden. Het zou aangestuurd worden.
Blender zonder interface
Blender bevat een volledige Python-interpreter, bpy, en draait probleemloos zonder interface. De hele scène past dus in een programma:
/Applications/Blender.app/Contents/MacOS/Blender \
--background --python build_office.py -- --render
Tijdens het bouwen ziet de agent niets. Hij beschrijft, in meters. De kamer meet 4,2 m op 5,2 m: dozen, heel simpel, tot en met de rechterwand die in vier panelen werd gesneden om er een raam in te maken:
box('floor', (4.2, 5.2, 0.05), (0, 0, -0.025), WOOD)
box('wall_back', (4.2, 0.06, 3.0), (0, -2.6, 1.5), WALL)
# Rechterwand DOORBOORD met een raam (opening y -1.35..0.15, z 0.85..2.5)
box('wall_right_a', (0.06, 5.2, 0.85), (2.1, 0, 0.425), WALL) # onder het raam
box('wall_right_b', (0.06, 5.2, 0.5), (2.1, 0, 2.75), WALL) # erboven
Het meubilair werd niet gemodelleerd. Alles komt van Poly Haven, een CC0-bibliotheek van gescande objecten met een API: het metalen bureau, de fauteuil, de scharnierlamp, de CRT-televisie, de laptop uit de jaren 90. Eén functie, place(), importeert elk object, meet het, schaalt het en zet het op de vloer. De redenering van een decorbouwer: dit bureau is 78 cm hoog, het staat daar, zo gedraaid.
desk = place(import_asset('polyhaven/desk', 'desk'), target_h=0.78, loc=(-0.5, -1.85, 0))
chair = place(import_asset('polyhaven/office-chair', 'chair'), target_h=0.95,
loc=(-1.05, -0.8, 0), rot_z=math.radians(210))
crt = place(import_asset('polyhaven/crt-tv', 'crt'), target_h=0.42,
loc=(0.15, -2.1, DESK_TOP), rot_z=math.radians(42))
De rommel is ook code
Een opgeruimd bureau vertelt niets; dit bureau had een verleden nodig. De module clutter.py importeert geen enkele asset. Primitieven en regels, meer niet. Stapels A4 die nooit helemaal recht liggen, ongelijke mappen, kabels die doorhangen in een kettinglijn, veertien post-its. Elke stapel krijgt zijn eigen random seed en zijn messiness-parameter: op 0 ligt de stapel netjes, op 1 spreekt de commentaarregel in het script van “chaos aan het einde van de nacht”:
clutter.paper_stack((-1.0, -1.55, DESK_TOP), height=0.16, seed=3, messiness=1.0)
clutter.folder_stack((1.1, -2.2, DESK_TOP), count=7, seed=5)
clutter.cable((0.15, -2.3, DESK_TOP), (0.9, -2.5, 0.05), sag=0.25, seed=11)
clutter.postits((-0.1, -2.555, 1.35), 'y', count=14, seed=9) # tegen de muur geplakt
Licht maakt de film
Vier bronnen. De bureaulamp, warm, die de hele scène draagt. Stadslicht, koud, door de venetiaanse jaloezieën. De schermen. En een lade die op een kier bleef staan en gouden licht lekt. Wat erin zit, vertellen we hier niet.
key.data.energy = 180
key.data.color = (1.0, 0.78, 0.5) # de lamp: warm, de key
moon.data.color = (0.6, 0.71, 0.95) # de stad: koud, door de jaloezieën
box('drawer_gold', ..., emit=(1.0, 0.72, 0.28), strength=90) # de lade
scene.view_settings.view_transform = 'AgX' # + look 'AgX - Punchy'
Alles gaat door de AgX-kleurtransformatie, die hoge lichten zacht laat afrollen in plaats van ze wit uit te bijten zoals 3D-renders dat tien jaar geleden deden.
De agent herleest zichzelf
De eerste render was niet goed.
Niemand kwam tussen deze twee beelden. De agent renderde de scène, bekeek het resultaat, merkte het overbelichte scherm op dat in de camera staarde, en corrigeerde zijn eigen script: het toestel draait naar de fauteuil, de emissie zakt, de tint koelt af. De correctie die een director of photography op het oog zou maken, gebeurt hier door code te herlezen.
De cijfers, op een gewone MacBook M1
- ≈ 3 min 20 per beeld in 1080p, 256 adaptieve samples, GPU-denoising
- 63 MB de bronscène (.blend), honderden objecten
- 6,6 MB hetzelfde decor, klaar voor de browser
- 0 klikken in de interface van Blender
De brug naar de browser: het licht bakken
Geen enkele telefoon zal deze belichting live berekenen, en dat hoeft ook niet. De truc is zo oud als het videospel: bereken het licht één keer en schilder het daarna op de muren. Dat is de bake.
Het tweede script voegt de scène samen tot twee objecten, de schil (muren, vloer, plafond, jaloezieën) en de inhoud (meubels, rommel), vouwt elk open op een nieuwe UV-atlas en bakt de Cycles-belichting in twee texturen. Daarna vervangt het de materialen. Het geëxporteerde bestand bevat geen enkele lamp meer: het licht is textuur geworden. Alleen de schermen en het goud van de lade blijven emissief; die blijven in realtime leven:
groups = {'shell': muren_vloer_plafond, 'stuff': al_de_rest}
bpy.ops.uv.smart_project(island_margin=0.002)
bpy.ops.uv.pack_islands(margin=0.003) # anders klitten de eilanden samen in een hoek
bpy.ops.object.bake(type='COMBINED', margin=8, use_clear=True)
bpy.ops.export_scene.gltf(filepath='office_baked.glb', export_format='GLB')
Drie valkuilen onderweg:
1. Het gebakken beeld moet manueel worden opgeslagen via script: het automatische opslaan van de bake is kapot in headless-modus.
2. Zonder pack_islands na het unwrappen klitten alle UV-eilanden samen in één hoek van de atlas.
3. Op M1 kan een GPU-bake artefacten opleveren: dezelfde bake opnieuw draaien op CPU lost het op.
Aan het einde van de keten: een GLB van 6,6 MB die three.js laadt als eender welk model. Alleen draagt dit model filmbelichting mee die niets meer kost om te berekenen.
Wat dit verandert, ook voor uw bedrijf
Dit notitieboek wil geen 3D verkopen. 3D is onze testbank, de zwaarste die we vonden: geometrie, licht en performancebudget moeten tegelijk kloppen. Waar het om gaat, is het mechanisme eronder: een AI-agent kan elke software aansturen die zich via code laat automatiseren. Hij klikt niet sneller dan een mens. Hij schrijft, voert uit, leest het resultaat, corrigeert zichzelf.
Zet uw ERP, uw planningstool of uw documentketen op de plaats van Blender: de lus verandert niet. Het is dezelfde die wij bij onze klanten installeren.