Un escalier en colimaçon de seize marches. À la main, chaque marche se duplique, pivote et monte d’un cran. En Python, l’escalier entier tient en une cinquantaine de lignes. Et pour passer à vingt-quatre marches, il suffit de changer un chiffre.

Ce petit pouvoir est partout dans Blender. L’interface elle-même est décrite en Python, comme les extensions que tu installes. Le revers, c’est qu’un fichier .blend peut aussi en transporter. Fin 2025, des modèles 3D piégés l’ont rappelé à tout le monde.

Voici comment écrire tes premiers scripts, et pourquoi certains rament. Puis quand préférer Geometry Nodes, et comment éviter la morsure. Avec, pour finir, la dernière porte d’entrée de Python dans Blender : l’IA.

Rendu 3D d'un escalier en colimaçon en bois et métal noir sur un sol de tomettes hexagonales, son ombre en spirale projetée sur un mur blanc
L’escalier et le sol sortent des deux scripts de cet article. Bois, métal, mur et lumière ont été ajoutés pour le rendu.

À quoi sert Python dans Blender ?

Python est la langue maternelle de Blender. Ses menus, ses panneaux et ses barres d’outils sont décrits par des scripts Python livrés avec le logiciel. Un script Script Programme court écrit en code (Python, MEL, MAXScript...) qui automatise des tâches ou ajoute des fonctionnalités à un logiciel 3D. Voir la définition complète → peut donc faire tout ce que fait l’interface : modifier une scène, un maillage, un matériau, tes raccourcis.

Ce n’est pas une nouveauté. Une page de documentation datée de mai 2001 décrit déjà l’API Python des versions antérieures à la 2.04. C’était l’époque de NaN, la société qui éditait Blender avant sa libération en 2002. Depuis Blender 5.1, c’est Python 3.13 qui tourne sous le capot.

Concrètement, Python sert à trois choses. Automatiser une corvée : renommer trois cents objets, rendre douze caméras, exporter un dossier entier. Générer de la géométrie à partir de règles. Et fabriquer des outils, ces add-ons Add-on Extension logicielle ajoutant des fonctionnalités à un logiciel 3D. Permet d'automatiser des tâches, ajouter des outils ou intégrer des services externes. Voir la définition complète → qui ajoutent un bouton ou un panneau.

Pour s’y retrouver, cinq noms suffisent.

Le vocabulaire de base
bpy.dataLes données : objets, maillages, matériaux
bpy.contextCe qui est actif : scène, sélection
bpy.opsLes opérateurs, c'est-à-dire les actions des menus
bmeshLe maillage, sommet par sommet
mathutilsVecteurs, matrices et rotations

Où écrire un script dans Blender ?

Dans l’atelier Scripting, l’onglet du même nom en haut de la fenêtre. Il réunit un éditeur de texte, la console Python et le journal Info. Quatre gestes suffisent pour démarrer.


Active les infobulles Python

Dans Edit > Preferences > Interface, panneau Display, coche Developer Extras et Python Tooltips. Au survol, chaque bouton donne alors son nom en Python.


Espionne le journal Info

Chaque action faite à la souris s’y inscrit en Python. Clique sur la ligne, copie-la avec Ctrl+C, colle-la dans ton script.


Teste dans la console

La console Python exécute une ligne à la fois. Tape bpy.data. puis la touche Tab : elle propose la suite.


Lance ton script

Dans l’éditeur de texte, clique sur New, colle le code, puis Alt+P ou le bouton lecture. Le menu Templates > Python offre aussi des exemples prêts à lancer.


Ton premier script : un escalier en colimaçon

Voici l’escalier de l’image d’ouverture. Colle ce code dans l’éditeur de texte et lance-le. Il fonctionne tel quel dans Blender 4.2 comme dans la 5.2.

import bpy, bmesh
from math import cos, sin, tau

MARCHES = 16     # nombre de marches
TOURS = 1.0      # tours complets
HAUTEUR = 3.0    # hauteur à gravir, en mètres
RAYON = 1.1      # longueur des marches, depuis l'axe
FUT = 0.1        # rayon du fût central


def cercle(cx, cy, r, cotes):
    """Les coins d'un polygone régulier, autour de (cx, cy)."""
    return [(cx + r * cos(tau * k / cotes), cy + r * sin(tau * k / cotes)) for k in range(cotes)]


def prisme(bm, coins, z0, z1):
    """Un volume vertical, de z0 à z1, posé sur une liste de coins."""
    bas = [bm.verts.new((x, y, z0)) for x, y in coins]
    haut = [bm.verts.new((x, y, z1)) for x, y in coins]
    bm.faces.new(haut)
    bm.faces.new(bas[::-1])
    n = len(coins)
    for k in range(n):
        bm.faces.new((bas[k], bas[(k + 1) % n], haut[(k + 1) % n], haut[k]))


bm = bmesh.new()
pas = HAUTEUR / MARCHES            # hauteur d'une marche
ouverture = tau * TOURS / MARCHES  # angle couvert par une marche

for i in range(MARCHES):
    a0, a1 = i * ouverture, (i + 1.05) * ouverture  # léger recouvrement
    z = (i + 1) * pas
    marche = [(r * cos(a), r * sin(a)) for r, a in
              ((FUT, a0), (RAYON, a0), (RAYON, a1), (FUT, a1))]
    prisme(bm, marche, z - 0.05, z)
    # un barreau au bout de la marche, 90 cm de haut
    milieu = (a0 + a1) / 2
    bx, by = (RAYON - 0.05) * cos(milieu), (RAYON - 0.05) * sin(milieu)
    prisme(bm, cercle(bx, by, 0.012, 8), z, z + 0.9)

prisme(bm, cercle(0, 0, FUT, 32), 0, HAUTEUR)  # le fût central

maillage = bpy.data.meshes.new("Escalier")
bm.to_mesh(maillage)
bm.free()
escalier = bpy.data.objects.new("Escalier", maillage)
bpy.context.collection.objects.link(escalier)

# la main courante : une hélice posée sur le haut des barreaux
courbe = bpy.data.curves.new("Rampe", 'CURVE')
courbe.dimensions = '3D'
courbe.bevel_depth = 0.025
spline = courbe.splines.new('POLY')
spline.points.add(MARCHES * 8)
for j, point in enumerate(spline.points):
    t = j / (MARCHES * 8) * (MARCHES - 1)  # de la 1re à la dernière marche
    a = (t + 0.525) * ouverture
    point.co = ((RAYON - 0.05) * cos(a), (RAYON - 0.05) * sin(a), (t + 1) * pas + 0.9, 1)
rampe = bpy.data.objects.new("Rampe", courbe)
bpy.context.collection.objects.link(rampe)

Les cinq constantes du début forment ton panneau de réglages. Viennent ensuite deux petites fonctions. La première calcule les coins d’un polygone régulier. La seconde dresse un volume sur une liste de coins : une face dessus, une dessous, et une par côté.

La boucle s’en sert pour chaque marche, puis pour son barreau. Hors de la boucle, la même fonction dresse le fût central. Le module bmesh assemble tout en un seul maillage, et bm.to_mesh() le range dans la scène.

La main courante est une courbe : une hélice posée sur le haut des barreaux. Le réglage bevel_depth lui donne son épaisseur, sans un seul polygone à modéliser.

Change MARCHES, TOURS ou HAUTEUR, relance, et tu obtiens un autre escalier. À la main, passer de seize à vingt-quatre marches obligerait à recaler chaque marche : leurs hauteurs changent toutes.

Trois escaliers en colimaçon générés par le même script Python : un quart de tour bas, un tour complet, deux tours hauts
Le même script, trois réglages. Seules les constantes MARCHES, TOURS et HAUTEUR ont changé.

Pourquoi mon script Blender est-il si lent ?

Parce qu’il passe sans doute par les opérateurs. C’est le réflexe naturel : on copie la ligne du journal Info, puis on la glisse dans une boucle.

for i in range(MARCHES):
    angle = i * ouverture
    bpy.ops.mesh.primitive_cube_add(size=1, location=(0.55 * cos(angle), 0.55 * sin(angle), (i + 1) * pas),
                                    rotation=(0, 0, angle), scale=(1.0, 0.3, 0.05))

Pour en mesurer le prix, on a construit le même escalier de cinq façons dans Blender 5.2.3. Une simple boîte par marche, de 16 à 65 536 marches. Le chronomètre tourne jusqu’à ce que la scène soit prête.

Graphique en échelles logarithmiques : le temps des opérateurs et de bmesh.ops en boucle explose avec le nombre de marches, les trois autres méthodes restent sous quelques secondes
À 16 marches, tout est instantané. À 4 096, les opérateurs mettent plus de 8 minutes, le maillage direct 37 millisecondes.

À seize marches, aucune différence : tout passe sous les dix millisecondes. C’est à grande échelle que le piège se referme. Avec les opérateurs, chaque marche coûte plus cher que la précédente. Dans un escalier de 16 marches, chacune prend une demi-milliseconde. Dans un escalier de 4 096, la moyenne passe à 120 millisecondes par marche. Au total, 8 minutes et 13 secondes.

Le nombre d’objets n’y est pour rien. Créés directement par bpy.data, 4 096 objets prennent un tiers de seconde. Le coût vient de l’opérateur lui-même : il refait tout ce que ferait le menu. Et la facture grimpe avec la taille de la scène.

Deuxième surprise, bmesh n’est pas un vaccin. Ses opérateurs maison, les bmesh.ops, s’effondrent eux aussi dans une boucle : 2 minutes 44 pour 16 384 marches. Notre script d’escalier crée donc ses sommets et ses faces un à un. Ainsi bâti, le maillage direct avale 65 536 marches en 0,6 seconde.

La règle est simple. Un opérateur pour une action ponctuelle, comme à la souris. Pour une boucle, écris directement dans les données : bpy.data, ou des sommets et des faces créés à la main.

Python ou Geometry Nodes : lequel choisir ?

Depuis Blender 2.92, en février 2021, Geometry Nodes génère de la géométrie avec des nœuds, sans code. Pour un escalier, il bat même tous nos scripts : 65 536 marches en 29 millisecondes. Et il garde un atout décisif : le réglage reste vivant. Tu changes le nombre de marches, l’escalier suit, sans rien relancer.

Détail amusant : l’arbre de nœuds de notre test a été construit par un script Python. Les deux outils ne s’opposent pas, ils se complètent.

Python reprend la main dès qu’on sort de la géométrie. Les nœuds ne savent ni lancer un rendu, ni renommer une collection, ni traiter un dossier entier. Ce script rend chaque caméra de la scène dans son propre fichier :

import bpy

scene = bpy.context.scene
for camera in [o for o in scene.objects if o.type == 'CAMERA']:
    scene.camera = camera
    scene.render.filepath = f"//rendus/{camera.name}"
    bpy.ops.render.render(write_still=True)

Ici, un opérateur par caméra ne pose aucun problème : il n’y en a qu’une poignée. Pour que chaque image sorte plus vite, joue aussi sur les réglages de rendu.

Qui fait quoi
Une forme qui doit rester modifiableGeometry Nodes
Une corvée sur des fichiers, des rendus, des nomsPython
Un outil à partager, avec bouton et panneauPython, en extension
Des milliers de copies d'un même objetGeometry Nodes, en instances

Pourquoi un vieux script Blender ne marche plus ?

Parce que l’API bouge à chaque version. Un exemple frais : régler un modificateur Geometry Nodes depuis Python. Jusqu’à la 5.1, on écrivait modificateur["Socket_2"] = 24. Depuis Blender 5.2, cette ligne déclenche une erreur. Il faut écrire modificateur.properties.inputs.Socket_2.value = 24. On l’a vérifié dans les deux versions : chaque écriture ne marche que dans la sienne.

Avant d’accuser ton code, ouvre donc les notes « Python API » de ta version. Et garde la console système ouverte : sous Windows, Window > Toggle System Console affiche le message d’erreur complet.

Créer un matériau avec Python : un sol de tomettes

Python sait aussi poser des nœuds de matériau. Ce second script dalle le sol de l’image d’ouverture. Tel quel, il pose 900 tomettes hexagonales, chacune avec sa teinte. Pour couvrir tout le cadre de l’image, RANGS est simplement passé à 100.

import bpy, bmesh, random
from math import cos, sin, tau, sqrt

COTE = 0.09      # côté d'une tomette, en mètres
JOINT = 0.006    # largeur du joint
RANGS = 30       # tomettes par rangée, et nombre de rangées
random.seed(2026)

bm = bmesh.new()
alea = bm.faces.layers.float.new("alea")   # un nombre au hasard par tomette
largeur = sqrt(3) * COTE                   # d'un côté plat à l'autre
r = COTE - JOINT / sqrt(3)                 # la tomette, joint déduit

for rang in range(RANGS):
    for col in range(RANGS):
        cx = col * largeur + (rang % 2) * largeur / 2
        cy = rang * 1.5 * COTE
        sommets = [bm.verts.new((cx + r * cos(a), cy + r * sin(a), 0))
                   for a in (tau * (k + 0.5) / 6 for k in range(6))]
        tomette = bm.faces.new(sommets)
        tomette[alea] = random.random()

maillage = bpy.data.meshes.new("Tomettes")
bm.to_mesh(maillage)
bm.free()
sol = bpy.data.objects.new("Tomettes", maillage)
bpy.context.collection.objects.link(sol)
sol.modifiers.new("Épaisseur", 'SOLIDIFY').thickness = 0.015
biseau = sol.modifiers.new("Biseau", 'BEVEL')
biseau.width, biseau.segments = 0.002, 2

# la terre cuite : le nombre au hasard choisit la teinte de chaque tomette
mat = bpy.data.materials.new("Terre cuite")
mat.use_nodes = True                       # superflu en 5.x, utile en 4.x
noeuds, liens = mat.node_tree.nodes, mat.node_tree.links
bsdf = noeuds["Principled BSDF"]
attribut = noeuds.new("ShaderNodeAttribute")
attribut.attribute_name = "alea"
degrade = noeuds.new("ShaderNodeValToRGB")
degrade.color_ramp.elements[0].color = (0.33, 0.07, 0.03, 1)
degrade.color_ramp.elements[1].color = (0.62, 0.22, 0.09, 1)
liens.new(attribut.outputs["Fac"], degrade.inputs["Fac"])
liens.new(degrade.outputs["Color"], bsdf.inputs["Base Color"])
bsdf.inputs["Roughness"].default_value = 0.7
sol.data.materials.append(mat)

Deux idées font tout le travail. D’abord, une rangée sur deux se décale d’une demi-tomette : c’est le secret du pavage hexagonal. Ensuite, chaque tomette reçoit un nombre au hasard, rangé dans un attribut nommé alea. Le matériau le lit avec un nœud Attribute, et un dégradé le change en teinte de terre cuite.

L’épaisseur et le biseau ne sont pas modélisés : deux modificateurs s’en chargent, ajoutés par le script. Quant à la ligne mat.use_nodes = True, elle ne sert plus à rien depuis Blender 5.0. Un matériau neuf y naît déjà avec ses nœuds. La propriété est dépréciée et doit disparaître en 6.0. Elle reste indispensable en 4.2, où un matériau neuf naît sans nœuds.

Gros plan sur des tomettes hexagonales en terre cuite aux teintes variées, séparées par de fins joints
Gros plan sur le sol du script : chaque tomette a tiré sa teinte au hasard.

Extensions Blender : le Python que tu installes

Un add-on n’est rien d’autre qu’un script Python doté d’un mode d’emploi. Depuis Blender 4.2, ils se distribuent sous forme d’extensions, depuis extensions.blender.org ou directement dans le logiciel. Les anciens add-ons, eux, s’installent toujours depuis le disque.

Chaque extension embarque un manifeste, le fichier blender_manifest.toml. Elle doit y déclarer ses permissions : fichiers, réseau, presse-papiers, caméra ou micro, avec une raison pour chacune. Une extension qui va sur Internet doit aussi respecter le réglage Allow Online Access, coupé par défaut.

Ces permissions informent, elles n’enferment pas. Le code d’une extension garde tous les droits d’un script. Python « ne restreint pas ce qu’un script peut faire », prévient la doc de Blender. Installe donc une extension comme un logiciel : depuis une source connue. Bien choisis, certains add-ons incontournables font gagner des heures. Et MB-Lab, qui génère des personnages entiers, montre jusqu’où peut aller un add-on écrit en Python.

Fichier .blend piégé : le Python qui s’exécute à l’ouverture

Fin novembre 2025, l’éditeur de sécurité Morphisec a donné l’alerte, rapporte The Hacker News. La campagne durait depuis au moins six mois. Des fichiers .blend déposés sur CGTrader cachaient un script, Rig_Ui.py. Exécuté à l’ouverture, il téléchargeait un script PowerShell, qui récupérait deux archives. Dedans, StealC V2, un voleur de données, et un second voleur écrit en Python. Mots de passe enregistrés, portefeuilles de cryptomonnaie, messageries : tout y passait.

Le nom n’a rien d’un hasard. Rigify, l’outil de rigging livré avec Blender, glisse dans chaque rig Armature (Rig) Structure de squelette composée d'os (bones) utilisée pour animer des personnages, créatures ou objets articulés en 3D. Voir la définition complète → un script d’interface, réglé pour s’exécuter au chargement. Sans lui, le panneau du rig n’apparaît pas. Beaucoup d’animateurs autorisent donc l’exécution automatique, et un faux script de rig passe inaperçu.

Par défaut, Blender bloque deux choses à l’ouverture. Les textes cochés Register, qui s’exécutent au chargement. Et les drivers dont l’expression Python va au-delà du calcul. On l’a vérifié avec un fichier piégé maison, au script inoffensif : il écrit un simple fichier témoin. Sans autorisation, rien ne se passe. Les drivers qui lisent les données de la scène ou importent un module restent inactifs. Les expressions de pur calcul, elles, passent. Avec l’autorisation, le témoin apparaît sans un mot de Blender.

Allow Execution n’est pas un « OK ». À l’ouverture d’un fichier bloqué, Blender propose ce bouton. Il recharge le fichier en lui faisant confiance : tous ses scripts s’exécutent, sans distinction. Lis-les avant de cliquer.


Laisse la case décochée

Dans Edit > Preferences > Save & Load, panneau Blend Files, Auto Run Python Scripts est décoché par défaut. Garde-le ainsi.


Exclus tes téléchargements

Si tes rigs l’exigent, coche-le, mais ajoute ton dossier de téléchargements aux Excluded Paths. C’est la configuration que suggère la doc de Blender.


Lis avant d'autoriser

Fichier inconnu ? Avant Allow Execution, ouvre l’atelier Scripting et parcours les textes du fichier. Un script de rig n’a aucune raison de télécharger quoi que ce soit.


Inspecte sans rien lancer

Dans un terminal, blender -b -Y fichier.blend --python-expr "import bpy; print(bpy.data.texts.keys())" liste les scripts du fichier sans les exécuter.


Et pour le reste de ta machine, les mêmes réflexes valent contre les malwares en général.

Blender MCP : quand une IA écrit le Python à ta place

MCP, pour Model Context Protocol, permet à un assistant IA d’utiliser des outils. Côté Blender, le principe ne change pas d’un projet à l’autre. Une extension ouvre une porte dans le logiciel, l’IA y envoie du code Python, et Blender l’exécute.

La version la plus connue s’appelle aujourd’hui MCP for Blender, ex-blender-mcp. C’est un projet communautaire sous licence MIT, qui dépasse les 32 000 étoiles sur GitHub. Son outil execute_blender_code permet, selon son README, de lancer « du code Python arbitraire dans Blender ». Le même README conseille de toujours enregistrer ton travail avant. Il précise aussi que sa connexion locale n’a ni authentification ni chiffrement. Un mode sûr, facultatif, s’active avec la variable BLENDER_MCP_SAFE_MODE=1. Il vérifie chaque script avant de le lancer. Il bloque la lecture ou l’écriture directe de fichiers, le lancement d’autres programmes et le réseau.

Blender a désormais son propre serveur, issu de son laboratoire : MCP Server. Signé par la Blender Foundation, il demande Blender 5.1 ou plus. Sa page de démonstration le branche sur un modèle local, sans envoyer ta scène dans le cloud. Et elle ne cache rien : le serveur exécute le code généré par l’IA sans aucun garde-fou. Rien n’empêche ce code d’effacer tes données, ou de les envoyer ailleurs. La fondation conseille donc une machine virtuelle, ou un système sans données sensibles.

Notre avis : MCP ne remplace pas Python, il en écrit davantage. Chaque ligne qu’il lance a les mêmes droits que toi sur ta machine. Utilise-le pour explorer l’API ou débroussailler une scène, dans une machine virtuelle. Puis relis ce qu’il a produit et garde les bons morceaux : c’est encore la meilleure façon d’apprendre.

Par où commencer ?


Branche les infobulles

Developer Extras et Python Tooltips : chaque bouton te dit alors son nom en Python.


Recopie l'escalier

Lance le script de cet article, puis change trois chiffres. Tu viens d’écrire ton premier générateur.


Chasse une corvée

Repère la tâche que tu répètes chaque semaine et retrouve sa ligne dans le journal Info. Une boucle, et c’est réglé.


Garde la case décochée

Auto Run ne s’active que pour tes propres dossiers. Un fichier inconnu se lit avant de s’exécuter.


La documentation officielle de l’API reste la référence. Pour le reste, Blender a bien d’autres cordes à son arc. Quelques livres pour apprendre Blender aident à les découvrir.