Infoforall

BLENDER PYTHON - 01 - Utiliser Python pour créer des objets

Voici le genre d'objet assez pénible à faire à la main :

Image créée par script

Utiliser Python dans Blender va ainsi permettre d'automatiser certains placements.

1 - Console Python

Commençons par montrer où se trouve la console qui permet de rentrer du code en direct.

01° Ouvrir Python Console plutôt que info.

Menu

Agrandir un peu la fenêtre pour voir un peu plus de code. Ou appuyer sur le bouton console pour la placer en plein écran ou revenir à la configuration initiale.

Menu Menu

Vous devriez obtenir un message d'accueil du style :

PYTHON INTERACTIVE CONSOLE 3.5.1 (default, Feb 17 2016, 17:09:19) [MSC v.1800 64 bit (AMD64)]


Command History: Up/Down Arrow

Cursor: Left/Right Home/End

Remove: Backspace/Delete

Execute: Enter

Autocomplete: Ctrl-Space

Zoom: Ctrl +/-, Ctrl-Wheel

Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, blf, mathutils

Convenience Imports: from mathutils import *; from math import *

Convenience Variables: C = bpy.context, D = bpy.data

Ce texte vous explique surtout que certains modules sont déja importés dans cette console. Notamment les modules commençant par bpy (pour Blender Python).

02° Faire disparaitre le cube de départ PUIS taper ceci dans la console :

>>> bpy.ops.mesh.primitive_cube_add()

Vous devriez constater qu'un nouveau cube vient d'apparaitre juste sur le curseur 3D.

03° Décaler le cube avec les flèches de direction et retaper la ligne de code (CTRL+C, CTRL+V).

04° Avec un clic gauche, placer le curseur 3D à un autre endroit. Retaper la ligne de code.

Vous devriez au final obtenir un résultat du type :

Trois cubes

Comment fonctionne ce code ? Il suffit de faire un clic-droit sur le carré du menu Tools et de sélectionner Online Python reference pour trouver des informations complètes :

  1. aller dans le menu de création (CREATE) sur l'objet voulu
  2. rester statique au dessus du bouton voulu
ONGLET CREATION

Retenons déjà que

bpy.ops.mesh.primitive_cube_add()

veut dire :

Les points signalant les liaisons.

La documentation en ligne donne ceci :

bpy.ops.mesh.primitive_cube_add(radius=1.0, calc_uvs=False, view_align=False, enter_editmode=False, location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), layers=(False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))

Construct a cube mesh.


    Parameters:

  •     radius (float in [0, inf], (optional)) – Radius
  •     calc_uvs (boolean, (optional)) – Generate UVs, Generate a default UV map
  •     view_align (boolean, (optional)) – Align to View, Align the new object to the view
  •     enter_editmode (boolean, (optional)) – Enter Editmode, Enter editmode when adding this object
  •     location (float array of 3 items in [-inf, inf], (optional)) – Location, Location for the newly added object
  •     rotation (float array of 3 items in [-inf, inf], (optional)) – Rotation, Rotation for the newly added object
  •     layers (boolean array of 20 items, (optional)) – Layer

Remarquons que tous les arguments transmissibles sont optionnels. C'est pour cela qu'on peut créer un cube en ne notant rien entre les parenthèses de la méthode.

Mais on peut créer un cube ayant un radius de 2 en tapant :

>>> bpy.ops.mesh.primitive_cube_add(radius=2.0)

05° Créer un autre objet qu'un cube en vous renseignant sur le code à utiliser :

  1. aller dans le menu de création (CREATE) sur l'objet voulu
  2. rester statique au dessus du bouton voulu
ONGLET CREATION

Imaginons maintenant que nous voulions créer un cube mais en ne le plaçant pas à l'emplacement du curseur 3D. Pour cela, il faut renseigner le paramètre location.

On peut trouver la documentation facilement : plutôt que de rester statique au dessus de la touche de l'objet à créer, il faut faire un clic droit et sélectionner Online Python References. En regardant via la documentation, on trouve alors dans l'intitulé de la méthode :

bpy.ops.mesh.primitive_cube_add(radius=1.0, ... location = (0.0, 0.0, 0.0), rotation = (0.0, 0.0, 0.0), ...)

On voit donc que certains paramètres ont des valeurs par défaut.

Lorsqu'on note bpy.ops.mesh.primitive_cube_add(), location prend la valeur par défaut : (0.0, 0.0, 0.0).

location = (0.0, 0.0, 0.0)

Pourquoi avoir noter cela avec des parenthèses rouges ?

Et bien parce que c'est important pour la suite ! On n'envoie pas un 0.0 puis un 0.0 puis un 0.0.

On envoie les trois 0.0 d'un coup dans un objet qui comporte 3 données. On nomme cela un N-uplets. C'est un type de données :

  • ouvert par une parenthèse,
  • dont les valeurs sont séparées par des virgules,
  • fermé par une parenthèse

Ici, nous avons un 3-uplet. On nomme également cela tuple.

06° Créer un cube en utilisant bpy.ops.mesh.primitive_cube_add(location=(5,5,0)).

Trois cubes

Cela donne :

Trois cubes

Vous pouvez constatez qu'on travaille depuis l'origine O (0,0,0) du plan. Vous pouvez changer les valeurs pour vous en convaincre.

Voilà pour le premier contact. Il vous reste à voir comment créer un script dans un fichier plutôt que de taper les instructions à chaque fois.

2 - Script

La console est bien pratique mais elle ne permet pas de stocker du code pour pouvoir le réutiliser au besoin. Pour cela, nous allons devoir créer un script : enregistrer un fichier d'extension .py qui va contenir notre "programme". Puisque ce programme n'est pas autonome, mais est destiné à être utilisé par Blender, on ne le nomme pas programme mais script.

07° Pour créer un script, remplacer la console par text editor.

Vous devriez pour l'instant avoir ceci :

Python console

Et vous allez passer à :

Text editor

08° Utiliser new pour créer un nouveau fichier qui va nous permettre de créer un fichier python .py.

Voici le script que nous allons utiliser :

import bpy # On importe la bibliothèque Blender Python

bpy.ops.mesh.primitive_cube_add( location = (0,0,0))

bpy.ops.mesh.primitive_cube_add( location = (5,5,0))

bpy.ops.mesh.primitive_cube_add( location = (5,-5,0))

bpy.ops.mesh.primitive_cube_add( location = (-5,5,0))

bpy.ops.mesh.primitive_cube_add( location = (-5,-5,0))

L'interpréteur Python va suivre le script dans l'ordre, comme si vous aviez tapé les lignes les unes après les autres :

CLIQUEZ ICI POUR VOIR LE DEROULEMENT :

09° Utiliser le code pour voir le résultat en appuyant sur Run Script.

Text editor

Et voilà. Vous avez vu les bases fondamentales de la manipulation d'objets via Blender.

Quelques remarques :

  • Pour passer sur une vue plus grande du script, il faut utiliser VIEW - Toggle Max Area.
  • Menu View
  • Pour enregistrer le script, il faut utiliser TEXT - Save as. On y trouve également le choix OPEN pour ouvrir un fichier préexistant.
  • Menu Text
  • Pour convertir les espaces en tabulation, il faut utiliser FORMAT - Convert Whitespace.
  • Menu Convert
  • Si une erreur survient, pensez à cliquer sur l'icone Blender dans le menu bas de l'écran : vous aurez ainsi accés à la console qui affiche en direct les actions et erreurs qui sont survenues dans le logiciel. C'est toujours pratique de savoir pourquoi le script ne fonctionne pas. Sans cela, pas facile de savoir d'où vient l'erreur.
  • Menu Convert
  • Si vous ne parvenez plus à atteindre la console, vous pouvez la faire apparaître à l'aide d'un des menus de info - Window - Toggle System Console.

    Menu Convert
  • ERREUR TYPIQUE : lorsqu'on tape les coordonnées, on utilise parfois le systême français des virgules. Pour affecter une coordonnée x à 2,5 vous risquez de taper x=2,5 ! Attention, avec Python, c'est le systême anglosaxon qu'il faut utiliser : x = 2.5. Utilisez donc bien le clavier numérique si vous en avez un et vérifier bien cette histoire de point et de virgule dès qu'il y a un nombre "à virgule".

3 - Afficher des choses sur la console

Nous allons quitter Blender pendant quelques minutes. Pour aborder cette partie, nous allons revenir à l'utilisation de code Python classique et pas des méthodes propres à Blender. Pour cela, modifier la vue 3D pour y afficher la console Python.

Menu

Commençons par voir comment afficher des choses en commande directe sur la console Python.

10° Dans la console Python de Blender (vous devriez voir apparaitre les trois chevrons), taper le code suivant :

>>> 9*9+2

>>> 12-2*0.8888

Bref, on remarquera qu’on lance des calculs en temps réel. Puisqu’on l’utilise notamment pour faire des calculs, on dispose de nombreuses fonctions :

11° Taper les codes suivants qui illustrent trois fonctions différentes :

>>> 14/3

donne 4.666666667.

Approximatif mais le nombre de chiffres significatifs devraient permettre une résolution correcte des problèmes physiques.

>>> 14//3

renvoie 4, la partie entière de la division de 14 par 3 qui vaut 4,6666666667.

>>> 14%3

renvoie 2, le reste de la division : 14 = 4x3 + 2. On parle également de modulo, comme pour les angles qui sont connus modulo 360° ou 2Π rad.

>>> 3**2

renvoie 9, soit 32.

Regardons maintenant comment afficher des caractères dans la console.

12° A votre avis, que fait ce code ? >>> print("Hello World !")

13° Et là ? >>> print("Hello W"+"orld !")

Si vous voulez afficher un ", c’est simple : on utilise l’antislash \ avant le signe lui même.

>>> print("Comme on dit souvent : \"Hello World !\"")

14° A votre avis, que fait ce code ?

Premier constat : puisqu’on a une instruction par ligne, pas besoin de mettre de code de fin d’instruction. Pas de ; ou de : ou de . tout court comme dans certains langages..

Remarque :

\ se nomme antislash ou backslash.

/ se nomme slash.

Sur la plupart des systèmes d'exploitation, les adresses sur des périphériques de données s'écrivent avec la barre oblique. Pour Microsoft Windows, c'est la barre oblique inversée (exemple : C:\Mes Documents\Mes Images) alors que dans les systèmes UNIX, ainsi que pour les adresses réseau et internet (URL), les adresses de fichier s'écrivent avec la barre oblique normale (exemple dans votre barre d'adresse).

Pour finir, pour formater un affichage via des tabulations, on peut utiliser \t, avec t comme tabulations.

Du coup, l’antislash est un caractère spécial puisqu’il sert à coder des fonctions particulières comme la tabulation. Comment afficher un antislash alors ? C’est simple … on en met deux à la suite.

>>> print("Nom\tPrenom\tAge")

>>> print("Voilà un antislash \\")

15° Qu’affiche ce code ?

Pour afficher un nombre (120 par exemple), vous pouvez utiliser

>>> print ("120") pour afficher la chaîne de caractères 120 ou

>>> print(120) pour afficher le nombre 120.

Pour un humain, c'est pareil mais pas pour l'ordinateur : Pour lui "120" est du même type qu'une chaîne comme "ABC".

16° Tenter de deviner ce que vont afficher les codes suivants. Taper et exécuter le code une fois que vous pensez avoir la réponse.

>>> print(120*2)

>>> print("120"*2)

>>> print("120"+2)

17° A votre avis, pourquoi le dernier cas ne donne-t-il rien d’interprétable ?

...CORRECTION...

Si on veut deux fois le nombre 120, on obtient 240.

Si on veut deux fois la chaîne "120", on obtient "120120".

Par contre, Python ne sait absolument pas additionner une chaîne de caractères et un nombre ... En même temps, que feriez-vous si on vous demandait de faire la somme de "ABC" et du nombre 2.

Il nous reste à voir le passage à la ligne. Si vous voulez afficher "Bon" sur une ligne et "jour" sur la ligne suivante, il suffit d'utilser un caractère spécial à la fin de "Bon". Lequel ? \n : on obtient alors la chaîne de caractères "Bon\njour".

18° Afficher, avec un print("Bon\njour"), la chaîne "Bon\njour" pour voir comment Python interprète votre chaîne.

On obtient donc :

>>> print("Bon\njour")

Bon

jour

Voilà. Vous connaissez les bases de l'affichage via la console.

4 - Variables

Voyons maintenant comment stocker des informations pour les réutiliser plus tard.

19° Taper ceci dans la Console Python :

>>> a = 5

>>> print(a)

5

Et voilà, vous venez de créer votre première variable : vous avez stocké 5 dans une zone mémoire qu'on pourra retrouver en tapant simplement a.

Ainsi, à chaque fois qu'on tapera a dans le script, Python remplacera cette variable par ce qui est stocké à l'adresse correspondante.

Vous pouvez voir les variables comme un raccourci pour atteindre une zone mémoire sans avoir à fournir son adresse réelle.

Ici, votre variable contient un entier, un Integer en langage informatique.

20° Expliquer (sans la taper) ce que va alors donner l'instruction ci-dessous ? Taper l'instruction pour vérifier.

>>> print(a*2)

10

Et si nous plaçions un string dans la variable a ?

>>> a = "5"

>>> print(a*2)

55

21° Pourquoi obtient-on "55" et pas 10 ?

...CORRECTION...

On crée une variable a qui désigne l'adresse d'une zone mémoire qui contient un STRING "5".

Lorsqu'on demande de multiplier le string par 2, Python va alors simplement comprendre qu'on veut 2 "5" , soit "55" .

Comme vous le voyez, connaitre le type des données est important. Comment savoir à l'avance ce que désigne une variable ? Il faut utiliser une fonction native de Python : type.

22° Lancer les instructions suivantes pour comprendre ce que fait cette fonction :

>>> premiere = 5

>>> type(premiere)

>>> deuxieme = "5"

>>> type(deuxieme)

>>> troisieme = 5.0

>>> type(troisieme)

...CORRECTION...

La fonction type permet donc d'obtenir le type de données stocké à l'adresse mémoire pointée par la variable.

Si on stocke 5, on obtient une variable de type int pour integer (nombre entier)

Si on stocke "5", on obtient une variable de type str pour string (chaîne de caractères)

Si on stocke 5.0, on obtient une variable de type float pour float (nombre réel ou nombre à virgule flottante)

Les types de variables disponibles et les contenus attendus de ces variables sont donnés ci-dessous :

Type de variableNom du type pour PythonCe qu'il peut contenir
Booléen/BooleanboolFalse or True (avec une majuscule)
Entier/IntegerintUn nombre entier (attention aux limites maximales) comme 12
Nombre réelfloatUn nombre à virgule (attention aux limites maximales) comme 12.0 ou 12.5
Nombre complexecomplexUn nombre complexe comme z = 145 + 2i
Chaîne de caractèrestringUne chaîne de caractères, c'est-à-dire un mot ou une phrase. On la définit entre deux guillemets ou apostrophes."chaîne de caractère"'autre chaîne de caractère'

On peut bien entendu tenter de transformer un type de variable en une autre. Pour cela, on utilise les fonctions natives suivantes :

23° Lancer les instructions suivantes pour comprendre ce que font ces fonctions :

>>> a = 5

>>> type(a)

>>> print(a*2)

>>> b = str(a)

>>> type(b)

>>> print(b*2)

...CORRECTION...

1e cas : a est un integer. On obtient un string b.

b désigne "5".

2*b désigne "55"

>>> c = 5

>>> type(c)

>>> print(c*2)

>>> d = float(c)

>>> type(d)

>>> print(d*2)

...CORRECTION...

2e cas : c est un integer. On obtient un float d.

d désigne 5.0

2*d désigne 10.

>>> e = "5"

>>> type(e)

>>> print(e*2)

>>> f = int(e)

>>> type(f)

>>> print(f*2)

...CORRECTION...

1e cas : e est un string. On obtient un integer b.

b désigne 5.

2*b désigne 10.

Remarque : vous remarquerez que tous les types de variables commencent par une minuscule, pas une majuscule.

5 - Les variables dans Blender

Nous allons pouvoir les utiliser pour réaliser un script qui créer sensiblement la même chose à chaque mais en fonction d'un paramètre qu'on peut changer.

24° Revenir à une configuration de type Ecran pour la vue 3D et Text Editor pour la fenêtre du haut. Utiliser ensuite new pour créer un nouveau fichier qui va nous permettre de créer un fichier python .py.

Text editor

Voici le script Python que nous avions executé au début:

import bpy # On importe la bibliothèque Blender Python

bpy.ops.mesh.primitive_cube_add( location = (0,0,0))

bpy.ops.mesh.primitive_cube_add( location = (5,5,0))

bpy.ops.mesh.primitive_cube_add( location = (5,-5,0))

bpy.ops.mesh.primitive_cube_add( location = (-5,5,0))

bpy.ops.mesh.primitive_cube_add( location = (-5,-5,0))

Et bien, nous pourrions réecrire la même chose mais en utilisant une variable pour stocker 5.

25° Modifier le programme pour stocker ce 5 dans une variable puis utiliser cette variable pour dessiner les cubes plutôt que de taper réellement 5... Lancer votre script.

...CORRECTION...

import bpy # On importe la bibliothèque Blender Python

distance = 5

bpy.ops.mesh.primitive_cube_add( location = (0,0,0))

bpy.ops.mesh.primitive_cube_add( location = (distance,distance,0))

bpy.ops.mesh.primitive_cube_add( location = (distance,-distance,0))

bpy.ops.mesh.primitive_cube_add( location = (-distance,distance,0))

bpy.ops.mesh.primitive_cube_add( location = (-distance,-distance,0))

26° Relancer le script mais en stockant 15 et non pas 5 dans votre variable. Pratique non ?

...CORRECTION...

import bpy # On importe la bibliothèque Blender Python

distance = 15

bpy.ops.mesh.primitive_cube_add( location = (0,0,0))

bpy.ops.mesh.primitive_cube_add( location = (distance,distance,0))

bpy.ops.mesh.primitive_cube_add( location = (distance,-distance,0))

bpy.ops.mesh.primitive_cube_add( location = (-distance,distance,0))

bpy.ops.mesh.primitive_cube_add( location = (-distance,-distance,0))

27° Réaliser un script qui crée un cube à une distance donnée, puis à 3 fois cette distance puis à 5 fois cette distance.

...CORRECTION...

import bpy # On importe la bibliothèque Blender Python

distance = 3

bpy.ops.mesh.primitive_cube_add( location = (distance,0,0))

bpy.ops.mesh.primitive_cube_add( location = (distance*2,0,0))

bpy.ops.mesh.primitive_cube_add( location = (distance*3,0,0))

28° Dernière question : faites preuve d'imagination et réalisez une scène difficilement réalisable si on ne connait recours pas aux variables. En gros, il s'agit des scènes où un grand nombre de formes sont précisement positionnées et déformées.

A titre d'exemple, voici ce qu'on peut obtenir à l'aide du script suivant : on génère les cubes.

J'ai ensuite dû associer manuellement deux matériaux différents aux différents cubes.

Les couleurs sont le rose et le vert avec :

Dans l'activité suivante, nous verrons comment éviter de taper trop de lignes identiques à l'aide des boucles.

import bpy # On importe la bibliothèque Blender Python


decalage = 2


# Création des cubes dans le plan xy (z reste à 0)

bpy.ops.mesh.primitive_cube_add( location = (0,0,0))


bpy.ops.mesh.primitive_cube_add( location = (decalage,0,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage,decalage,0))


bpy.ops.mesh.primitive_cube_add( location = (decalage*2,0,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*2,decalage,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*2,decalage*2,0))


bpy.ops.mesh.primitive_cube_add( location = (decalage*3,0,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*3,decalage,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*3,decalage*2,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*3,decalage*3,0))


bpy.ops.mesh.primitive_cube_add( location = (decalage*4,0,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*4,decalage,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*4,decalage*2,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*4,decalage*3,0))

bpy.ops.mesh.primitive_cube_add( location = (decalage*4,decalage*4,0))


# Création des cubes dans le plan yz (x reste à 0)

bpy.ops.mesh.primitive_cube_add( location = (0,0,decalage))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage,decalage))


bpy.ops.mesh.primitive_cube_add( location = (0,0,decalage*2))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage,decalage*2))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*2,decalage*2))


bpy.ops.mesh.primitive_cube_add( location = (0,0,decalage*3))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage,decalage*3))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*2,decalage*3))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*3,decalage*3))


bpy.ops.mesh.primitive_cube_add( location = (0,0,decalage*4))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage,decalage*4))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*2,decalage*4))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*3,decalage*4))

bpy.ops.mesh.primitive_cube_add( location = (0,decalage*4,decalage*4))v

Comme vous le voyez, nous faisons souvent la même chose où presque. Heureusement, il existe un moyen d'automatiser encore plus tout cela : la boucle FOR. C'est dans l'activité suivante.

Image créée par script