Nous allons maintenant changer le point de vue de la scène.
Imaginons pour cela que nous enregistrions la scène 3d au moyen d'une caméra. Il y a trois paramètres à régler, à savoir :
Ces trois valeurs se changent à l'aide de la fonction gluLookAt(), qui admet neuf paramètres :
Notez les valeurs par défaut de ces paramètres :
Mais avant de positionner notre caméra dans la scène, il faut la régler (ou plus exactement définir notre champ de vision : notre oeil, par exemple, ne distingue pas les objets trop proches ou trop éloignés, ni sur les côtés), avec la fonction gluPerspective(), c'est-à-dire :
La figure ci-dessous illustre cela :
La partie capturée par la caméra se trouve dans la partie basse de cette pyramide renversée.
L'angle A au sommet de la pyramide correspond ici à l'angle d'ouverture de la caméra (dans le plan yOz).
Il ne reste plus qu'à connaître le rapport w/h pour avoir le volume exact de la scène à représenter à l'écran. En effet, à une largeur de pyramide correspondra une unique longueur, donc en augmentant notre largeur de fenêtre, la longueur de la scène à afficher changera aussi.
Ainsi, par exemple,
gluPerspective(45.0,float(w)/h,1.,10.)
définit une caméra avec un angle d'ouverture de 45°, une base de pyramide ayant un rapport de largeur sur longueur égal à w/h, et tous les points trop proches (z<1.0 par-rapport au z de la caméra) ou trop loin (z>10.0) ne seront pas affichés.
Remarquons enfin qu'une autre fonction,
glFrustum(gauche,droite,bas,haut,proche,éloigné),
fait le même travail, sauf qu'on spécifie les 4 coordonnées définissant le premier rectangle de la figure précédente, les deux dernières variables étant les mêmes que pour gluPerspective().
Reste à savoir où placer gluPerspective().
Il faut d'abord signaler dans le main() qu'une fonction, que l'on nomme traditionnellement reshape(), est chargée de gérer l'affichage de la scène (contenue dans la fonction ecran()).
C'est-à-dire que la fonction reshape() est sensée :
Cela se fait, comme d'habitude, au moyen d'un glutReshapeFunc(reshape).
La partie de programme qui suit illustre ce principe :
def reshape(*args):
glViewport(0,0,args[0],args[1]) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(60.0,float(args[0])/args[1],1.,10.)
def main():
glutInit(sys.argv) glutInitDisplayMode(GLUT_RGBA) glutInitWindowPosition(100,100) glutInitWindowSize(320,320) glutCreateWindow("Une table") glutDisplayFunc(ecran) glutReshapeFunc(reshape) glutMainLoop()
(Il manque ici le détail de la fonction ecran(), donnant du sens à ce programme.)
Les paramètres passés à la fonction reshape() via OpenGL sont :
On parle ici de la fenêtre qui vient d'être créée, ou déplacée, ou redimensionnée.
Ces paramètres se retrouvent naturellement dans la fonction gluPerspective() pour obtenir exactement le champ de vision détaillé au point précédent.
Expliquons maintenant le glLoadIdentity().
Comme dans le cours d'algèbre-géométrie, l'espace est un ensemble de points, et de volumes pleinement définis par la donnée de points caractéristiques : les sommets d'un cube, etc.
Et, comme dans notre cours, effectuer un déplacement revient à multiplier ces points à l'aide de matrices de transformation : homothétie, rotation, projection, etc. La matrice produit résultante s'appelle alors la « matrice active. »
Donc, pour obtenir une représentation plane (dans notre écran) à partir d'un espace de points 3d (notre scène), OpenGL multiplie, à notre demande, chaque point de l'espace par les matrices de transformation adéquates.
Quand on demande plusieurs opérations de ce type, OpenGL multiplie les matrices correspondantes entre-elles, et attend le signal pour appliquer la matrice résultante (c'est-à-dire la « matrice active ») à l'ensemble des points.
On peut ainsi enchaîner les opérations géométriques à effectuer en rajoutant des matrices au produit en mémoire. Cependant, il faut enlever ce produit matriciel de la mémoire, réinitialiser la « matrice active » à chaque fois que l'on souhaite faire une nouvelle opération, sans quoi OpenGL rajoutera sans cesse les nouvelles opérations aux anciennes, donnant un produit matriciel sans fin.
C'est le sens de glLoadIdentity(), qui transforme la « matrice active », la rendant égale à la matrice identité.
En fait, OpenGL distingue trois types d'opérations matricielles, concernant respectivement :
Pour simplifier la tâche du programmeur, la « matrice active » est donc le produit de trois matrices, correspondant respectivement à chacun des points précédents. Ainsi, par exemple, on peut vouloir changer la projection sans toucher à notre modèle, ni à ses textures.
Il convient donc, avant d'utiliser glLoadIdentity(), de préciser quelle partie de la matrice active on souhaite initialiser. Pour cela, on spécifie avec la fonction glMatrixMode() quelle est la partie concernée de la matrice active :
Il faut donc, à chaque fois, préciser sur quelle partie porte nos lignes de code (visualisation-modélisation, cadrage-projection, ou textures). Notez cependant que, par défaut, OpenGL est en glMatrixMode(GL_MODELVIEW).