Copy Link
Add to Bookmark
Report

3d Chapitre 3 - Modélisations

eZine's profile picture
Published in 
2d3dfx
 · 17 Feb 2021

CHAPITRE 3 - Modélisations

Ce chapitre traite de 3 différentes façon de représenter nos objets 3D. La première méthode ne rempli pas les faces des polygones, elle ne fait que dessiner les vecteurs sous forme de lignes, d'où l’appellation "filaire", ou Wire Frame en anglais. La seconde méthode présenté est celle du Glenzing, ou "face de verre", qui elle rempli la surface mais ne gère pas les faces cachées. Finalement, nous verrons le remplissage uniforme des polygones avec gestion des faces cachées.

FILIAIRE

Cette méthode requiert une petite modification à la structure de donnée « Objet » vue au chapitre précédent. En effet, dans son état présent, le programme possède les coordonnées des 8 sommets du cube. Pour dessiner les arrêtes de ce cube, nous allons avoir besoins des couples de lignes formant ce cube, un pour chaque arrête du cube, soit 12. Elles seront pour leur part contenu dans la structure 2D Lignes. On ajoute la fonction de ligne de Bresenham, et le reste du programme est pareil.

 typedef struct _objet     // Structure pour contenir un objet 
{
int nbsommet; // nombre de sommets
int nbligne; // nombre de lignes
_sommet sommet[100]; // coordonnées des sommets
_2D ligne[100]; // couples de lignes
};

2D Ligne[12]={
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};

3d Chapitre 3 - Modélisations
Pin it

FACE DE VERRE

Le deuxième programme exemple effectue le remplissage des surfaces du cube. Premièrement, nous aurons besoin d’initialiser les 6 faces de notre cube, sous forme de quadrilatères. Une structure pouvant contenir 4 coordonnée est donc mise sur pied, et encore une fois nous devons indiquer quels vecteurs décrivent la surface:

 typedef struct _quad // Structure pour représenter une surface quadrilatère 
{
short a,b,c,d;
};


typedef struct _objet // Structure pour contenir un objet
{
int nbsommet; // nombre de sommets
int nbpolygone; // nombre de polygone
_sommet sommet[MAX_SOMM]; // coordonnees des sommets
_quad poly[MAX_POLY]; // polygone
};


Pour les explications sur la fonction de scanline et de dessin de polygones, regarder la section 2D, chapitre 2, car je n’y reviendrai pas dans ce chapitre. Il faut donc parcourir chaques faces et trouver les extremités de chaques polygones. Ensuite, quand viens le temps de dessiner les polygones, on transmet leurs coordonnées d’écran à la fonction dessine_poly :

 void dessine_objet(_objet *objet) 
{
_2D poly[4];

for (int f=0; f<6; f++)
{
poly[0] = objet->sommet[objet->poly[f].a].ecran;
poly[1] = objet->sommet[objet->poly[f].b].ecran;
poly[2] = objet->sommet[objet->poly[f].c].ecran;
poly[3] = objet->sommet[objet->poly[f].d].ecran;

dessine_poly(poly,4,20+f);
}
}

3d Chapitre 3 - Modélisations
Pin it

GESTION DES FACES CACHÉES

La dernière technique présenté consiste à remplir les surfaces d'un objet d'un couleur uni, sans aucun artifice. Toutes les techniques vues ci-haut sont encore utilisé. En fait, côté code, il s'agit que de rajouter un tout petit "if" et le tour est joué. Avant de remplir chacune des facettes de notre objet 3D, nous devons éliminer celles qui ne sont pas visibles par l'observateur. La technique présentée ici fonctionne seulement avec des objets convexe, comme un cube. Cependant, pour des objets concaves, il faudra ajouter une autre étape, que je présente au prochain chapitre.

Comme la caméra est fixe sur (0,0,1), il est très facile de vérifier si une face est visible ou non. Il suffit de tester le signe de sa normale de face. Pour obtenir le vecteur normal, un faut effectuer le produit vectoriel, qui nous retourne alors le vecteur perpendiculaire a la face.

      | Normale 
|
|
_____|_____ Polygone

Comme vous pouvez le voir, la normal est à 90 deg par rapport à la surface du polygone. Afin de trouver la normale, il nous faut 3 points consécutif de notre polygone, disons (A,B,C), et ensuite nous effectuons le produit vectoriel. Donc, la normal Xn, Yn et Zn du vecteur est

Xn=(y1-y0)(z0-z2)-(z1-z0)(y0-y2)
Yn=(z1-z0)(x0-x2)-(x1-x0)(z0-z2)
Zn=(x1-x0)(y0-y2)-(y1-y0)(x0-x2)

Dans notre cas, nous sommes intéressé par la normale Z, donc nous utiliserons la dernière formule. En sachant que la caméra pointe vers (0,0,1), si la normale nous retourne une valeur négative, cela signifie que le polygone est face à nous (donc on peut le dessiner), tandis qu'une valeur positive signifie qu'il pointe de l'autre direction. Autre fait intéressant, comme la normale Z n’a pas besoin d’élément Z (seulement X et Y), nous pouvons effectuer ce calcul sur les coordonnées d’écran!

 for (int f=0; f<6; f++) 
{
poly[0] = objet->sommet[objet->poly[f].a].ecran;
poly[1] = objet->sommet[objet->poly[f].b].ecran;
poly[2] = objet->sommet[objet->poly[f].c].ecran;
poly[3] = objet->sommet[objet->poly[f].d].ecran;

normale = (poly[0].y - poly[2].y) *
(poly[1].x - poly[0].x) -
(poly[0].x - poly[2].x) *
(poly[1].y - poly[0].y);

if (normale<0) dessine_poly(poly,4,21+f);
}
}

3d Chapitre 3 - Modélisations
Pin it

C'est pas plus compliqué que cela! On dessine le polygone si la normale est négative. Dans le prochain cours, nous verrons comment utiliser les normales pour faire des effets d'ombrages plus réalistes que cette simple démonstration.

En résumé :

  • Gestion des faces cachées grâce au produit vectoriel
  • Modélisation filiaire, face de verre, et uniforme
  • Modification à la structure de données _Objet


3dchap3a.cpp

  
//////////////////////////////////////////////////////////////////////////
// Code source : Shaun Dore //
// Fichier : 3DCHAP2A.CPP //
// Date : 29-09-1998 //
// Compilateur : Borland C++ 3.1 //
// Description : Rotation 3D //
//////////////////////////////////////////////////////////////////////////

// --------------------------- INCLUDE --------------------------------//

#include <mem.h>
#include <math.h>
#include <conio.h>

// ---------------------- CONSTANTES & MACROS --------------------------//

#define MX 160 // Millieu de l'abscisse
#define MY 100 // Millieu de l'ordonnee
#define DISTANCE 200 // Distances de l'objet
#define SIN(x) SinTable[x] // Macro SIN()
#define COS(x) CosTable[x] // Macro COS()

// ------------------- STRUCTURES DE DONNEES --------------------------//

// type matrice reelle de 4x4
typedef float _mat[4][4];

// Structure pour representer un point dans un espace 2D
typedef struct _2D
{
int x,y;
};

// Structure pour representer un point dans un espace 3D
typedef struct _3D
{
float x,y,z;
};

// Structure pour represente un sommet
typedef struct _sommet
{
_3D local; // coordonnees locales
_3D monde; // coordonnees dans le monde
_2D ecran; // coordonnees d'ecran
};

// Structure pour contenir un objet
typedef struct _objet
{
int nbsommet; // nombre de sommets
_sommet sommet[100]; // coordonnees des sommets
int nbligne; // nombre de lignes
_2D ligne[100]; // couples de lignes
};


//------------------------- VARIABLES GLOBALES --------------------------//

// Utilise pour initialiser les coordonnes locales d'un objet de type cube
_3D Cube[8] = {
{ 1.0, 1.0, 1.0 },
{ -1.0, 1.0, 1.0 },
{ -1.0, -1.0, 1.0 },
{ 1.0, -1.0, 1.0 },
{ 1.0, 1.0, -1.0 },
{ -1.0, 1.0, -1.0 },
{ -1.0, -1.0, -1.0 },
{ 1.0, -1.0, -1.0 }
};

_2D Ligne[12]={
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};

float SinTable[360]; // Table Sinus
float CosTable[360]; // Table Cosinus
_mat matrice; // mat de transformation homogene
_mat mat1, mat2; // matrices temporaires

char *ecran = (char *) (0xA0000000L); // Memoire video
char *virtuel = new char[64000L]; // Ecran virtuel

// ------------------------- FONCTIONS --------------------------------//


void line(int x1, int y1, int x2, int y2, unsigned char coul)
{
int x_chan, y_chan; // Pour le changement dans x et y
int offset = (y1<<8)+(y1<<6) + x1; // Calcule l'offset dans la RAM
int ydiff = y2-y1; // Calcule la difference entre y2 et y1
int deviation = 0; // Initialise la deviation a 0;

if (ydiff < 0) // Si la ligne va dans un direction -
{
ydiff = -ydiff;
y_chan = -320;
}
else y_chan = 320;

int xdiff = x2-x1; // Calcule la difference entre x2 et x1

if (xdiff < 0) // Si la ligne va dans un direction +
{
xdiff = -xdiff;
x_chan = -1;
}

else x_chan = 1;

if (xdiff > ydiff) // si la difference est + grande
{ // sur l'axe X
int longueur = xdiff+1;
for(int i = 0; i < longueur; i++)
{
virtuel[offset] = coul;
offset+=x_chan;
deviation+=ydiff;
if (deviation>xdiff) // Est-ce le temps de changer Y?
{
deviation-=xdiff;
offset+=y_chan;
}
}
}
else // Difference + grande sur Y
{
int longueur = ydiff+1;
for(int i = 0; i < longueur; i++)
{
virtuel[offset] = coul;
offset+=y_chan;
deviation+=xdiff;
if (deviation>0) // Est-ce le temps de changer X?
{
deviation-=ydiff;
offset+=x_chan;
}
}
}
}

/////////////////////////////////////////////////////////////////////////
// precalc - Calcule le tableau de sinus/cosinus //
/////////////////////////////////////////////////////////////////////////
void precalc()
{
for(int angle=0; angle<360; angle++)
{
SinTable[angle]=sin(angle*M_PI/180.0);
CosTable[angle]=cos(angle*M_PI/180.0);
}
}

/////////////////////////////////////////////////////////////////////////
// copie_matrice - copie une matrice source vers matrice destination //
/////////////////////////////////////////////////////////////////////////
void copie_matrice(_mat4x4 source, _mat4x4 dest)
{
memcpy(dest,source,sizeof(_mat4x4));
}


/////////////////////////////////////////////////////////////////////////
// mult_matrice - multiplie 2 matrices et mets le resultat dans dest //
/////////////////////////////////////////////////////////////////////////
void mult_matrice(_mat m1, _mat m2, _mat dest)
{
for(short i=0;i<4;i++)
for(short j=0;j<4;j++)
dest[i][j]=
m1[i][0]*m2[0][j]+
m1[i][1]*m2[1][j]+
m1[i][2]*m2[2][j]+
m1[i][3]*m2[3][j];
}


/////////////////////////////////////////////////////////////////////////
// ident_matrice - construit une matrice identite //
/////////////////////////////////////////////////////////////////////////
void ident_matrice(_mat m)
{
memset(m,NULL,sizeof(_mat));
m[0][0] = 1.0;
m[1][1] = 1.0;
m[2][2] = 1.0;
m[3][3] = 1.0;
}

/////////////////////////////////////////////////////////////////////////
// echelle - matrice de changement d'echelle //
/////////////////////////////////////////////////////////////////////////
void echelle(_mat m,float ex,float ey, float ez)
{
_mat emat;

ident_matrice(emat);
emat[0][0]=ex;
emat[1][1]=ey;
emat[2][2]=ez;

mult_matrice(m,emat,mat1);
copie_matrice(mat1,m);
}

/////////////////////////////////////////////////////////////////////////
// translation - matrice de translation //
/////////////////////////////////////////////////////////////////////////
void translation(_mat m,float tx,float ty,float tz)
{
_mat tmat;

ident_matrice(tmat);
tmat[3][0]=tx;
tmat[3][1]=ty;
tmat[3][2]=tz;

mult_matrice(m,tmat,mat1);
copie_matrice(mat1,m);
}


/////////////////////////////////////////////////////////////////////////
// rotation - matrice de rotation //
/////////////////////////////////////////////////////////////////////////
void rotation(_mat m,int ax,int ay,int az)
{
_mat xmat, ymat, zmat;

ident_matrice(xmat);
ident_matrice(ymat);
ident_matrice(zmat);

xmat[1][1] = COS(ax); xmat[1][2] = SIN(ax);
xmat[2][1] = -SIN(ax); xmat[2][2] = COS(ax);

ymat[0][0] = COS(ay); ymat[0][2] = -SIN(ay);
ymat[2][0] = SIN(ay); ymat[2][2] = COS(ay);

zmat[0][0] = COS(az); zmat[0][1] = SIN(az);
zmat[1][0] = -SIN(az); zmat[1][1] = COS(az);

mult_matrice(m,ymat,mat1);
mult_matrice(mat1,xmat,mat2);
mult_matrice(mat2,zmat,m);
}

/////////////////////////////////////////////////////////////////////////
// projection - transformation 3D -> 2D //
/////////////////////////////////////////////////////////////////////////
void projection(_sommet *sommet)
{
if(!sommet->monde.z) sommet->monde.z=1;
sommet->ecran.x = MX + sommet->monde.x * (DISTANCE / sommet->monde.z);
sommet->ecran.y = MY + sommet->monde.y * (DISTANCE / sommet->monde.z);
}

/////////////////////////////////////////////////////////////////////////
// transformation - multiplication de chaque sommet par la matrice //
/////////////////////////////////////////////////////////////////////////
void transformation(_objet *object, _mat m)
{
int v;
_sommet *sommet;

for(v=0; v<object->nbsommet; v++)
{
sommet = &object->sommet[v];

sommet->monde.x = sommet->local.x*m[0][0]+
sommet->local.y*m[1][0]+
sommet->local.z*m[2][0]+
m[3][0];

sommet->monde.y = sommet->local.x*m[0][1]+
sommet->local.y*m[1][1]+
sommet->local.z*m[2][1]+
m[3][1];

sommet->monde.z = sommet->local.x*m[0][2]+
sommet->local.y*m[1][2]+
sommet->local.z*m[2][2]+
m[3][2];
projection(sommet);
}
}

/////////////////////////////////////////////////////////////////////////
// Initialisation des sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void initialise_objet(_objet *objet)
{
objet->nbsommet=8;
objet->nbligne=12;
for (int i=0;i<objet->nbsommet;i++)
{
objet->sommet[i].local.x=Cube[i].x;
objet->sommet[i].local.y=Cube[i].y;
objet->sommet[i].local.z=Cube[i].z;
}
for (i=0;i<objet->nbligne;i++)
{
objet->ligne[i].x = Ligne[i].x;
objet->ligne[i].y = Ligne[i].y;
}
}

/////////////////////////////////////////////////////////////////////////
// dessine_objet - dessine les sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void dessine_objet(_objet *objet)
{
_2D deb, fin;

for (int l=0;l<objet->nbligne;l++)
{
deb.x = objet->sommet[objet->ligne[l].x].ecran.x;
deb.y = objet->sommet[objet->ligne[l].x].ecran.y;

fin.x = objet->sommet[objet->ligne[l].y].ecran.x;
fin.y = objet->sommet[objet->ligne[l].y].ecran.y;

line(deb.x,deb.y,fin.x,fin.y,31);
}
}

//------------------------ FONCTION PRINCIPALE --------------------------//


void main(void)
{
int angle=0;
_objet cube;

asm {MOV AX,0x13; INT 0x10}
precalc();
initialise_objet(&cube);

while(!kbhit())
{
memset(virtuel,0,64000L);

ident_matrice(matrice);
echelle(matrice,20,20,20);
rotation(matrice,angle,angle,angle);
translation(matrice,0,0,-100);

transformation(&cube,matrice);
dessine_objet(&cube);

while(!(inp(0x3DA)&8));
memcpy(ecran,virtuel,64000L);
if (angle++ == 359) angle = 0;
};

delete []virtuel;
asm {MOV AX,0x03; INT 0x10}
}


3dchap3b.cpp

  
//////////////////////////////////////////////////////////////////////////
// Code source : Shaun Dore //
// Fichier : 3DCHAP2A.CPP //
// Date : 29-09-1998 //
// Compilateur : Borland C++ 3.1 //
// Description : Rotation 3D //
//////////////////////////////////////////////////////////////////////////

// --------------------------- INCLUDE --------------------------------//

#include <mem.h>
#include <math.h>
#include <conio.h>

// ---------------------- CONSTANTES & MACROS --------------------------//

#define MX 160 // Millieu de l'abscisse
#define MY 100 // Millieu de l'ordonnee
#define DISTANCE 200 // Distances de l'objet
#define MAX_POLY 100 // Nb max de polygones
#define MAX_SOMM 100 // Nb max de sommets
#define SIN(x) SinTable[x] // Macro SIN()
#define COS(x) CosTable[x] // Macro COS()

// ------------------- STRUCTURES DE DONNEES --------------------------//

// type matrice reelle de 4x4
typedef float _mat4x4[4][4];

// Structure pour representer un point dans un espace 2D
typedef struct _2D
{
int x,y;
};

// Structure pour representer un point dans un espace 3D
typedef struct _3D
{
float x,y,z;
};

// Structure pour represente un sommet
typedef struct _sommet
{
_3D local; // coordonnees locales
_3D monde; // coordonnees dans le monde
_2D ecran; // coordonnees d'ecran
};

// Structure pour representer une surface quadrilatere
typedef struct _quad
{
short a,b,c,d;
};

// Structure pour contenir un objet
typedef struct _objet
{
int nbsommet; // nombre de sommets
int nbpolygone; // nombre de polygone
_sommet sommet[MAX_SOMM]; // coordonnees des sommets
_quad poly[MAX_POLY]; // polygone
};

typedef struct TScan // Structure pour le remplissage de polygones
{
long gauche,droite;
};


//------------------------- VARIABLES GLOBALES --------------------------//

// Utilise pour initialiser les coordonnes locales d'un objet de type cube
_3D Cube[8] = {
{-1.0, -1.0, -1.0},
{-1.0, 1.0, -1.0},
{ 1.0, 1.0, -1.0},
{ 1.0, -1.0, -1.0},
{-1.0, -1.0, 1.0},
{-1.0, 1.0, 1.0},
{ 1.0, 1.0, 1.0},
{ 1.0, -1.0, 1.0}
};

_quad faces[6] = {
{0,1,2,3},
{7,6,5,4},
{4,5,1,0},
{6,7,3,2},
{3,7,4,0},
{5,6,2,1}
};

char *ecran = (char *) (0xA0000000L); // Memoire video
char *virtuel = new char[64000L]; // Ecran virtuel

float SinTable[360]; // Table Sinus
float CosTable[360]; // Table Cosinus

unsigned int miny,maxy;
TScan scanline[200]; // Largeur des lignes des polys

_mat4x4 m1, m2; // matrices temporaires
_mat4x4 matrice; // mat de transformation homogene

// ------------------------- FONCTIONS --------------------------------//

//----------------------------------------------------------------------//
// hline - Dessine une ligne horizontale //
//----------------------------------------------------------------------//
void hline(int x1, int x2, int y, unsigned char coul)
{
memset(virtuel+x1+(y<<8)+(y<<6),coul,(x2-x1));
}

//----------------------------------------------------------------------//
// Swap - Effectue l'echange entre 2 variables float //
//----------------------------------------------------------------------//
void Swap(float &x,float &y)
{
float temp = x;
x = y;
y = temp;
}

//----------------------------------------------------------------------//
// Scan - Trouve le minX et maxX d'un cote d'un polygone //
//----------------------------------------------------------------------//
void scan(float x1, float y1, float x2, float y2)
{
if (y1==y2) return; // Check pour la div/0
if (y2<y1) {Swap (y1,y2); Swap (x1,x2);} // Dans le bon sens...

double Xinc = (x2-x1) / (y2-y1); // Regression lineaire
double x = x1 += Xinc; // pente m = (dx/dy)
// on saute par dessus le premier
if(y1<miny) miny=y1; // pixel
if(y2>maxy) maxy=y2;

for (int y=y1;y<y2;y++) // On scan la ligne de haut en bas
{
if (x < scanline[y].gauche) scanline[y].gauche = x;
if (x > scanline[y].droite) scanline[y].droite = x;
x+=Xinc;
}
}

//----------------------------------------------------------------------//
// dessinepoly - Dessine un polygone avec liste de points(listesommet) //
//----------------------------------------------------------------------//
void dessine_poly(_2D *listesommet, int nbcotes, unsigned char coul)
{
_2D *ptrcour = ptrcour = listesommet;
_2D *ptrsuiv = ptrsuiv = listesommet+1;

miny=200; maxy=0;
for (int i=0;i<200;i++)
{
scanline[i].gauche = 32000;
scanline[i].droite = -32000;
}
for (i = 1; i < nbcotes; i++)
{
scan(ptrcour->x, ptrcour->y, ptrsuiv->x, ptrsuiv->y);
ptrcour++;
ptrsuiv++;
}
ptrsuiv = listesommet;
scan(ptrcour->x, ptrcour->y, ptrsuiv->x, ptrsuiv->y);
for (int y=miny;y<maxy;y++)
hline(scanline[y].gauche,scanline[y].droite,y,coul);
}

/////////////////////////////////////////////////////////////////////////
// precalc - Calcule le tableau de sinus/cosinus //
/////////////////////////////////////////////////////////////////////////
void precalc()
{
for(int angle=0; angle<360; angle++)
{
SinTable[angle]=sin(angle*M_PI/180.0);
CosTable[angle]=cos(angle*M_PI/180.0);
}
}

/////////////////////////////////////////////////////////////////////////
// copie_matrice - copie une matrice source vers matrice destination //
/////////////////////////////////////////////////////////////////////////
void copie_matrice(_mat4x4 source, _mat4x4 dest)
void copie_matrice(_mat4x4 source, _mat4x4 dest)
{
memcpy(dest,source,sizeof(_mat4x4));
}

/////////////////////////////////////////////////////////////////////////
// mult_matrice - multiplie 2 matrices et mets le resultat dans dest //
/////////////////////////////////////////////////////////////////////////
void mult_matrice(_mat4x4 m1, _mat4x4 m2, _mat4x4 dest)
{
for(short i=0;i<4;i++)
for(short j=0;j<4;j++)
dest[i][j]=
m1[i][0]*m2[0][j]+
m1[i][1]*m2[1][j]+
m1[i][2]*m2[2][j]+
m1[i][3]*m2[3][j];
}


/////////////////////////////////////////////////////////////////////////
// ident_matrice - construit une matrice identite //
/////////////////////////////////////////////////////////////////////////
void ident_matrice(_mat4x4 m)
{
memset(m,NULL,sizeof(_mat4x4));
m[0][0] = 1.0;
m[1][1] = 1.0;
m[2][2] = 1.0;
m[3][3] = 1.0;
}

/////////////////////////////////////////////////////////////////////////
// echelle - matrice de changement d'echelle //
/////////////////////////////////////////////////////////////////////////
void echelle(_mat4x4 m,float ex,float ey, float ez)
{
_mat4x4 emat;

ident_matrice(emat);
emat[0][0]=ex;
emat[1][1]=ey;
emat[2][2]=ez;

mult_matrice(m,emat,m1);
copie_matrice(m1,m);
}

/////////////////////////////////////////////////////////////////////////
// translation - matrice de translation //
/////////////////////////////////////////////////////////////////////////
void translation(_mat4x4 m,float tx,float ty,float tz)
{
_mat4x4 tmat;

ident_matrice(tmat);
tmat[3][0]=tx;
tmat[3][1]=ty;
tmat[3][2]=tz;

mult_matrice(m,tmat,m1);
copie_matrice(m1,m);
}


/////////////////////////////////////////////////////////////////////////
// rotation - matrice de rotation //
/////////////////////////////////////////////////////////////////////////
void rotation(_mat4x4 m,int ax,int ay,int az)
{
_mat4x4 xmat, ymat, zmat;

ident_matrice(xmat);
ident_matrice(ymat);
ident_matrice(zmat);

xmat[1][1] = COS(ax); xmat[1][2] = SIN(ax);
xmat[2][1] = -SIN(ax); xmat[2][2] = COS(ax);

ymat[0][0] = COS(ay); ymat[0][2] = -SIN(ay);
ymat[2][0] = SIN(ay); ymat[2][2] = COS(ay);

zmat[0][0] = COS(az); zmat[0][1] = SIN(az);
zmat[1][0] = -SIN(az); zmat[1][1] = COS(az);

mult_matrice(m,ymat,m1);
mult_matrice(m1,xmat,m2);
mult_matrice(m2,zmat,m);
}

/////////////////////////////////////////////////////////////////////////
// projection - transformation 3D -> 2D //
/////////////////////////////////////////////////////////////////////////
void projection(_sommet *sommet)
{
if(!sommet->monde.z) sommet->monde.z=1;
sommet->ecran.x = MX + sommet->monde.x * (DISTANCE / sommet->monde.z);
sommet->ecran.y = MY + sommet->monde.y * (DISTANCE / sommet->monde.z);
}

/////////////////////////////////////////////////////////////////////////
// transformation - multiplication de chaque sommet par la matrice //
/////////////////////////////////////////////////////////////////////////
void transformation(_objet *object, _mat4x4 m)
{
int v;
_sommet *sommet;

for(v=0; v<object->nbsommet; v++)
{
sommet = &object->sommet[v];

sommet->monde.x = sommet->local.x*m[0][0]+
sommet->local.y*m[1][0]+
sommet->local.z*m[2][0]+
m[3][0];

sommet->monde.y = sommet->local.x*m[0][1]+
sommet->local.y*m[1][1]+
sommet->local.z*m[2][1]+
m[3][1];

sommet->monde.z = sommet->local.x*m[0][2]+
sommet->local.y*m[1][2]+
sommet->local.z*m[2][2]+
m[3][2];
projection(sommet);
}
}

/////////////////////////////////////////////////////////////////////////
// Initialisation des sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void initialise_objet(_objet *objet)
{
objet->nbsommet=8;
objet->nbpolygone=6;
for (int i=0;i<objet->nbsommet;i++)
{
objet->sommet[i].local.x=Cube[i].x;
objet->sommet[i].local.y=Cube[i].y;
objet->sommet[i].local.z=Cube[i].z;
}
for (i=0;i<objet->nbpolygone;i++)
{
objet->poly[i].a = faces[i].a;
objet->poly[i].b = faces[i].b;
objet->poly[i].c = faces[i].c;
objet->poly[i].d = faces[i].d;
}
}

/////////////////////////////////////////////////////////////////////////
// dessine_objet - dessine les sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void dessine_objet(_objet *objet)
{
_2D poly[4];

for (int f=0; f<6; f++)
{
poly[0] = objet->sommet[objet->poly[f].a].ecran;
poly[1] = objet->sommet[objet->poly[f].b].ecran;
poly[2] = objet->sommet[objet->poly[f].c].ecran;
poly[3] = objet->sommet[objet->poly[f].d].ecran;

dessine_poly(poly,4,20+f);
}
}

//------------------------ FONCTION PRINCIPALE --------------------------//


void main(void)
{
int angle=0;
_objet cube;

asm {MOV AX,0x13; INT 0x10}
precalc();
initialise_objet(&cube);

while(!kbhit())
{
memset(virtuel,0,64000L);

ident_matrice(matrice);
echelle(matrice,20,20,20);
rotation(matrice,angle,angle,angle);
translation(matrice,0,0,-100);

transformation(&cube,matrice);
dessine_objet(&cube);

while(!(inp(0x3DA)&8));
memcpy(ecran,virtuel,64000L);
if (angle++ == 359) angle = 0;
};

delete []virtuel;
asm {MOV AX,0x03; INT 0x10}
}

3dchap3c.cpp

  
//////////////////////////////////////////////////////////////////////////
// Code source : Shaun Dore //
// Fichier : 3DCHAP2A.CPP //
// Date : 29-09-1998 //
// Compilateur : Borland C++ 3.1 //
// Description : Rotation 3D //
//////////////////////////////////////////////////////////////////////////

// --------------------------- INCLUDE --------------------------------//

#include <mem.h>
#include <math.h>
#include <conio.h>

// ---------------------- CONSTANTES & MACROS --------------------------//

#define MX 160 // Millieu de l'abscisse
#define MY 100 // Millieu de l'ordonnee
#define DISTANCE 200 // Distances de l'objet
#define MAX_POLY 100 // Nb max de polygones
#define MAX_SOMM 100 // Nb max de sommets
#define SIN(x) SinTable[x] // Macro SIN()
#define COS(x) CosTable[x] // Macro COS()

// ------------------- STRUCTURES DE DONNEES --------------------------//

// type matrice reelle de 4x4
typedef float _mat4x4[4][4];

// Structure pour representer un point dans un espace 2D
typedef struct _2D
{
int x,y;
};

// Structure pour representer un point dans un espace 3D
typedef struct _3D
{
float x,y,z;
};

// Structure pour represente un sommet
typedef struct _sommet
{
_3D local; // coordonnees locales
_3D monde; // coordonnees dans le monde
_2D ecran; // coordonnees d'ecran
};

// Structure pour representer une surface quadrilatere
typedef struct _quad
{
short a,b,c,d;
};

// Structure pour contenir un objet
typedef struct _objet
{
int nbsommet; // nombre de sommets
int nbpolygone; // nombre de polygone
_sommet sommet[MAX_SOMM]; // coordonnees des sommets
_quad poly[MAX_POLY]; // polygone
};

typedef struct TScan // Structure pour le remplissage de polygones
{
long gauche,droite;
};


//------------------------- VARIABLES GLOBALES --------------------------//

// Utilise pour initialiser les coordonnes locales d'un objet de type cube
_3D Cube[8] = {
{-1.0, -1.0, -1.0},
{-1.0, 1.0, -1.0},
{ 1.0, 1.0, -1.0},
{ 1.0, -1.0, -1.0},
{-1.0, -1.0, 1.0},
{-1.0, 1.0, 1.0},
{ 1.0, 1.0, 1.0},
{ 1.0, -1.0, 1.0}
};

_quad faces[6] = {
{0,1,2,3},
{7,6,5,4},
{4,5,1,0},
{6,7,3,2},
{3,7,4,0},
{5,6,2,1}
};

float SinTable[360]; // Table Sinus
float CosTable[360]; // Table Cosinus
_mat4x4 matrice; // mat de transformation homogene
_mat4x4 mat1, mat2; // matrices temporaires
TScan scanline[200]; // Largeur des lignes des polys
char *ecran = (char *) (0xA0000000L); // Memoire video
char *virtuel = new char[64000L]; // Ecran virtuel
unsigned int miny,maxy;

// ------------------------- FONCTIONS --------------------------------//

//----------------------------------------------------------------------//
// hline - Dessine une ligne horizontale //
//----------------------------------------------------------------------//
void hline(int x1, int x2, int y, unsigned char coul)
{
memset(virtuel+x1+(y<<8)+(y<<6),coul,(x2-x1));
}

//----------------------------------------------------------------------//
// Swap - Effectue l'echange entre 2 variables float //
//----------------------------------------------------------------------//
void Swap(float &x,float &y)
{
float temp = x;
x = y;
y = temp;
}

//----------------------------------------------------------------------//
// Scan - Trouve le minX et maxX d'un cote d'un polygone //
//----------------------------------------------------------------------//
void scan(float x1, float y1, float x2, float y2)
{
if (y1==y2) return; // Check pour la div/0
if (y2<y1) {Swap (y1,y2); Swap (x1,x2);} // Dans le bon sens...

double Xinc = (x2-x1) / (y2-y1); // Regression lineaire
double x = x1 += Xinc; // pente m = (dx/dy)
// on saute par dessus le premier
if(y1<miny) miny=y1; // pixel
if(y2>maxy) maxy=y2;

for (int y=y1;y<y2;y++) // On scan la ligne de haut en bas
{
if (x < scanline[y].gauche) scanline[y].gauche = x;
if (x > scanline[y].droite) scanline[y].droite = x;
x+=Xinc;
}
}

//----------------------------------------------------------------------//
// dessinepoly - Dessine un polygone avec liste de points(listesommet) //
//----------------------------------------------------------------------//
void dessine_poly(_2D *listesommet, int nbcotes, unsigned char coul)
{
_2D *ptrcour = listesommet;
_2D *ptrsuiv = listesommet+1;

miny=200; maxy=0;
for (int i=0;i<200;i++)
{
scanline[i].gauche = 32000;
scanline[i].droite = -32000;
}
for (i = 1; i < nbcotes; i++)
{
scan(ptrcour->x, ptrcour->y, ptrsuiv->x, ptrsuiv->y);
ptrcour++;
ptrsuiv++;
}
ptrsuiv = listesommet;
scan(ptrcour->x, ptrcour->y, ptrsuiv->x, ptrsuiv->y);
for (int y=miny;y<maxy;y++)
hline(scanline[y].gauche,scanline[y].droite,y,coul);
}

/////////////////////////////////////////////////////////////////////////
// precalc - Calcule le tableau de sinus/cosinus //
/////////////////////////////////////////////////////////////////////////
void precalc()
{
for(int angle=0; angle<360; angle++)
{
SinTable[angle]=sin(angle*M_PI/180.0);
CosTable[angle]=cos(angle*M_PI/180.0);
}
}

/////////////////////////////////////////////////////////////////////////
// copie_matrice - copie une matrice source vers matrice destination //
/////////////////////////////////////////////////////////////////////////
void copie_matrice(_mat4x4 source, _mat4x4 dest)
{
memcpy(dest,source,sizeof(_mat4x4));
}

/////////////////////////////////////////////////////////////////////////
// mult_matrice - multiplie 2 matrices et mets le resultat dans dest //
/////////////////////////////////////////////////////////////////////////
void mult_matrice(_mat4x4 m1, _mat4x4 m2, _mat4x4 dest)
{
for(short i=0;i<4;i++)
for(short j=0;j<4;j++)
dest[i][j]=
m1[i][0]*m2[0][j]+
m1[i][1]*m2[1][j]+
m1[i][2]*m2[2][j]+
m1[i][3]*m2[3][j];
}

/////////////////////////////////////////////////////////////////////////
// ident_matrice - construit une matrice identite //
/////////////////////////////////////////////////////////////////////////
void ident_matrice(_mat4x4 m)
{
memset(m,NULL,sizeof(_mat4x4));
m[0][0] = 1.0;
m[1][1] = 1.0;
m[2][2] = 1.0;
m[3][3] = 1.0;
}

/////////////////////////////////////////////////////////////////////////
// echelle - matrice de changement d'echelle //
/////////////////////////////////////////////////////////////////////////
void echelle(_mat4x4 m,float ex,float ey, float ez)
{
_mat4x4 emat;

ident_matrice(emat);
emat[0][0]=ex;
emat[1][1]=ey;
emat[2][2]=ez;

mult_matrice(m,emat,mat1);
copie_matrice(mat1,m);
}

/////////////////////////////////////////////////////////////////////////
// translation - matrice de translation //
/////////////////////////////////////////////////////////////////////////
void translation(_mat4x4 m,float tx,float ty,float tz)
{
_mat4x4 tmat;

ident_matrice(tmat);
tmat[3][0]=tx;
tmat[3][1]=ty;
tmat[3][2]=tz;

mult_matrice(m,tmat,mat1);
copie_matrice(mat1,m);
}


/////////////////////////////////////////////////////////////////////////
// rotation - matrice de rotation //
/////////////////////////////////////////////////////////////////////////
void rotation(_mat4x4 m,int ax,int ay,int az)
{
_mat4x4 xmat, ymat, zmat;

ident_matrice(xmat);
ident_matrice(ymat);
ident_matrice(zmat);

xmat[1][1] = COS(ax); xmat[1][2] = SIN(ax);
xmat[2][1] = -SIN(ax); xmat[2][2] = COS(ax);

ymat[0][0] = COS(ay); ymat[0][2] = -SIN(ay);
ymat[2][0] = SIN(ay); ymat[2][2] = COS(ay);

zmat[0][0] = COS(az); zmat[0][1] = SIN(az);
zmat[1][0] = -SIN(az); zmat[1][1] = COS(az);

mult_matrice(m,ymat,mat1);
mult_matrice(mat1,xmat,mat2);
mult_matrice(mat2,zmat,m);
}

/////////////////////////////////////////////////////////////////////////
// projection - transformation 3D -> 2D //
/////////////////////////////////////////////////////////////////////////
void projection(_sommet *sommet)
{
if(!sommet->monde.z) sommet->monde.z=1;
sommet->ecran.x = MX + sommet->monde.x * (DISTANCE / sommet->monde.z);
sommet->ecran.y = MY + sommet->monde.y * (DISTANCE / sommet->monde.z);
}

/////////////////////////////////////////////////////////////////////////
// transformation - multiplication de chaque sommet par la matrice //
/////////////////////////////////////////////////////////////////////////
void transformation(_objet *object, _mat4x4 m)
{
int v;
_sommet *sommet;

for(v=0; v<object->nbsommet; v++)
{
sommet = &object->sommet[v];

sommet->monde.x = sommet->local.x*m[0][0]+
sommet->local.y*m[1][0]+
sommet->local.z*m[2][0]+
m[3][0];

sommet->monde.y = sommet->local.x*m[0][1]+
sommet->local.y*m[1][1]+
sommet->local.z*m[2][1]+
m[3][1];

sommet->monde.z = sommet->local.x*m[0][2]+
sommet->local.y*m[1][2]+
sommet->local.z*m[2][2]+
m[3][2];
projection(sommet);
}
}

/////////////////////////////////////////////////////////////////////////
// Initialisation des sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void initialise_objet(_objet *objet)
{
objet->nbsommet=8;
objet->nbpolygone=6;
for (int i=0;i<objet->nbsommet;i++)
{
objet->sommet[i].local.x=Cube[i].x;
objet->sommet[i].local.y=Cube[i].y;
objet->sommet[i].local.z=Cube[i].z;
}
for (i=0;i<objet->nbpolygone;i++)
{
objet->poly[i].a = faces[i].a;
objet->poly[i].b = faces[i].b;
objet->poly[i].c = faces[i].c;
objet->poly[i].d = faces[i].d;
}
}

/////////////////////////////////////////////////////////////////////////
// dessine_objet - dessine les sommets de l'objet //
/////////////////////////////////////////////////////////////////////////
void dessine_objet(_objet *objet)
{
_2D poly[4];
int normal;

for (int f=0; f<6; f++)
{
poly[0] = objet->sommet[objet->poly[f].a].ecran;
poly[1] = objet->sommet[objet->poly[f].b].ecran;
poly[2] = objet->sommet[objet->poly[f].c].ecran;
poly[3] = objet->sommet[objet->poly[f].d].ecran;

normal = (poly[0].y - poly[2].y) *
(poly[1].x - poly[0].x) -
(poly[0].x - poly[2].x) *
(poly[1].y - poly[0].y);

if (normal<0) dessine_poly(poly,4,21+f);
}
}

//------------------------ FONCTION PRINCIPALE --------------------------//


void main(void)
{
int angle=0;
_objet cube;

asm {MOV AX,0x13; INT 0x10}
precalc();
initialise_objet(&cube);

while(!kbhit())
{
memset(virtuel,0,64000L);

ident_matrice(matrice);
echelle(matrice,20,20,20);
rotation(matrice,angle,angle,angle);
translation(matrice,0,0,-100);

transformation(&cube,matrice);
dessine_objet(&cube);
while(!(inp(0x3DA)&8));
memcpy(ecran,virtuel,64000L);
if (angle++ == 359) angle = 0;
};

delete []virtuel;
asm {MOV AX,0x03; INT 0x10}
}

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT