TUTORIAL 1: THE 3D ENGINE

  Home  
  Tutorials  
    The 3d engine    
    OpenGL and GLUT    
    Texture mapping    
    3ds File Loader    
    Vectors and lighting    
  Projects  
  Useful links  
  Store  
  About  
 

 
     
 

Subscribe to know
 about the latest updates

 
     
 
INTRODUCTION

Premièrement, il est nécessaire d’expliquer le principe de d’un moteur 3D.

La réponse est relativement simple: un moteur 3D est un ensemble de structures, fonctions et algorithmes utiliser pour visualiser, après de nombreux calculs et transformations des objets 3D sur un écran en 2D.

Les 3 parties principales d’un moteur 3D sont:

1-L’aquisition des données des objets dans des structures

2-Les transformations de position des objets dans le monde

3-Le rendu de la scène sur l’écran 2D

C’est pourquoi nous existons… allez maintenant au taf !

Dans cette leçon, nous verrons comment définir les structures principales pour tracer un objet 3D.

 

LES VERTICES 

Supposons que l’on ai un objet et que l’on veuille le montrer sur un écran en 2D. Afin de le réaliser, il est nécessaire d’obtenir des informations a propos de sa structure. Comment faire? Premièrement, on définit des points clés : les vertices de l’objet. Chaque vertex est composé de 3 coordonnées x, y et z. Chaque coordonnée doit être exprimée travers une variable FLOAT ou DOUBLE, car nous avons toujours besoin de la meilleure résolution pour rendre la scène. Cette solution est utilisée dans tout moteur 3D mais n’est pas sans défauts, en effet on perd de la précision pour des valeurs numériques trop élevés. Cela limite l’espace dans lequel la simulation évolue. Dans un simulateur spatial on peut éventuellement faire face a ce problème. En bref pour définir un vertex en C, on utilise une structure composée de 3 variables x,y,z.

typedef struct{
   float x,y,z;
}vertex_type;

Il est très important de garder à l’esprit que les calculs traitant du positionnement et de la rotation de l’objet sont appliqués aux vertex, puisque se sont les unités de la structure de base. La deuxième structure, en terme d’importance est le polygone.

 

LES POLYGONES

Les polygones sont les faces de l’objet et sont composées de N vertex. Dans la plupart des moteurs 3D, les polygones sont composés de  3 vertex, en accord avec cette règle.
Utilisant notre structure vertex_type , on peut définir une structure de polygone qui contient 3 vertices:

typedef struct{
   vertex_type a,b,c;
}polygon_type;

Nous déclarons aussi une variable tableau  polygon_type qui sera remplie par tous les polygones qui constitue l’objet

#define MAX_POLYGONS 2000
polygon_type polygon[MAX_POLYGONS]; 

Mais… attention ! Notre définition assigne 3 vertices à chaque polygone et ces vertex ne sont pas partagés avec les autres polygones. En effet, si l’on réfléchit un peu nous allons voir que chaque polygone d’un objet partage en fait ses cotés, et aussi ses vertices avec les autres polygones. Donc nous avons fait une erreur ! Bon, c’est pas vraiment une erreur, mais nous avons augmenté considérablement le nombre réel de vertex de la scène bien plus que de nécessaire. On a déjà dit que le moteur utiliserait les vertex pour faire ses calculs donc on devrait vraiment trouver une autre méthode pour définir nos polygones. On pourrait créer une liste de vertices qui contiendrait l’ensemble des vertices de l’objet. Afin de définir les polygones, on utilisera une sorte de schéma de références qui pointe sur les vertices de la liste. On déclare maintenant un tableau de type vertex_type qui contiendra MAX_VERTICES vertices.

#define MAX_VERTICES 2000
vertex_type vertex[MAX_VERTICES];

La structure polygone ne contiendra plus les vertices mais seulement 3 nombres qui pointent sur 3 éléments de la liste des vertices. Dans ce sens, plus de polygones peuvent pointés sur le même vertex. Cela optimise grandement le design du moteur.

typedef struct{
   int a,b,c;
}polygon_type;

 

L’OBJET

On effectue ici un peu de nettoyage, et on organise les définitions précédentes dans une structure que l’on appelle obj_type

typedef struct{
   vertex_type vertex[MAX_VERTICES];
   polygon_type polygon[MAX_POLYGONS];
}obj_type,*obj_type_ptr;

C’est la seule définition de base. Plus tard, on ajoutera plus de champs qui identifierons la position, rotation et état de l’objet.

A ce point nous pouvons déclarer la variable objet et remplir la liste des vertices.

obj_type obj;

obj.vertex[0].x=0;  obj.vertex[0].y=0;  obj.vertex[0].z=0; //vertex v0
obj.vertex[1].x=1;  obj.vertex[1].y=0;  obj.vertex[1].z=0; //vertex v1
obj.vertex[2].x=1;  obj.vertex[2].y=0;  obj.vertex[2].z=1; //vertex v2
obj.vertex[3].x=0;  obj.vertex[3].y=0;  obj.vertex[3].z=1; //vertex v3
obj.vertex[4].x=0;  obj.vertex[4].y=1;  obj.vertex[4].z=0; //vertex v4
obj.vertex[5].x=1;  obj.vertex[5].y=1;  obj.vertex[5].z=0; //vertex v5
obj.vertex[6].x=1;  obj.vertex[6].y=1;  obj.vertex[6].z=1; //vertex v6
obj.vertex[7].x=0;  obj.vertex[7].y=1;  obj.vertex[7].z=1; //vertex v7

Maintenant le problème et de subdiviser notre cube en triangles. La réponse est simple : chaque face du cube est un carré composé par deux triangles adjacents. Donc notre cube sera composé de 12 polygones (triangles) et 8 vertices.

La liste des polygones doit être remplie comme suit:

obj.polygon[0].a=0;  obj.polygon[0].b=1;  obj.polygon[0].c=4;  //polygon v0,v1,v4
obj.polygon[1].a=1;  obj.polygon[1].b=5;  obj.polygon[1].c=4;  //polygon v1,v5,v4
obj.polygon[2].a=1;  obj.polygon[2].b=2;  obj.polygon[2].c=5;  //polygon v1,v2,v5
obj.polygon[3].a=2;  obj.polygon[3].b=6;  obj.polygon[3].c=5;  //polygon v2,v6,v5
obj.polygon[4].a=2;  obj.polygon[4].b=3;  obj.polygon[4].c=6;  //polygon v2,v3,v6
obj.polygon[5].a=3;  obj.polygon[5].b=7;  obj.polygon[5].c=6;  //polygon v3,v7,v6
obj.polygon[6].a=3;  obj.polygon[6].b=0;  obj.polygon[6].c=7;  //polygon v3,v0,v7
obj.polygon[7].a=0;  obj.polygon[7].b=4;  obj.polygon[7].c=7;  //polygon v0,v4,v7
obj.polygon[8].a=4;  obj.polygon[8].b=5;  obj.polygon[8].c=7;  //polygon v4,v5,v7
obj.polygon[9].a=5;  obj.polygon[9].b=6;  obj.polygon[9].c=7;  //polygon v5,v6,v7
obj.polygon[10].a=3; obj.polygon[10].b=2; obj.polygon[10].c=0; //polygon v3,v2,v0
obj.polygon[11].a=2; obj.polygon[11].b=1; obj.polygon[11].c=0; //polygon v2,v1,v0

On doit garder à l’esprit que pour définir les polygones proprement, il est nécessaire de toujours utiliser la même direction sens des aiguille d’une montre ou sens inverse pour tous les polygones de la scène. On verra dans le prochain tutorial, comment la direction est utilisée pour déterminer si le polygone est visible ou pas. Donc faites très attention à la façon dont vous définissez les polygones ou nombres d’entre eux ne seront pas visibles. On utilisera ici la méthode sens inverse des aiguilles (par exemple le premier polygone est définit par v0,v1,v4 ou v1,v4,v0 ou v4,v0,v1 et non pas par v1,v0,v4 ou v0,v4,v1 ou v4,v1,v0). 

 

UNE AUTRE METHODE PLUS ELEGANTE POUR DEFINIR NOTRE OBJET

En C/C++ on peut remplir la structure obj_type de cette façon plus élégante:


obj_type cube = 
{
    {
        -10,-10, 10, //vertex v0
         10,-10, 10, //vertex v1
         10,-10,-10, //vertex v2
        -10,-10,-10, //vertex v3
        -10, 10, 10, //vertex v4
         10, 10, 10, //vertex v5
         10, 10,-10, //vertex v6 
        -10, 10,-10  //vertex v7
    },  
    {
        0, 1, 4, //polygon v0,v1,v4
        1, 5, 4, //polygon v1,v5,v4
        1, 2, 5, //polygon v1,v2,v5
        2, 6, 5, //polygon v2,v6,v5
        2, 3, 6, //polygon v2,v3,v6
        3, 7, 6, //polygon v3,v7,v6
        3, 0, 7, //polygon v3,v0,v7
        0, 4, 7, //polygon v0,v4,v7
        4, 5, 7, //polygon v4,v5,v7
        5, 6, 7, //polygon v5,v6,v7
        3, 2, 0, //polygon v3,v2,v0
        2, 1, 0, //polygon v2,v1,v0
    }
};

On peut également noter que les coordonnées de vertices de 0,1 à 10, -10. Cela est intentionnel, en effet, on a besoin d’avoir le centre de l’objet à 0,0 (on comprendra pourquoi dans le prochain tutorial). Notre objet est également 20 fois plus gros (pour faciliter la manipulation des coordonnées).

 

CONCLUSIONS  

C’est tout pour cette leçon. Dans la suivante, on commencera par utiliser OpenGL pour afficher notre cube à l’ecran. Si vous avez des doutes ou trouvez des erreurs n’hésitez pas à me contacter info[at]spacesimulator.net (en anglais svp)

SOURCE CODE

Téléchargez le code source ici: C/C++ source code

 

NEXT TUTORIAL>>

 

 

©2000-2003 Damiano Vitulli. All Rights Reserved. No Portion Of This Site May Be Reproduced Without Permission. Best viewed at 1024x768.