13. GRAPHISMES EN 3D: VPYTHON (MODULE visual)

VPython est l’extension de Python par le module visual qui permet l’affichage d’objets en 3D.

VPython est distribué sur http://vpython.org/ en versions Linux / Mac OS X / Windows pour Python 2.X et Python 3.X.

La documentation est disponible en ligne sur http://vpython.org/, mais elle se trouve aussi dans les dossiers d’installation de VPython, avec de nombreux exemples de programmes. (Sous linux faire par exemple locate vpython pour trouver les dossiers où est installé vpython. Souvent la documentation et les exemples résident dans /usr/share/doc/vpython-doc-....)

Warning

Cette extension est distribuée sous le nom de VPython mais le module à importer s’appelle visual. Dans la pratique, on parle indifféremment de module visual ou module VPython.

13.1. S’il te plaît dessine-moi une boîte

Premier pas ... un simple parallélépipède rectangle (en très gros plan):

import visual
# dessiner une boîte:
visual.box()

Souvent au lieu de faire import visual on fera: from visual import * ce qui évitera ensuite dans le programme de devoir préfixer les noms des fonctions du module par visual. On pourra alors écrire directement:

from visual import *
box()
sphere(pos=(10,10,3))

pour obtenir un boîte et une sphère. La boîte est en fait ici un cube centré à l’origine du repère et la sphère est centrée en (10,10,3), ces trois composantes étant respectivement la position horizontale, la position verticale, et la position selon la profondeur.

La librairie travaille en 3D. Toutefois, il est possible d’indiquer seulement 2 coordonnées pour un objet, dans ce cas la profondeur prend pour valeur 0.

La plupart des objets ont une propriété pos et une propriété color (i.e., position et couleur). D’autres propriétés sont utilisées selon le type d’objets, par exemple une boîte a aussi des propriétés donnant sa longueur, sa hauteur et sa largeur (selon l’axe profondeur):

box(pos=(0,-5,0), length=40, height=1, width=30, color=color.blue)

Les propriétés de taille et de position sont stockées en nombres flottants.

Warning

La fenêtre de visualisation s’adapte (en général) automatiquement pour que l’on puisse voir tous les objets de la scène. Il existe une option permettant de modifier ce comportement.

La fenêtre de visualisation fournit la possibilité de tourner et de zoomer dans la scène à l’aide de la souris, pendant l’exécution du programme:

  • pour faire tourner la scène: “drag” avec bouton droit
  • pour zoomer: “drag” avec bouton central

Selon les raccourcis déjà associés à la souris, il peut aussi être nécessaire d’utiliser les touches “CTRL” ou “ALT” conjointement aux boutons de la souris.

Note

Les print, les input et les raw_input sont réalisés dans la fenêtre où l’interpréteur Python s’exécute et non dans la fenêtre graphique de visualisation VPython.

Lorsque les paramètres ne sont pas donnés, ils ont des valeurs par défaut. Pour les paramètres principaux ces valeurs sont:

  • couleur: blanche
  • position: (0,0,0)
  • rayon: 1
  • length=1, height=1, width=1

13.2. Changer les propriétés des objets

Les objets créés peuvent être stockés dans des variables, pour pouvoir être ensuite modifiés de façon dynamique pendant l’exécution. Voici trois objets stockés dans les variables a, b et sol:

a = box(pos=(0,1,0))

b = sphere(pos=(10,10,3))

sol = box(pos=(0,0,0), length=40, height=1, width=30, color=color.green)

Pour modifier la position d’un objet:

b.x=2
b.y=1
b.z=20

ou encore:

b.pos=(2,1,20)

Il est aussi possible de modifier dynamiquement les autres propriétés (radius, color, length ...):

b.color = color.red
b.radius = 4

Par défaut, après sa création un objet est visible, mais il est possible de le cacher:

b.visible = False

et de le montrer de nouveau:

b.visible = True

Les propriétés peuvent être consultées avec la même notation. Par exemple, on pourra utiliser le rayon de la sphère b pour créer une sphère de rayon deux fois plus grand:

c = sphere(radius = b.radius*2)

ou encore incrémenter l’abscisse du centre de la sphère pour la translater selon l’axe des x:

b.x = b.x + 4

Warning

Lors d’une affectations, en fait ce n’est pas l’objet graphique lui-même qui est stocké dans la variable, mais son identifiant (comme pour les listes). Ainsi b = sphere(pos=(10,10,3), radius=5) crée un objet dont l’identifiant est stocké dans b. Si l’on exécute:

b = sphere(pos=(10,10,3), radius=5)
e = b
e.radius = 10

dans ce cas l’identifiant d’objet contenu dans b est recopié dans e, il n’y a pas création d’une seconde sphère, nous avons une seule et unique sphère. L’instruction e.radius = 10 modifie le rayon de la sphère dont l’identifiant est dans e, cette instruction a donc le même effet que b.radius = 10

Note

La bibliothèque VPython fournit un objet curve, qui permet de tracer des graphes de fonctions en 2D/3D, sous forme explicite et sous forme paramétrique.

Note

Pour essayer les composants graphiques, il est tout à fait possible de faire des tests depuis l’interpréteur interactif Python après avoir importé le module visual.

13.3. Animations

Pour faire des animations, il suffit de modifier les propriétés des objets par programme dans une boucle. Voici un exemple d’animation:

from visual import *
from math import *
from random import *

terre = sphere(pos=(0,0,0), radius=14, color=color.blue)
lune = sphere()
vaisseau = sphere(pos=(0,30,0), radius=0.5, color=color.red)

angle = 0.0
distance = 40.0
while True:
  lune.x = distance * cos(angle)
  lune.y = distance * sin(angle)
  vaisseau.x = vaisseau.x + random() - 0.5
  vaisseau.y = vaisseau.y + random() - 0.5
  angle = angle + pi/1000
  rate(100)

Note

La fonction rate du module VPython permet de garantir un temps d’attente minimal (rate(n) impose une attente d’au moins 1/n seconde). Elle est utilisée ici pour ralentir l’animation.

Note

Il est possible d’arrêter le programme en appuyant sur la touche “ESCAPE”, VPython détecte cet événement et interrompt l’exécution.

13.4. Simplification grâce aux manipulations vectorielles

Le module fournit un type vector pour créer et manipuler des vecteurs. La création d’un vecteur se note:

v = vector(2,4,3)

Note

Les composantes de ces vecteurs sont toujours des flottants, même si elles sont données sous la forme d’entiers (dans ce cas elles sont converties et stockées en flottant).

Un vecteur peut être utilisé pour fixer la position d’un objet (en fait la propriété pos est du type vector):

b.pos = vector(2,4,3)
a.pos = v

Le module fournit divers opérations sur les vecteurs. Telles que l’addition, la soustraction et la multiplication par un scalaire:

v1 = vector(2,3,0)
v2 = 3 * v + v1 - vector(0,0,5)

ou encore la norme (appelée magnitude):

normeV = mag(v)

Il est aussi possible par une simple affectation de modifier la norme d’un vecteur, ce vecteur gardant la même direction et le même sens:

v1.mag=2

Warning

La fonction norm existe mais ne fournit pas la norme, elle permet d’obtenir le vecteur normalisé correspondant (vecteur de même direction et de même sens, mais de norme 1):

w = norm(v) # c'est n'est pas la norme de v !

Le type vector permet d’exprimer les calculs de façon plus naturelle et compacte. Ainsi dans l’exemple précèdent on pourra remplacer:

vaisseau.x = vaisseau.x + random() - 0.5
vaisseau.y = vaisseau.y + random() - 0.5

par:

vaisseau.pos = vaisseau.pos + vector(random()-0.5,random()-0.5,0)

On dispose aussi bien sûr du produit vectoriel:

cross(v1,v2)

et du produit scalaire:

k = dot(v1,v2)

13.5. Angles et rotations

En VPython les angles sont en radians (comme en Python). La constante pi est définie par VPython ainsi que les fonctions de conversion degrés <-> radians: degrees(x) et radians(x).

L’angle entre deux vecteurs peut s’obtenir avec la fonction diff_angle:

v1 = vector(3,1,2); v2 = vector(1,-3,6)
a = v1.diff_angle(v2)

Pour les rotations, la fonction rotate fournit le vecteur résultant de la rotation d’un autre vecteur:

v1 = vector(2,3,1)
v3 = rotate(v1, angle=0.1, axis=(0,1,1))

angle est l’angle de rotation et axis est un vecteur qui donne l’axe de rotation.

Les rotations peuvent directement être appliquées sur les objets graphiques:

b = box()
b.rotate(angle=0.1, axis=(2,3,0), origin=(10,0,0))

Dans cet exemple, l’objet dont l’identifiant est dans b, est transformé par une rotation de 0.1 radian autour de l’axe orienté selon le vecteur (2,3,0) et passant par le point (10,0,0).

Si axis et origin ne sont pas spécifiés, c’est l’axe principal et l’origine de l’objet (en général le centre de l’objet) qui sont utilisés. Essayer par exemple:

b=box()
for i in range(400):
  rate(100)
  b.rotate(angle=0.01)