40 - Les API dont Blender
Après avoir vu les modules et vu qu'on pouvait y placer des fonctions utilisables de l'extérieur, les fonctions d'interface, nous allons voir aujourd'hui un dernier type d'interface.
Si on résume, nous avons vu sur deux ans :
- Les interfaces graphiques (turtle, tkinter, Qt...) ou textuelles (console) : des programmes qui permettent de faire communiquer un utilisateur humain et un programme
- L'interface des structures de donnnées : un ensemble de fonctions qui permet de manipuler des données sans avoir à réfléchir à la façon dont elles sont implémentées concrétement et qui permettent donc à un programme de manipuler des données sans connaître leurs implémentation.
- L'interface de la programmation orientée objet, composée des méthodes accessibles par un utilisateur de l'objet (les accesseurs pour lire et les mutateurs pour modifier). Elle permet donc de faire communiquer le programme avec des données et fonctions encapsulées dans l'objet. C'est donc la même chose qu'au dessus.
- L'interface d'un module composée des fonctions d'interface, utilisables par un utilisateur extérieur au module. Dans le cas de Python, elles permettent donc de faire communiquer un programme en Python avec un autre programme en Python.
Type d'interfaçage : HUMAIN - PROGRAMME
Type d'interfaçage : PROGRAMME - DONNEES
Type d'interfaçage : PROGRAMME - DONNEES
Type d'interfaçage : PROGRAMME PYTHON - PROGRAMME PYTHON
Nous allons voir aujourd'hui qu'il existe une possibilité d'interfacage entre programme encore plus grande.
Type d'interfaçage : APPLICATION (ensemble de programmes) - APPLICATION
Prérequis : les cours parlant des notions précédentes et pour parvenir à utiliser Blender Python :
- Notions sur les objets (attributs, méthodes)
- Notions sur les modules
- Les dictionnaires Python
Logiciel nécessaire pour l'activité : Blender 2.9 ou plus
Evaluation ✎ :
1 - Qu'est-ce qu'une API
API est un acronyme pour interface de programmation d’application. En Anglais, cela veut dire Application Programming Interface.
Il s'agit donc d'un programme (autonome ou pas) qui permet l'utilisation de ces fonctionnalités à travers l'utilisation d'un autre programme.
Parmi les API les plus connues du moment :
- Azure API de Microsoft : une large offre d'applications disponibles notamment via des interfaces Web. Beaucoup d'entreprises fonctionnent maintenant avec ce type de ressources applicatives disponibles dans le "Cloud". Elles utilisent ainsi les serveurs de Microsoft pour stocker leurs données mais également pour faire tourner leurs logiciels...
- Graph API de Facebook : cette interface permet d'exporter (un peu) des données de Facebook et surtout d'en importer automatiquement à travers une librairie Python.
- Google Maps API de Google : permet de facilement réaliser des sites Web ou des applications sur smartphones utilisant ce service de cartographie. On peut interagir facilement avec ce service à l'aide de Javascript.
- Les API de gestion de Salesforce : peu connue du grand public, cette société californienne est l'un des précurseurs des solutions en Cloud Computing, c'est à dire en louant des machines faisant tourner un service et non pas utiliser les propres machines de l'entreprise.
- et bien d'autres services...
Interfaçage entre une APPLICATION CLIENT et une APPLICATION qui "offre" le service
Le verbe "offre" est entre guillemets car beaucoup d'API sont payantes. Il s'agit d'un service. Par exemple, beaucoup de sociétés utilisent des API de Google Map ou ViaMichelin pour obtenir automatiquement des itinéaires et pouvoir facturer les choses en chose de la distance. Sinon, il faudrait payer un humain pour le faire.
Lorsqu'un logiciel offre une API permettant de l'utiliser depuis l'extérieur, on dit que le logiciel expose une API.
D'ailleurs, on peut presque voir un système d'exploitation comme une sorte particulière d'API puisque les applications communiquent avec le système matériel à travers les fonctions d'interface de l'OS !
L'interface peut être
- une interaction Web permettant de recevoir des requêtes HTTP et de renvoyer des réponses HTTP ou
- une interaction logicielle offerte par un module Python par exemple.
2 - API Blender
Blender 3D est un logiciel libre (le code source est accessible à tous) et gratuit, réalisé par une communauté de d'informaticiens passionnés.
Il permet de réaliser des scènes 3D pour ensuite réaliser des images 3D, des animations 3D ou même des jeux interactifs 3D.
Il s'agit d'un logiciel possédant des boutons, des menus et on peut créer des scènes sans toucher la moindre ligne de code. Comme un traitement de texte, un tableur ou un logiciel permettant de créer des présentations.
01° Aller sur la courte activité proposée ci-dessous si vous ne connaissez pas Blender 3D (en version 2.80+) puis revenir ici une fois que vous avez pris l'interface graphique en main. Ne faites pas la dernière question qui vous demande de réaliser une petite scène 3D.
En quoi est-ce une API ?
Le logiciel Blender 3D intègre des fonctions d'interface permettant à Python d'interagir avec lui : on peut donc profiter des fonctionnalités du logiciel, sans passer par l'interface utilisateur mais uniquement en le contrôlant avec un script Python.
Qu'allons nous faire aujourd'hui :
- Créer des objets avec le script
- Les déplacer, les modifier avec un script
- Modifier le placement de la caméra et l'intensité des lumières avec un script
- Enregistrer l'image... avec un scipt
Vous allez ainsi voir qu'on pourra créer une image 3D avec Blender 3D en passant par un simple programme python et sans utiliser réellement l'interface graphique de Blender.
3 - Module Blender Python
02° Ouvrir Blender 3D pour obtenir la scène de base : un unique cube au milieu de la scène. Cliquer sur scripting.
Vous obtenez alors un écran correspondant à la vue adaptée au mode script Python de Blender :
Vous devriez visualiser un message d'accueil de ce style dans la console Python de Blender :
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). Du coup, il n'est pas utile de taper import bpy
dans cette console. Nous le ferons néanmoins pour prendre l'habitude de l'importer.
bpy
Que veut dire bpy ? Tout simplement Blender PYthon.
Il s'agit d'un module Python permettant d'interagir avec l'API de Blender en utilisant un code Python.
03° Faire disparaitre le cube de départ (click gauche puis touche Supprimer) PUIS taper ceci dans la console :
>>> import bpy
>>> bpy.ops.mesh.primitive_cube_add()
Vous devriez constater qu'un nouveau cube vient d'apparaitre juste sur le curseur 3D.
04° Placer le curseur de la souris dans la vue 3D et appuyer sur la touche T
du clavier pour faire apparaître les outils (Tools).
Utiliser l'outil Déplacer (le bouton avec les 4 flèches) pour déplacer le cube nouvellement créé.
05° Utiliser l'outil Curseur 3D (le bouton avec le cercle) pour déplacer le curseur ailleurs qu'au milieu de l'écran.
Taper ensuite ceci dans la console Blender Python :
>>> import bpy
>>> bpy.ops.mesh.primitive_cube_add(size=1.0)
Comment obtenir de la documentation sur les fonctions d'interface disponibles via la bibliothèque bpy ?
Le plus simple est encore d'aller voir en ligne : Vers la documentation de API Blender Python
On trouve ceci :
Documentation sur primitive_cube_add
bpy.ops.mesh.primitive_cube_add(size=2.0, calc_uvs=True, enter_editmode=False, align='WORLD', location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0))
Construct a cube mesh
Parameters
size (float in [0, inf], (optional)) – Size
calc_uvs (boolean, (optional)) – Generate UVs, Generate a default UV map
enter_editmode (boolean, (optional)) – Enter Editmode, Enter editmode when adding this object
align (enum in ['WORLD', 'VIEW', 'CURSOR'], (optional)) –
Align, The alignment of the new object
WORLD World, Align the new object to the world.
VIEW View, Align the new object to the view.
CURSOR 3D Cursor, Use the 3D cursor orientation for the new 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
On voit bien que size est un paramètre optionnel : sa valeur par défaut est de 2.0. C'est pour celà que le premier cube était plus gros.
06° Avec cette documentation, créer un nouveau cube de taille 4.0 situé aux coordonnées x = 4.0, y = 2.0 et z = -1.0.
...CORRECTION...
>>> bpy.ops.mesh.primitive_cube_add(size=4.0, location=[4.0, 2.0, -1.0])
{'FINISHED'}
07° La fonction renvoie-t-elle visiblement la réference-mémoire permettant d'agir sur notre nouvel objet ?
...CORRECTION...
>>> bpy.ops.mesh.primitive_cube_add(size=4.0, location=[4.0, 2.0, -1.0])
{'FINISHED'}
On voit bien que la fonction ne renvoie pas un dictionnaire : la clé n'est pas associée à une valeur.
Il s'agit d'un type nommé set, comme ensemble. C'est une sorte de list mais où on ne peut pas placer deux fois le même élément.
>>> {5,5}
{5}
Je ne parlerai plus de set ensuite : pas au programme de NSI. On se débrouille très bien avec les types que vous connaissez déjà.
Comment faire alors pour mémoriser la référence d'un objet qu'on vient de créer et parvenir à le modifier ensuite ?
Créer, mémoriser et modifier un objet 3D avec Blender
On peut récupérer la référence de l'objet actuellement sélectionné à l'écran en utilisant ceci :
>>> objet3D = bpy.context.object
>>> type(objet3D)
<class 'bpy_types.Object'>
>>> objet3D
bpy.data.objects['Cube.002']
On constate qu'on parvient bien à récupérer la référence d'un objet dont la classe est visiblement Object (c'est certainement une vraie instance d'une classe POO puisqu'il y a une majuscule).
Vous allez donc pouvoir placer cette référence dans une variable ou le stocker comme élément d'un type construit (liste-tableau, liste chainée, dictionnaire, tuple...).
Et une fois qu'on a la référence-mémoire, nous pouvons agir sur l'objet !
Déplacer un objet
Il suffit pour cela d'agir sur l'"attribut" location et de lui fournir un nouveau tableau.
>>> bpy.ops.mesh.primitive_cube_add()
{'FINISHED'}
>>> objet3D = bpy.context.object
>>> objet3D.location = [0.0, 4.0, 0.0]
Avec ce code, on parvient à placer l'objet en x=0, y=4 et z=0.
Modifier la taille d'un objet
Le paramètre size est uniquement le nom du paramètre optionnel qu'on peut fournir au Constructeur.
Pour modifier la taille en x, y ou z, il faut agir sur l'"attribut" dimensions et de lui fournir un nouveau tableau.
>>> objet3D.dimensions = [0.5, 2.0, 8.0]
Avec ce code, on parvient à créer une sorte de poutre.
Modifier l'inclinaison d'un objet
C'est plus délicat : on peut faire tourner l'objet selon les trois axes !
On peut créer une rotation autour de l'axe X ou autour de l'axe Y ou autour de l'axe Z.
Ou autour des trois puisqu'on doit fournir un tableau contenant l'angle de rotation sur l'axe X, l'angle de rotation sur l'axe Y et l'angle de rotation sur l'axe Z.
Le paramètre size est uniquement le nom du paramètre optionnel qu'on peut fournir au Constructeur.
Pour modifier la taille en x, y ou z, il faut agir sur l'"attribut" rotation_euler et de lui fournir un nouveau tableau des angles. Problème : on doit fournir les angles en radians et pas en degrés.
Imaginons qu'on veuille créer une rotation de 90° sur l'axe X, avec ce code cela ne fonctionne pas car on donne 90 en croyant qu'on attend des degrés :
>>> objet3D.rotation_euler = [90, 0, 0]
On voit clairement que l'angle n'est pas bon.
Il faut donc convertir les angles en degrés en radians. Pour cela, il faut bien entendu soit connaître la conversion, soit utiliser les outils du module math.
Comme nous ne sommes pas là pour avoir les résultats précis, nous allons faire simple : l'angle en radians vaut l'angle en degrés divisé par 180 et multiplié par PI (on prendra 3.14 et ça ira bien).
>>> angleX = 90/180*3.14
>>> objet3D.rotation_euler = [angleX, 0, 0]
Ou pour une rotation à 45° :
>>> angleX = 45 / 180 *3.14
>>> objet3D.rotation_euler = [angleX, 0, 0]
08° Utiliser la documentation ci-dessus pour manipuler correctement un "Cube" qu'il faudra déplacer, déformer et faire tourner.
09° Lire la documentation de Blender API et dessiner des sphères, des cones....
En ligne : Vers la documentation de API Blender Python
4 - Programme
Lorsqu'on veut réalise un programme et pas taper les instructions en direct via la console, on peut soit créer un script externe (mais il faut configurer correctement la machine pour que Python trouve Blender, ça peut être pénible) ou alors directement travailler dans l'éditeur de code de Blender 3D.
10° Dans la zone de droite, créer un nouveau script avec le bouton NOUVEAU au haut et au milieu de la vue EDITEUR DE CODE.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 |
|
On obtient ici un tableau qui contient tous les "Cubes" qui ont été ajoutés. Vous pourriez donc encore agir dessus.
11° Lancer le script en utilisant la flèche.
Je vous laisse vous amuser. Il reste bien entendu beaucoup de choses à voir :
- Comment gérer les lumières et les caméras
- Comment gérer les couleurs des objets
- Comment enregistrer une image 3D
- Comment créer une animation
Tout ceci est possible avec un simple script Python. Mais en 1h, vous avez déjà vu pas mal de choses.
Une image scriptée parmi tant d'autres :
Une vidéo scriptée parmi tant d'autres :
5 - Les autres actions
A faire : il faut que je mette à jour mes tutos Blender Python : entre la versino 2.79 et 2.80 beaucoup de choses ont été modifié malheureusement.
En attendant : vers d'autres connaissances
6 - FAQ
Blender API ne permet pas d'accéder directement aux objets et autres éléments ?
Si, mais l'API stocke les éléments dans une structure de données que vous n'avez pas encore vu : la collection. C'est une sorte de dictionnaire où on peut accéder aux éléments à l'aide d'une clé ET aussi à l'aide d'un numéro d'index. C'est donc une sorte de mélange de listes et de dictionnaires.
>>> objet3D = bpy.context.object
>>> type(objet3D)
<class 'bpy_types.Object'>
>>> objet3D
bpy.data.objects['Cube.002']
On constate qu'on parvient bien à récupérer la référence d'un objet dont la classe est visiblement Object (c'est certainement une vraie instance d'une classe POO puisqu'il y a une majuscule).
Si on demande à visualiser le contenu de cette variable, on voit que l'API renvoie une information claire (une fois qu'on sait la lire) : la référence de l'objet est stockée dans une collection nommée objects et on peut y accéder à l'aide de la clé 'Cube.002'.
Tout comme set, les Collections ne sont pas au programme. Il s'agit d'une sorte de mélange entre dictionnaire et tableau. On peut accéder aux éléments à l'aide d'une clé mais on peut aussi itérer sur leurs positions indexées.
>>> for objet in bpy.data.objects : objet
...
bpy.data.objects['Camera']
bpy.data.objects['Cube']
bpy.data.objects['Cube.001']
bpy.data.objects['Cube.002']
bpy.data.objects['Light']
On peut accéder à la référence-mémoire de la caméra de deux façons :
>>> bpy.data.objects[0]
bpy.data.objects['Camera']
>>> bpy.data.objects['Camera']
bpy.data.objects['Camera']