Projection 3D

Transformation

Remplissage des faces

Eclairage

Textures

Z-Buffering



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 :
C'est un théorème redécouvert à la Renaissance.

ecran.x = point.x / point.z;
ecran.y = point.y / point.z;

C'est aussi simple que cela.
Le hic, c'est que cette équation assume que nous somme à l'origine.
Donc pour rétablir la situation, nous ajoutons les valeurs correctes.
Donc soit ResX la résolution en x et ResY la résolution en y.

ecran.x = ( ResX / 2 ) + point.x / point.z;
ecran.y = ( ResY / 2 ) + point.y / point.z;

finalement nous devons considérer la distance de la caméra.
Donc soit Distance la distance de la camera.

ecran.x = ( ResX / 2 ) + Distance * point.x / point.z;
ecran.y = ( ResY / 2 ) + Distance * point.y / point.z;

Mais pour créer l'effet de profondeur il faut aussi jouer sur la couleur.
Elle doit varier en fonction de z.

/*
        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());
 }