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 :

Comme vous pouvez le constater en utilisant la simulation, l'interpréteur va suivre les instructions de façon séquentielle : il les lit et les execute les unes à la suite des autres, dans l'ordre qu'on lui a fourni. Il n'exécute pas les instructions dans un ordre aléatoire.

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 :

>>> 14/3

>>> 9*9+2

>>> 12-2*0.8888

>>> 3E8*12E-15

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 opérateurs différents :

Opérateur 1/4 :

>>> 14/3

4.666666667

Comme sur les calculatrices, c'est approximatif mais cela devrait permettre une résolution correcte des problèmes.

L'utilisation de  /  représente donc bien l'opérateur division.

On retrouve les autres signes standards pour les opérateurs :  +   -  et  * .

Opérateur 2/4 :

>>> 14//3

4

L'utilisation de  //  permet donc d'obtenir la partie entière de la division de 14 par 3 qui vaut 4,6666666667.

Opérateur 3/4 :

>>> 14%3

2

L'utilisation de  %  permet donc d'obtenir le reste de la divison entière : 14 = 4x3 + 2. On parle également de modulo, comme pour les angles qui sont connus modulo 360° ou 2Π rad.

Opérateur 4/4 :

>>> 3**2

9

L'utilisation de  **  permet donc de calculer la puissance.

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

12° A votre avis, que fait cette instruction ?

>>> print("Hello World !")

13° Et là ?

>>> print( "Hello W" + "orld !" )

...CORRECTION...

Dans les deux cas, on voit s'afficher Hello World ! dans la console.


Python sait donc additionner deux strings. On nomme cela la concaténation.

Ce qui apparaît en bleu se nomme un STRING en python : une chaîne de caractères en français.

Un string commence avec des guillements doubles et finit par des guillemet doubles :

"Hello World !"

Mais on peut également utiliser des guillemets simples :

'Hello World !'

Par contre, on doit fermer un string avec le même type de guillemets en ouverture et en fermeture. Le code suivant ne permet pas de créer un string :

'Hello World !"

Si on utilise un guillemet double en ouverture, on ne peut donc plus l'afficher : Python va croire qu'on ferme le string ! En réalité, on peut afficher un " et c’est simple : on utilise l’antislash  \  avant le signe lui même.

14° A votre avis, que fait ce code ?

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

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).

Dernière chose : 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.

15° Qu’affiche le code ci-dessous ?

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

>>> print("ARG\tBob\t17")

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

...CORRECTION...

Vous devriez voir que \t permet de créer une tabulation.

Vous devriez voir que \\ permet d'afficher l'anti-slash.

Pour afficher un nombre (120 par exemple), vous pouvez utiliser deux façons de faire :

>>> print ("120")

120

>>> print (120)

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ées à 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 comme 12
Nombre réelfloatUn nombre à virgule 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))

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

Il nous reste une petite chose à voir pour comprendre certains codes : certains bouts de code apparaissent dans une couleur différente lorsqu'on écrit un dièse  # . Pourquoi ?

Commentaires via le dièse #

Simplement car le dièse vous permet d'insérer des commentaires : les commentaires sont des textes que l'interpréteur ne va même pas lire. Il sont destinés à fournir des indications sur le fonctionnement du code.

Tout le texte situé derrière le dièse sera totalement invisible pour l'interpréteur.

Les commentaires sont un élément fondamental d'un script : ils vous permettent de recomprendre le code que vous aviez créé il y a plusieurs mois. Dès qu'un script est compliqué, une absence de commentaires va impliquer qu'une modification ou une mise à jour va être très très compliquée...

Pour vos projets, pensez bien à donner des indications à l'aide de cet outil de conception.

Un exemple pour montrer que le commentaire n'est pas analysé :

decalage = 2


# decalage = 100


print(decalage)

Ce code va afficher 2 dans la console. Pas 100.