Si OpenGL vous autorise à réaliser des figures planes, c'est bien sûr dans l'espace que toute la puissance de cette bibliothèque apparaît.
Cette représentation dans l'espace s'effectue en trois partie :
En effet, pouvoir placer des objets à trois dimension dans la scène c'est bien, mais pouvoir se déplacer dans ladite scène, c'est mieux : un cube vu de face apparaît comme un carré, et il est donc inutile de travailler avec trois coordonnées et huit sommets, si on ne peut pas se déplacer autour du cube.
Ainsi, en OpenGL, on peut :
Pour illustrer cela, on commence par placer un cube de de côté 1.0 centré à l'origine (c'est le programme cube.py) :
from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * import sys def ecran(): glClearColor(0.5,0.5,0.5,0.5) glClear(GL_COLOR_BUFFER_BIT) glutWireCube(1.0) glFlush() def main(): glutInit(sys.argv) glutInitDisplayMode(GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("Un cube") glutDisplayFunc(ecran) glutMainLoop() main()
Le fond d'écran est gris (glClearColor(0.5,0.5,0.5,0.5)).
Comme on regarde le cube de face, il apparaît comme un carré.
C'est pourquoi il va falloir déplacer notre point de vue (notre caméra).
Pour cela, on utilise gluLookAt(), qui permet de changer de point de vue (on étudiera précisément cette fonction dans un prochain TP), et on spécifie le mode de vision (perspective), pour donner une impression de 3d.
Il faut donc insérer une ligne dans la fonction ecran(), comme suit (c'est le programme cube1.py) :
def ecran(): glClearColor(0,0,0,0) glClear(GL_COLOR_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(-3,0,0,0,0,0,0,1,0) glColor3d(1,0,0) glutWireCube(1.0) glFlush()
...et préciser encore que la vue doit être en perspective (et accessoirement définir les actions à réaliser en cas de redimensionnement de la fenêtre) comme cela :
def reshape(*args): glViewport(0,0,args[0],args[1]) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(60.0,float(args[0])/args[1],1.,10.)
en n'oubliant pas dans le main() :
glutReshapeFunc(reshape)
Tout cela peut paraître compliqué, mais le résultat est ce que l'on souhaite :
Les prochains tps reviendront sur le sens de la fonction reshape(), mais pour l'instant nous nous occupons de placer des objets dans la scène, et non pas de la visualisation de ces objets.
glutWireCube() n'est pas la seule fonction de ce genre. On trouve de même :
De plus, on peut remplacer, dans ces fonctions, Wire (c'est-à-dire en fil de fer) par Solid (en faces pleines).
Ces différents objets sont placés à l'origine dans notre scène
Si on veut les positionner ailleurs, il faut avoir recours aux applications de translation et de rotation : glTranslatef() et glRotatef().
Ainsi, pour poser une théière sur un cube (c'est le programme cubeEtPot.py) :
def ecran(): glClearColor(0,0,0,0) glClear(GL_COLOR_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(0.4,0.4,3.,0.,0.,0.,0.,1.,0.) glColor3d(1,0,0) glutWireCube(1.0) glTranslatef(0.,0.7,0.) glutSolidTeapot(0.3) glFlush()
Ce qui donne :
Une autre manière de procéder pour représenter des objets dans l'espace est d'utiliser comme précédemment :
où mode définit la méthode pour relier lesdits sommets.
Par exemple, considérons le programme pyramide.py, qui représente une pyramide à base carrée :
On y trouve les différents triangles définis à la suite les uns des autres, et bien positionnés dans l'espace, comme suit
glBegin(GL_LINE_LOOP) glVertex3f(0.5,0.5,0.0) glVertex3f(0.,0.,1.0) glVertex3f(0.5,-0.5,0.0) glVertex3f(0.5,0.5,0.0) glVertex3f(-0.5,0.5,0.0) glVertex3f(0.,0.,1.0) glVertex3f(-0.5,-0.5,0.0) glVertex3f(-0.5,0.5,0.0) glVertex3f(0.5,0.5,0.0) glVertex3f(0.5,-0.5,0.0) glVertex3f(-0.5,-0.5,0.0) glVertex3f(-0.5,0.5,0.0) glEnd()
Dans ce programme, différents points de vue sont accessibles : la variable pv passée en argument de gluLookAt() est modifiable par le clavier...
def clavier(*args): global pv # Le point de vue if args[0] == 'q': sys.exit() elif args[0] == 'a': pv = (-2.,-1.,.0,0.,0.,0.,0.,0.,1.) elif args[0] == 'z': pv = (-2.,-1.,.5,0.,0.,0.,0.,0.,1.) elif args[0] == 'e': pv = (-2.,-1.,1.5,0.,0.,0.,0.,1.,1.) elif args[0] == 'r': pv = (-3.,-1.,.5,0.,0.,0.,0.,0.,1.) glutPostRedisplay()
Les touches a, z, e, et r changent ainsi pv (le point de vue).
Certaines bibliothèques OpenGL possèdent plus de primitives graphiques que d'autres. Ainsi, si vous utilisez la bibliothèque OpenGLUT fournie dans la distribution Ubuntu GNU/Linux, vous n'aurez pas les fonctions glutWireCylinder(), ou encore glutSolidSierpinskiSponge(), par exemple.
En fait, OpenGL s'occupe de gérer le rendu d'une scène 3d, en permettant d'avoir un certain éclairage, la présence de brouillard, etc. mais ça n'est pas un logiciel de dessin : son rôle n'est pas de créer des objets 3d, mais de s'occuper de la scène contenant ces objets (qui sont fait dans la pratique sous Direct3d, ou Blender).
Vous pouvez à présent vous entrainer à placer ces figures élémentaires sur la scène, en ayant recours à glTranslatef() et glRotatef().