Projection 3D |
Programmation 3D
Chapitre
I
Projection 3D vers 2D
En théorie, vous ne devriez pas être
surpris d'appendre que votre écran d'ordinateur ne peut
afficher que des coordonnées en 2 dimensions.
Cet état
de fait pose un sérieux problème quand on désire
modéliser un objet 3D sur l'écran.
Comme les écrans
de sortie tridimensionnelle n'existent pas encore, voici un ouvrage
pour modifier les coordonnées 3D en 2D.
Pour se faire nous
allons utiliser la projection par perspective qui permet de
représenter correctement la profondeur d'un objet 3D.
(
1 ) OBJETS 3D :
Un objet 3D est décrit par un
ensemble de coordonnées (X,Y,Z).
Un objet est constitué
de plusieurs faces, et ces faces sont naturellement définies
par un ensemble de sommets, généralement trois car les
triangles permettent de dessiner toutes les faces possibles, et
évitent que les points ne soient pas dans le même
plan.
Les coordonnées des sommets possèdent
différents points de références dans
l'espace.
En 3D, on utilise quatre différents types
d'espaces :
Coordonnées locales (3D)
Ce
système de coordonnées nous retourne les sommets d'un
objet avec comme origine le centre de l'objet. Aussi connu sous le
nom de coordonnées d'objet.
Coordonnées de
monde (3D)
Ce système de coordonnées nous
retourne la position d'un objet dans un monde, avec comme origine le
centre de ce monde. C'est ici qu'on effectue la détection de
collisions et l'illumination.
Coordonnées de caméra
(3D)
Ce système est relatif à la caméra.
Les objets sont transformés des coordonnées de monde
vers les coordonnées de caméra pour définir ce
qui est visible sur l'écran.
Coordonnées
d'écran (2D)
Ce système de coordonnées
représente les coordonnées d'écran transformés
des coordonnées de caméra vers notre écran 2D.
L'origine est le centre de l'écran, et on trouve ces
coordonnées par la projection par perspective.
Dans
ce chapitre, nous allons assumer deux choses :
Premièrement,
la caméra est fixe et elle regarde vers le fond de l'écran,
c'est à dire (0,0,-1).
Deuxièmement, nous utilisons
un système de coordonnées main gauche, c'est à
dire que X positif va vers la droite, Y positive va vers le haut et Z
positif va vers le fond de l'écran.
Tout d'abord il est nécessaire de définir des nouveaux types. |
typedef struct { int x,y; }_2D; typedef struct { int x,y,z; }_3D; |
Maintenant, il faut convertir les coordonnées 3D en coordonnées 2D. Pour ce faire on utilise la PROJECTION PERSPECTIVE : |
/* Exemple : Des étoiles qui défilent. */ #include <SDL/SDL.h> #include <stdio.h> #include <conio.h> #define DISTANCE 100 #define MAX_ETOILES 1000 #define ZMIN -100S #define ZMAX -10 #define ResX 320 #define ResY 200 #define DX 160 #define DY 100 #define DZ (ZMAX-ZMIN) typedef struct str_2d { int x,y; }_2D; typedef struct str_3d { int x,y,z; }_3D; SDL_Surface *ecran; _3D Etoiles [MAX_ETOILES]; _2D Ecran [MAX_ETOILES]; void putpixel (int x, int y, unsigned char col) { SDL_Rect Point; Uint32 Couleur; Couleur=col+col<<2+col<<4; /* Rouge = Vert = Bleu => Gris */ Point.w=1;Point.h=1; Point.x=x;Point.y=y; SDL_FillRect(ecran,&Point,Couleur); } /* Initialise une étoile avec des variables aléatoires */ void PlaceEtoile(_3D *Vecteur, int z) { Vecteur->x = random(DX)-DX/2; Vecteur->y = random(DY)-DY/2; Vecteur->z = z; } /* Transforme les coordonnées 3D d'un point en coordonnées d'écran par perspective à point de fuite X' = (X/Z), en tenant compte de la distance locale et avec translation vers le milieu de l'écran */ void Projection(_3D Vecteur,_2D *Ecran) { Ecran->x = (ResX/2) + DISTANCE * Vecteur.x / Vecteur.z; Ecran->y = (ResY/2) + DISTANCE * Vecteur.y / Vecteur.z; } void main(void) { int e; SDL_Rect FullScreen; FullScreen.x=0;FullScreen.y=0; FullScreen.w=ResX;FullScreen.h=ResY; /* Initialise le mode graphique */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr,"Erreur SDL : %s\n",SDL_GetError()); exit(1); } ecran = SDL_SetVideoMode( ResX, ResY, 32, SDL_SWSURFACE|SDL_DOUBLEBUF ); if( ecran == NULL ) { fprintf(stderr,"Erreur SDL : %s\n",SDL_GetError()); exit(1); } randomize(); /* Initialise nombre aléatoire */ for(e=0;e<MAX_ETOILES;e++) /* Initialise les étoiles */ PlaceEtoile(&Etoiles[e],(random(DZ)+ZMIN)); do { for(e=0;e<MAX_ETOILES;e++) /* avance les étoiles */ { Etoiles[e].z++; if(Etoiles[e].z>ZMAX) PlaceEtoile(&Etoiles[e],ZMIN); } for(e=0;e<MAX_ETOILES;e++) /* Projection des étoiles */ { Projection(Etoiles[e],&Ecran[e]); putpixel(Ecran[e].x,Ecran[e].y,(Etoiles[e].z-ZMIN)*15/DZ+16 ); } SDL_Flip(ecran); SDL_FillRect(ecran,&FullScreen,0); } while(!kbhit()); } |