Personne n'a modelé ce bureau. Pas de souris, pas de viewport, pas d'artiste : des scripts Python écrits par un agent IA, exécutés par Blender en ligne de commande. Le même code a ensuite compressé le décor entier en 6,6 Mo pour qu'il tourne dans une page web. On déroule le carnet, avec le vrai code.
Le problème
Nos expériences web réclament des décors qui tiennent à côté d'un plan de film : lumière douce, bazar crédible, profondeur de champ. Sauf que ces décors doivent tourner à 60 images par seconde sur un téléphone. Cycles met plusieurs minutes à calculer une image ; le navigateur, lui, dispose de 16 millisecondes. Les deux mondes ne se parlent pas.
Autre donnée du problème : pas d'artiste 3D dans l'équipe. Le studio, c'est un humain qui décide et un agent IA qui exécute. Blender n'allait donc pas être ouvert. Il allait être piloté.
Blender sans interface
Blender embarque un interpréteur Python complet, bpy, et accepte très bien de tourner sans interface. La scène entière tient donc dans un programme :
/Applications/Blender.app/Contents/MacOS/Blender \
--background --python build_office.py -- --render
Pendant la construction, l'agent ne voit rien. Il décrit, en mètres. La pièce fait 4,2 m sur 5,2 m : des boîtes, tout bêtement, jusqu'au mur de droite qu'il a fallu découper en quatre panneaux pour y percer la fenêtre :
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)
# Mur droit PERCÉ d'une fenêtre (ouverture 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) # sous la fenêtre
box('wall_right_b', (0.06, 5.2, 0.5), (2.1, 0, 2.75), WALL) # au-dessus
Le mobilier n'a pas été modélisé. Tout vient de Poly Haven, une bibliothèque d'objets scannés en licence CC0 qu'on interroge par API : le bureau métallique, le fauteuil, la lampe articulée, le téléviseur CRT, le laptop des années 90. Une seule fonction, place(), importe chaque objet, le mesure, le remet à l'échelle et le pose au sol. Le raisonnement d'un décorateur : ce bureau fait 78 cm, il va là, tourné comme ça.
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))
Le désordre aussi est du code
Un bureau rangé ne raconte rien ; celui-ci avait besoin d'un passé. Le module clutter.py n'importe aucun asset. Des primitives et des règles, c'est tout. Piles de A4 jamais tout à fait droites, dossiers dépareillés, câbles qui pendent en caténaire, quatorze post-its. Chaque pile a sa graine aléatoire et son paramètre messiness : à 0 la pile est nette, à 1 le commentaire du script parle de « bazar de fin de nuit » :
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) # collés au mur
La lumière fait le film
Quatre sources. La lampe de bureau, chaude, qui porte toute la scène. Une lumière de ville, froide, à travers les stores vénitiens. Les écrans. Et un tiroir resté entrouvert, d'où fuit une lumière dorée. Ce qu'il contient ne se dira pas dans ce carnet.
key.data.energy = 180
key.data.color = (1.0, 0.78, 0.5) # la lampe : chaude, la clé
moon.data.color = (0.6, 0.71, 0.95) # la ville : froide, par les stores
box('drawer_gold', ..., emit=(1.0, 0.72, 0.28), strength=90) # le tiroir
scene.view_settings.view_transform = 'AgX' # + look 'AgX - Punchy'
Le tout passe par la transformation de couleur AgX, celle qui roule doucement les hautes lumières au lieu de les cramer en blanc, comme le faisaient les rendus 3D d'il y a dix ans.
L'agent se relit
Le premier rendu n'était pas bon.
Personne n'est intervenu entre ces deux images. L'agent a rendu la scène, regardé le résultat, remarqué l'écran surexposé qui fixait la caméra, puis corrigé son propre script : le poste pivote vers le fauteuil, l'émission baisse, la teinte refroidit. La correction qu'un chef opérateur ferait à l'œil, faite ici en relisant du code.
Les chiffres, sur un simple MacBook M1
- ≈ 3 min 20 par image en 1080p, 256 échantillons adaptatifs, débruitage GPU
- 63 Mo la scène source (.blend), des centaines d'objets
- 6,6 Mo le même décor, prêt pour le navigateur
- 0 clic dans l'interface de Blender
Le pont vers le navigateur : cuire la lumière
Aucun téléphone ne calculera cet éclairage en direct, et il n'en a pas besoin. L'astuce est vieille comme le jeu vidéo : calculer la lumière une fois, puis la peindre sur les murs. C'est le bake.
Le second script fusionne la scène en deux objets, la coquille (murs, sol, plafond, stores) et le contenu (meubles, désordre), déplie chacun sur un atlas UV neuf et cuit l'éclairage Cycles dans deux textures. Puis il remplace les matériaux. Le fichier exporté ne contient plus une seule lampe : la lumière est devenue la texture. Restent émissifs les écrans et l'or du tiroir, qui continuent de vivre en temps réel :
groups = {'shell': murs_sol_plafond, 'stuff': tout_le_reste}
bpy.ops.uv.smart_project(island_margin=0.002)
bpy.ops.uv.pack_islands(margin=0.003) # sinon les îlots s'entassent dans un coin
bpy.ops.object.bake(type='COMBINED', margin=8, use_clear=True)
bpy.ops.export_scene.gltf(filepath='office_baked.glb', export_format='GLB')
Trois pièges rencontrés en chemin :
1. L'image cuite doit être sauvée manuellement par script : la sauvegarde automatique du bake est cassée en headless.
2. Sans pack_islands après l'unwrap, tous les îlots UV s'entassent dans un coin de l'atlas.
3. Sur M1, un bake GPU peut sortir des artefacts : le même bake refait en CPU les élimine.
Au bout de la chaîne : un GLB de 6,6 Mo que three.js charge comme n'importe quel modèle. Sauf que celui-là embarque un éclairage de cinéma qui ne coûte plus rien à calculer.
Ce que ça change, aussi pour votre entreprise
Ce carnet ne cherche pas à vendre de la 3D. La 3D est notre banc d'essai, le plus exigeant qu'on ait trouvé : géométrie, lumière et budget de performance doivent être justes en même temps. Ce qui compte, c'est la mécanique en dessous : un agent IA sait piloter n'importe quel logiciel qui s'automatise par code. Il ne clique pas plus vite qu'un humain. Il écrit, il exécute, il lit le résultat, il se corrige.
Mettez votre ERP, votre outil de planification ou votre chaîne documentaire à la place de Blender : la boucle ne change pas. C'est celle que nous installons chez nos clients.