|
Textures |
Programmation 3D
Chapitre V
Les
textures
Il est bien beau de dessiner des objets avec une
couleur pleine mais il serai bien de pouvoir y ajouter un dessin (une
texture).
Nous avons vue dans les chapitres précédant
comment modéliser des objets en 3 dimension, mais aussi
comment alléger le remplissage graphique avec la méthode
de la normale aux surfaces, ainsi que l'algorithme du peintre.
Nous
pouvons donc considéré que nous avons délimité
un triangle a dessiner.
Découpage 2D et projection
linéaire en 3D :
|
Texture a appliquer |
Triangle a projeter |
Découpage de la texture |
Projection Bi-linaire |
|
|
|
|
|
Ci vous avez suivis le cour jusque là, le decoupage de la
texture en 2D ne seras alors qu'une simple formalité.
Il
sufit de rajouter pour chaque sommet les cordonnées en 2D de
sa position sur la texture.
typedef struct str_triangle
{
int a,b,c; /* Numéro de point */
_2D PointTexture[3]; /* Coordonnée des point sur la texture */
}TRIANGLE;
|
|
Et maintenant la projection linéaire. Lorsque nous avons déterminé la projection des sommets dans le plan 2D de l'écran, on utiliser la fonction pour dessiner les polygones en y ajoutant quelque modification. |
#define MIN(a,b) ( a < b ? a : b )
#define MAX(a,b) ( a > b ? a : b )
#define ABS(a) ( a < 0 ? -a : a )
#define Swap(a,b) {int temp; temp=a; a=b; b=temp; }
int MinY,MaxY;
static struct str_scan
{
/* Coordonnée de la projection vertical */
int gauche,droite;
/* Coordonnée relative de la texture a gauche */
float PGXtexture,PGYtexture;
/* Coordonnée relative de la texture a droite */
float PDXtexture,PDYtexture;
}scan[800];
/*
Projection du triangle en ligne horizontal avec,
(x1,y1) et (x2,y2) les coordonnées du coté a traiter,
(rx1,ry1) et (rx2,ry2) leur coordonnées plan sur la texture.
*/
void ScanLine(int x1,int y1,int x2,int y2,int rx1,int ry1,int rx2,int ry2)
{
double pente,PosX;
int PosY;
double prtx,PosRTX;
double prty,PosRTY;
/* On force y1<= y2 */
if(y1>y2)
{
Swap(x1,x2);
Swap(y1,y2);
Swap(rx1,rx2);
Swap(ry1,ry2);
}
/* On teste si le triangle apparaît à l'écran */
if(y2<0 || y1>ResY)
return;
/*
Ceci est un cas à traiter a part car plus bas
on divise par la différence de y1 et y2
*/
if(y1==y2)
{
if(x1>x2)
{
scan[y1].droite = x1;
scan[y1].PDXtexture=rx1;
scan[y1].PDYtexture=ry1;
scan[y1].gauche = x2;
scan[y1].PGXtexture=rx2;
scan[y1].PGYtexture=ry2;
}
else
{
scan[y1].gauche = x1;
scan[y1].PGXtexture=rx1;
scan[y1].PGYtexture=ry1;
scan[y1].droite = x2;
scan[y1].PDXtexture=rx2;
scan[y1].PDYtexture=ry2;
}
return;
}
/* On calcule la pente réel de notre droite */
pente = (float)(x1-x2) / (float)(y1-y2);
/* Puis la pente relative a la texture de notre droite */
prtx = (float)(rx1-rx2) / (float)(y1-y2);
prty = (float)(ry1-ry2) / (float)(y1-y2);
PosX=x1;
PosY=y1;
PosRTX=rx1;
PosRTY=ry1;
/* On rabat y2 afin d'éviter un dépassement d'espace mémoire */
y2=MIN(y2,ResY);
/* Puis on rabat PosY afin d'éviter le même problèmes */
while(PosY<0)
{
PosX+=pente;
PosY++;
PosRTX+=prtx;
PosRTY+=prty;
}
/* On sauvegarde la position la plus haute et la position la plus bas */
MinY=MIN(PosY,MinY);
MaxY=MAX(y2,MaxY);
/* On projette linéairement la droite */
while(PosY<=y2)
{
if(scan[PosY].gauche>PosX)
{
scan[PosY].gauche=PosX;
scan[PosY].PGXtexture=PosRTX;
scan[PosY].PGYtexture=PosRTY;
}
if(scan[PosY].droite<PosX)
{
scan[PosY].droite=PosX;
scan[PosY].PDXtexture=PosRTX;
scan[PosY].PDYtexture=PosRTY;
}
PosX+=pente;
PosY++;
PosRTX+=prtx;
PosRTY+=prty;
}
}
/*
Texture représente l'image a appliquer, mais si je n'ai pas
déclaré le type IMAGE, c'est par-ce qu'il dépend directement
du mode de stockage des textures que vous aurais choisi.
Vous pourrez facilement vous aider avec la librairie SDL.
*/
void DrawPoly(_2D Point[],_2D PointTexture,IMAGE Texture)
{
int i;
COULEUR dc={0,0,0};
/* On initialise les variables */
MinY=ResY;
MaxY=0;
for(i=0;i<=ResY;i++)
{
scan[i].droite=0; scan[i].gauche=799;
}
/* Premiere projection linéaire */
ScanLine(Point[0].x,Point[0].y,
Point[1].x,Point[1].y,
PointTexture[0].x,PointTexture[0].y);
PointTexture[1].x,PointTexture[1].y);
ScanLine(Point[1].x,Point[1].y,
Point[2].x,Point[2].y,
PointTexture[1].x,PointTexture[1].y);
PointTexture[2].x,PointTexture[2].y);
ScanLine(Point[2].x,Point[2].y,
Point[0].x,Point[0].y,
PointTexture[2].x,PointTexture[2].y);
PointTexture[0].x,PointTexture[0].y);
if(MinY!=ResY)
for(i=MinY;i<=MaxY;i++)
DrawLinear2(i,Texture);
}
|
|
Il ne nous reste plus cas écrire la fonction
DrawLinear2() et le tour est jouer. |
void DrawLinear2(int ligne,IMAGE Texture)
{
int X;
double PosTX,PenteX;
double PosTY,PenteY;
PenteX=(double)(scan[ligne].PDXtexture-scan[ligne].PGXtexture)/
(double)(scan[ligne].droite-scan[ligne].gauche);
PenteY=(double)(scan[ligne].PDYtexture-scan[ligne].PGYtexture)/
(double)(scan[ligne].droite-scan[ligne].gauche);
PosTX=scan[ligne].PGXtexture;
PosTY=scan[ligne].PGXtexture;
X=scan[ligne].gauche;
if(scan[ligne].droite>ResX)
scan[ligne].droite=ResX;
while(X<0)
{
X++;
PosTX+=PenteX;
PosTY+=PenteY;
}
while(X<=scan[ligne].droite)
{
On dessine le point de coordonnées (PosTX,PosTY) de la texture, au coordonnées (X,ligne) de l'écran.
Cette méthode n'est pas la meilleur mais elle gagne en rapidité.
Toute fois, avec des méthode plus complexe, on obtient pas toujours mieux.
X++;
PosTX+=PenteX;
PosTY+=PenteY;
}
}
|
|
Pour dessiner il existe plusieurs méthodes dont 3
grandes : |
|
Astuce
|