Infoforall

BLENDER PYTHON - 02 - Les boucles FOR

Même si vous connaissez déjà la boucle FOR, il va falloir faire l'effort de faire cette activité pour voir les quelques spécificités de Python via Blender.

Cette activité vous permettra de réaliser ceci sans créer les cubes et les placer un par un. Ce serait un peu long...

vue de face

1 - La configuration Scripting

L'un des points 'faibles' de Blender en Python, c'est la multiplicité des sources d'informations et d'affichage. Pour rappel :

La console ou le terminal de votre ordinateur correspond en windows à l'invité de commande qu'on trouve dans le sous-menu Système Windows. On ne l'utilise pas avec Blender.

Terminal

Même si Blender fonctionne avec Python, nul besoin de passer par votre propre interpréteur Python : tout est intégré directement à Blender. Oubliez donc le IDLE Python (icone blanche) et l'icone vers la console Python (icone noire) que vous avez peut-être sur votre ordinateur.

IDLE

Dans Blender, il existe trois endroits qu'il faut savoir activer :

  1. Le TextEditor qui permet d'écrire des scripts Python et de les executer
  2. La Console Python interne à Blender qui permet d'executer du code Python en direct
  3. Console Python
  4. La Console System de Blender qui permet de voir les messages qu'affiche Blender, notamment les erreurs
  5. Console system

01° Ouvrir Blender. Changer la disposition par défaut pour utiliser plutôt la disposition Scripting.

Scripting : choix

On arrive normalement à ceci :

Configuration Scripting

Toutes les fenêtres utiles pour programmer sont là.

02° Dans TextEditor, sélectionner la numérotation des lignes et la mise en couleur synthaxique.

03° Tirer le menu Info pour qu'il prenne un peu plus de place si possible. Sélectionner ensuite Window - Toggle System Console. Attention, je parle bien de la console Systeme, pas juste la console Python qu'on peut sélectionner comme fenêtre active.

Console system

Au final, vous devriez avoir la bonne configuration de travail, à savoir une interface qui ressemble à ceci:

Configuration Scripting finale

2 - la boucle itérative POUR (FOR) par itérateur chiffré

Vous avez réussi dans l'activité précédente à générer des cubes à des endroits bien définis. Nous allons aller plus loin et automatiser cette création.

Pour l'instant, si vous voulez créer 1000 cubes, vous avez besoin de 1000 lignes. C'est beaucoup...

Nous allons voir comment faire cela en une dizaine de lignes. C'est mieux non ?

On peut utiliser un FOR pour faire une boucle revenant à réaliser les mêmes instructions X fois.

Comment fonctionne une boucle for ? Le cas le plus simple est facile à comprendre : on prend une variable, nommée i par exemple, qui commence à la valeur zéro. On l'augmente de 1 à chaque tour tant qu'elle ne dépasse pas strictement une valeur de seuil iMAX telle que i < iMAX.

Si vous n'étes pas familier avec le concept, utilisez le script ci-dessous :

Valeur initiale (initialisation) :

On continue tant que i < Valeur de test:

Je vais maintenant vous présenter l’utilisation basique de la fonction range (xmax). On notera toujours la présence du double point et de la tabulation pour montrer clairement où se situent les actions à répéter :

for x in range(5) :

    print (x)

Pour obtenir le décalage, utilisez bien la touche TABULATION qui se trouve normalement sous le symbole 2 en haut à gauche du clavier.

04° Dans TextEditor, cliquer sur New et faire un copier-coller du code ci-dessus. Lancer le script après le bouton RUN SCRIPT. Si vous ne voyez ce bouton, pensez à agrandir le TextEditor. Allez ensuite voir le résultat dans la console System. Quelles sont les différentes valeurs prises par x ? Va-t-on réellement jusqu’à 5 ou s’arrête-t-on juste avant ?

Et oui. On ne compte que jusqu'à 4, on s'arrête avant 5.

Alors, pourquoi s'arrêter à 4 ?

Nous verrons plus loin la raison exacte mais si on regarde ce qui est affiché ...

0

1

2

3

4

... on voit qu'on compte jusqu'à 4 mais qu'on a bien 5 nombres : 0 - 1 - 2 - 3 - 4.

La boucle s'exécute donc tant que x est strictement inférieur à 5.

Regardons comme utiliser ceci dans un cas plutôt simple : on veut faire bouger le point en suivant le trajet. Vous pouvez utiliser les curseurs pour définir :

for i in range(IMAX) :

    va_a_gauche()


for j in range(JMAX) :

    va_en_bas()

A droite : IMAX = 0
En bas : JMAX = 0

...CORRECTION...

Il faut régler IMAX sur 4 pour avoir 4 étapes : 0-1-2-3.

Il faut régler JMAX sur 7 pour avoir 7 étapes : 0-1-2-3-4-5-6.

Il faut donc se souvenir qu'on commence ici avec le compteur à 0 car on note var i = 0.

05° Afficher les chiffres de 0 à 20 avec une boucle.

...CORRECTION...

for x in range(20) :

    print(x)

06° Regarder le code ci-dessous et prévoir ce qu’il va afficher à l’écran. Vérifier en lançant le code.

print("Debut"

print("Nous ne sommes pas encore dans la boucle"

for i in range(3) :

    print("Cas ",i)

    print (i," x2 =",i*2,"\n")

print("On continue mais plus dans la boucle"

CLIQUEZ SUR UN BOUTON-REPONSE :

i :

Voilà ce que devrait afficher l'ordinateur :

Debut

Nous ne sommes pas encore dans la boucle

Cas 0

0 x2 = 0


Cas 1

1 x2 = 2


Cas 2

2 x2 = 4


On continue mais plus dans la boucle

Il exécute donc la boucle avec i=0, puis i=1 et finalement i=2. En gros, tant que i est strictement inférieur à 3.

07° Réaliser un programme ne comprenant qu’une seule boucle FOR qui affiche (pour chaque valeur de x variant de 0 à 6) le carré de x et la puissance trois de x.

Remarque : En Python, la puissance se note ** : Ainsi 6 puissance 2 se note 6**2.

Si on veut que le compteur ne commence pas à 0, il suffit de la préciser dans la fonction : range(2,6) va donc prendre les valeurs 2, 3, 4 et 5.

08° Réaliser un programme qui affiche un à un les nombres compris entre 32 et 127.

Les images ne sont que des successions de nombres stockés dans le fichier image. On code chaque pixel "coloré" à l'aide de trois intensités allant de 0 à 255. Une pour le rouge, une pour le vert et une pour le bleu.

C'est la même chose pour les caractères : l'ordinateur ne stocke pas un caractère mais un nombre : chr(x) permet de connaître le caractère associé au nombre entier x.

09° Réaliser un programme qui affiche un à un les caractères associés aux nombres compris entre 32 et 127 sous la forme :

        Le caractère XXX correspond au code X

Il faudra utiliser une boucle FOR et la fonction chr.

...CORRECTION...

for x in range(32,128) :

    print("Le caractère ",chr(x)," correspond au code ",x)

Il est possible (mais pas obligatoire) que votre console affiche très mal les accents ! Encore une fois, tout cela est dû au codage du texte en forme de nombre. Python demande d'afficher un é mais il transmet juste des nombres à la console système. Visiblement, les nombres que Python envoie ne sont pas tous décodés correctement. Nous verrons un peu cela lorsque nous parlerons de l'encodage des caractères.

Moralité : lorsque vous envoyez des choses vers la console, évitez les caractères accentués.

Le caractère 127 est-il imprimable ? Allez donc vous renseigner sur Internet le caractère 127 du code ASCII.

10° Essayer les caractères de 0 à 31. A-t-on des caractères imprimables ? Que se passe-t-il pour le 10 ?

...CORRECTION de A à Z...

Le code 10 correspond au saut à la ligne. Lorsqu'on l'affiche, on part donc à la ligne !

    print(chr(x))

On peut encore rajouter un paramètre à range : range (5,10,2) va compter de 2 en 2 à partir de 5 et jusqu’10 non inclus : 5, 7 et 9 donc.

Si le pas est négatif, on compte en sens inverse : range (9,1,-1) donne : 9 8 7 6 5 4 3 2, mais pas 1 puisque la condition n'est alors plus vérifiée.

11° Créer un programme qui affiche automatiquement une lettre sur 2 de A (code 65) à Z (code 90) puis qui affiche les lettres de Z à A. Utiliser les boucles FOR associées au code ASCII.

...CORRECTION de A à Z...

for x in range(65,91,2) :

    print(chr(x))

...CORRECTION de Z à A...

for x in range(90,64,-2) :

    print(chr(x))

Il existe également une possibilité pour lire une chaîne de caractères string caractère par caractère en utilisant un FOR numérique : une chaîne de caractères n’est rien d’autre qu’une sorte de tableau ordonné de caractères.

Le string monTexte = "Bonjour, je suis ici." peut se voir comme le tableau suivant :

Case 00 : contient : B
Case 01 : contient : o
Case 02 : contient : n
Case 03 : contient : j
Case 04 : contient : o
Case 05 : contient : u
Case 06 : contient : r
Case 07 : contient : ,
Case 08 : contient :  
Case 09 : contient : j
Case 10 : contient : e
Case 11 : contient :  
Case 12 : contient : s
Case 13 : contient : u
Case 14 : contient : i
Case 15 : contient : s
Case 16 : contient :  
Case 17 : contient : i
Case 18 : contient : c
Case 19 : contient : i
Case 20 : contient : .

Attention: comme d’habitude en informatique, le premier élément est l’élément 0.

On peut accéder aux différents caractères stockées dans la chaîne de caractéres à l'aide d'une boucle FOR NUMERIQUE. On dit que le String est un objet :

  • itérable car il contient une succéssion d'éléments (des caractères)
  • séquentiel car on peut y accéder en suivant un certain ordre.

Si on veut connaître la taille d’un string monTexte (son nombre de case), on peut utiliser la fonction len pour length (longueur en anglais) : len(monTexte) renvoie un integer qui vaut … 21. Le tableau va jusqu’à 20 mais la première case est la case 0. D’où 20+1=21. On notera que l’espace est bien stocké dans une case : on stocke bien l’information « laisser un espace » dans la chaîne de caractères.

Nous pouvons accéder à l’élément n°X d’une chaîne de caractères monTexte en utilisant la syntaxe suivante : monTexte[X] où X est un integer, monTexte est une chaîne de caractères définie préalablement. On notera l’utilisation des crochets [ ].

A titre d'exemple, voilà un programme qui permet de définir une chaîne de caractères monTexte, de stocker dans nLongueur le nombre de caractères de la chaîne et qui demande quel numéro de caractère nCase afficher. On affiche alors le caractère numéro nCase.

Votre chaîne de caractères:

Position désirée :

La chaîne possède - caractères.

Le caractère voulu est

En Python :

monTexte = "Bonjour, je suis ici."

nLongueur = len(monTexte)

# n devant nLongueur pour indiquer que c'est un nombre, int pour transformer l'entrée clavier en nombre integer justement


print(monTexte)

print("Nombre de caractères au total : ", nLongueur)


sCase = input("Donner le numéro du caractère voulu :")

# s devant sCase pour indiquer que c'est un string

nCase = int(sCase)

# n devant nCase pour indiquer que c'est un nombre, int pour transformer l'entrée clavier en nombre integer justement

print(monTexte[nCase])


Deux nouveautés :

12° La couleur du texte est-elle la même derrière le dièse # ? S'agit-il d'un code à exécuter ou d'un simple commentaire qu'on rajoute pour donner des explications à un humain qui serait en train de lire votre code ?

...CORRECTION de Z à A...

Il s'agit de commentaires, des textes qui seront totalement ignorés par l'interpréteur Python. Ils sont uniquement destinés à donner des explications sur le code.

Il va falloir en placer un maximum de façon à vous permettre de retrouver le fonctionnement de votre script même 6 mois plus tard.

Lors de mes tests, Python affichait les commentaires en verts. Sur le site, ils sont en bleu-gris pale.

13° Lancez le code et allez voir la console Système. Que fait la ligne suivante à votre avis ? Lisez le code, la console et relancez le si nécessaire.

sCase = input("Donner le numéro du caractère voulu :")

...CORRECTION ...

La fonction input permet de poser une question à l'utilisateur.

  1. On affiche le string donné entre les parenthèses.
  2. On attend la réponse de l'utilisateur sur la console.
  3. On affecte la réponse à la variable nCase.

Attention, grosse subtilité de l'utilisation du input : quelque soit votre réponse, le système va vous renvoyer un string, une chaîne de caractère. Ainsi, même si vous répondez 58, le système va vous renvoyer le string "58" et pas le nombre 58.

14° Dans quelle partie du code a-t-on réussi à transformer le string de réponse en nombre ?

...CORRECTION ...

nCase = int(sCase)

J'espère que les commentaires vous ont aidé à comprendre ces quelques lignes.

Nous n'allons néanmoins pas trop souvent utiliser la console, ni pour écrire, ni pour obtenir des réponses. On peut en effet faire cela directement depuis l'interface Blender.

D'ailleurs, maintenant que vous savez utiliser les boucles FOR, les print et les input, nous allons voir ce qu'on peut en faire dans Blender.

3 - Utilisation du FOR dans Blender

Bon, et ça sert à quoi tout ceci dans Blender ?

Et bien, cela va permettre de dessiner des objets géométriques ou placés de façon très précise mathématiquement.

Si vous aviez 3 cubes à placer, vous pourriez à la limite le faire à la main, mais s'ils étaient 300 ?

Gérer les translations

15° Tenter de voir ce que fait le code suivant puis lancer le dans Blender.

import bpy # On importe la bibliothèque Blender Python

for x in range(-16,17,4):

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

CLIQUEZ SUR UN BOUTON-REPONSE :

x :

...CORRECTION...

On part de -16 et on augmente de 4 à chaque retour de boucle.

Ceci est vrai tant que le compteur donne un résultat strictement inférieur à 17.

Il devrait vous créer des cubes en x = -16, x = -12, x = -8, x = -4, x = 0, x = 4, x = 8, x = 12 et x = 16.

Pour supprimer les objets créés, vous pouvez utiliser la touche C pour activer le curseur de sélection. Appuyer sur le bouton de gauche le temps de sélectionner les objets voulus, cliquer sur le bouton de droite puis supprimer la sélection avec la touche SUPPR.

Text editor

Gérer les rotations

On peut aussi gérer les rotations. Il faut alors faire un peu de math, surtout de la trigonométrie : si les maths et vous, c'est une histoire compliquée, gardez cette méthode, il vous permettra de gérer les rotations ensuite sans trop de difficulté.

Imaginons qu'on désire créer un cercle de cube. Il faut falloir importer le module math pour parvenir à calculer les sinus et les cosinus. Et convertir les angles qu'on exprime en degrés en radians, unité naturelle des angles pour Python.

Voici le code qui permet d'obtenir les coordonnées d'un cube qui subit une rotation autour de (0,0) avec un rayon fourni dans la variable rayon :

import bpy # On importe la bibliothèque Blender Python

import math # On importe la bibliothèque math pour calculer les cos...


rayon = 10


for angle_degre in range(-0,360,36):

    angle = math.radians(angle_degre) # math.radians permet de convertir en radians

    x = rayon*math.cos(angle)

    y = rayon*math.sin(angle)

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

Nous allons donc plusieurs calculs en boucle avec les valeurs angle_degre de 0°, 36°, 72° ... puisqu'on part de 0 et qu'on augmente de 36° à chaque retour.

16° Lancer le code pour voir le résultat. Tentons d'en comprendre le sens :

pyramide de cube

17° Je vous laisse tenter de faire ceci (vous ne pouvez pas faire la colorisation via un script pour l'instant) :

vue de face Text editor

Une proposition de correction : un for dans un for et un nombre de cubes et une altitude variable en fonction du rayon;

import bpy # On importe la bibliothèque Blender Python

import math # On importe la bibliothèque math pour calculer les cos...


rayon = 10


for rayon in range (6,23,4):

    for angle_degre in range(0,360,int(36*6/rayon)):

        angle = math.radians(angle_degre) # math.radians permet de convertir en radians

        x = rayon*math.cos(angle)

        y = rayon*math.sin(angle)

        altitude = -rayon//2

        bpy.ops.mesh.primitive_cube_add( location=(x,y,altitude) )

Les lumières, le plan et son effet miroir ont été rajoutés après l'utilisation du script pour permettre de mieux voir la structure obtenue.

Faire cette structure à la main aurait demandé des heures de travail (et un positionnement final approximatif, à moins de refaire les calculs un à un).

Dans la prochaine partie, nous verrons d'autres structures logiques et la façon de coder la taille ou la couleur des objets.

18° A quoi sert le int de int(36*6/rayon) ?

...CORRECTION...

On veut obtenir un nombre entier (integer) et pas un nombre à virgule (float). On utilise donc la fonction native int qui permet justement de transformer un résultat en entier, si cela est possible.

19° Quelles seront les valeurs prises par rayon et angle ?

...CORRECTION...

rayon in range (6,23,4) : on part de 6 et on rajoute 4 tant que rayon est inférieur à 23 : 6 - 10 - 14 - 18 - 22.


angle_degre in range(0,360,int(36*6/rayon)) : on part de 0 et on rajoute la partie entière de (36*6/rayon) à chaque tour. On continue tant que angle_degre est inférieure à 360.

20° le code contenant deux signes division, -rayon//2, est-il une erreur ou une notation engendrant une action particulière ?

...CORRECTION...

L'utilisation de //, plutôt qu'un simple /, va renvoyer uniquement la partie entière de la division (7//2 renvoie donc 3 car 7 = 3*2+1.

4 - FAQ

Question : comment sortir d'une boucle for avant la fin ?

On utilise l'instruction break. Exemple : on lance une boucle avec un compteur évoluant de 0 à 20 mais on sort définitivement de la boucle lorsque le compteur vaut 5 :

for compteur in range(21) :

    print(compteur)

    if (compteur == 5) :

        break

input("pause")

CLIQUEZ SUR UN BOUTON-REPONSE :

compteur :

Sur la console, on voit bien qu'on ne revient pas dans la boucle pour le cas 6 et plus :

0

1

2

3

4

5

Remarque : même s'il reste des instructions sous le break, on ne les exécute pas : on quitte immédiatement la boucle.

Question : Je voudrais compter de 0 à 6 mais sans passer par 5, c'est possible ?

On utilise l'instruction continue. On lance une boucle avec un compteur évoluant de 0 à 6 mais sans agir pour 5 en forçant un retour au début de la boucle :

for compteur in range(7) :

    if (compteur == 5) :

        continue

    print(compteur)

input("pause")

CLIQUEZ SUR UN BOUTON-REPONSE :

compteur :

Comme vous le voyez, je n'ai même pas besoin de mettre un else après le if. L'exécution du programme va répartir au début de la boucle dès qu'elle rencontrera continue.

Sur la console, on voit bien qu'on a sauté l'exécution du print pour le 5 :

0

1

2

3

4

6

Remarque : même s'il reste des instructions sous le continue, on ne les exécute pas : on remonte immédiatement la boucle pour faire l'itération suivante.