You are on page 1of 21

Transformaciones 3D

El hecho de querer incursionar en el modelado 3D parece como si fuera realmente


complicado aunque realmente es sencillo y se requiere poco esfuerzo.
Utilizo el compilador BorlandC++ 3.1 y las librerias BGI, las limitaciones son la cantidad
de vertices y poligonos que puede tener el modelo, ya que se trata de un compilador de 16
Bits y estoy limitado por los 64K de datos que se puede utilizar ya que no utilizo asignacion
dinamica de memoria, por no complicar el código.
La imagen de abajo se realizó con el programa presentado aqui, se trata de un toro
compuesto por 512 vertices y 1024 poligonos.

Para la visualización de un objeto 3D, se requieren 3 pasos:

 En primer lugar se necesita una base de datos o un arreglo con las coordenadas
(x,y,z) de los vértices y ademas los polígonos que forman el objeto.
 En segundo lugar el objeto primero se rota y luego se traslada hasta la localización
adecuada, con lo que se obtienen unas nuevas coordenadas (x,y,z) para los vértices.
 Finalmente, se eliminan los polígonos que no son visibles por el observador, se
aplica la perspectiva y se dibuja el objeto en la pantalla.

Base de Datos del Objeto 3D

Mi objeto esta compuesto por polígonos de tres lados, y cada poligono tiene 3 vértices
cuyas coordenadas son (x,y,z).

Número máximo de vértices que puede tener el objeto


#define NUM_VERTICES
Cantidad máxima de polígonos que tiene el objeto
#define NUM_FACES
Definición de un vértice
typedef struct VTX
{
double x, y, z;
};

Definición de un polígono
typedef struct TRI
{
int a, b, c;
};

Estructura para el ordenamiento qsort, donde para cada polígono


almaceno la cordenada z y el indice del polígono
d=coordenada z del poligono, index=indice del poligono
typedef struct LSTRI
{
int d;
int index;
};

Tabla que contiene los vértices originales


VTX points[NUM_VERTICES];
Tabla con los vértices transformados
VTX outpoints[NUM_VERTICES];
Tabla que contiene los polígonos
TRI faces[NUM_FACES];
Tabla de polígonos para aplicar el ordenamiento qsort
LSTRI ListFaces[NUM_FACES];
Número de vértices, y polígonos del objeto
int vertices, poligonos;
Vértices del objeto
V0 = points[0].x, points[0].y, points[0].z
V1 = points[1].x, points[1].y, points[1].z
.. .... .... ....
V7 = points[7].x, points[7].y, points[7].z

Polígonos del objeto


faces[0].a = 0 faces[0].b = 2 faces[0].c = 1
faces[1].a = 2 faces[1].b = 3 faces[1].c = 1
.... .... ....
faces[5].a = 6 faces[5].b = 7 faces[5].c = 5

Matrices de Transformación 3D

Sistema de Coordenadas El sistema de coordenadas


tridimensional utilizado es el
llamado de la mano
izquierda

Matriz Identidad

La matriz identidad se representa como matriz_identidad :

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

Escalado

El escalado consiste en multiplicar las coordenadas del objeto por una constante, para
modificar su tamaño. Se describe el escalamiento cuando el punto fijo es el origen. Para
obtener un escalamiento con un punto fijo arbitrario, este se debe trasladar al origen, escalar
el objeto, y despues realizar el inverso de la traslacion original.
La matriz de escalamiento con factores de escala Ex, Ey, Ez en las direcciones x, y, z
respectivamente, esta dada por la matriz Es(Ex, Ey, Ez) :

Ex 0 0 0
0 Ey 0 0
0 0 Ez 0
0 0 0 1

La inversa de un escalamiento se obtiene usando los reciprocos de los factores de escala :


1/Ex, 1/Ey, 1/Ez.

Rotación en torno al eje X

La rotación de un angulo a sobre el eje x se representa por medio de la matriz Rx(a) :

1 0 0 0
0 cos(a) sin(a) 0
0 -sin(a) cos(a) 0
0 0 0 1

Código en C

void matriz_rotacion_x(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[1][1] = tmpcos;
m->v[1][2] = tmpsin;
m->v[2][1] = -tmpsin;
m->v[2][2] = tmpcos;
}

Ejemplo: matriz_rotacion_x(&Rx, 0.7)


Esto crea la matriz de rotación alrededor del eje X, donde Rx es una matriz 4x4 y 0.7 es el
angulo de rotación, en radianes.

Rotación en torno al eje Y

La rotación de un punto alrededor del eje Y se realiza en un plano paralelo al plano x, z. El


valor de la coordenada Y no cambia. La matriz de rotacion es Ry(a) :

cos(a) 0 -sin(a) 0
0 1 0 0
sin(a) 0 cos(a) 0
0 0 0 1

Código en C.

void matriz_rotacion_y(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[0][0] = tmpcos;
m->v[0][2] = -tmpsin;
m->v[2][0] = tmpsin;
m->v[2][2] = tmpcos;
}
Ejemplo : matriz_rotacion_y(&Ry, 0.7)
donde Ry es la matriz de rotación 4x4, y 0.7 es el angulo de rotacióon.

Rotación en torno al eje Z

La rotación de un angulo a sobre el eje Z se representa por medio de la matriz Rz(a) :

cos(a) sin(a) 0 0
-sin(a) cos(a) 0 0
0 0 1 0
0 0 0 1

Código en C

void matriz_rotacion_z(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[0][0] = tmpcos;
m->v[0][1] = tmpsin;
m->v[1][0] = -tmpsin;
m->v[1][1] = tmpcos;
}

Ejemplo : matriz_rotacion_z(&Rz, 0.7)


donde Rz es la matriz de 4x4, y 0.7 es el angulo de rotación en torno al eje Z.
Traslación

La matriz asociada a la traslación es la siguiente Tr(Tx, Ty, Tz) :

1 0 0 0
0 1 0 0
0 0 1 0
Tx Ty Tz 1

Código en C

void matriz_traslacion(MATRIZ *m, double Tx, double Ty, double Tz)


{
*m = matriz_identidad;
m->v[3][0] = Tx;
m->v[3][1] = Ty;
m->v[3][2] = Tz;
}

Ejemplo : matriz_traslacion(&Tr, 0.0, 0.0, -350.0)


donde Tr es la matriz de traslación 4x4, y -100.0 es el desplazamiento en el eje Z.
La matriz de traslación inversa se obtiene invirtiendo el signo de los valores de Tx, Ty, Tz.
Es decir Tr(-Tx,-Ty,-Tz)

Importante

Hay que tener en cuenta que no es lo mismo rotar y luego trasladar, que trasladar y luego
rotar: Si se rota el objeto y luego se traslada, aparecerá el objeto (rotado sobre si mismo) en
el punto correspondiente a la traslación, en cambio, si primero se traslada y luego se rota, se
obtiene algo totalmente distinto, pues el objeto no rota sobre si mismo, sino que lo hace
respecto al origen de coordenadas de la escena. Esto es debido a que el eje sobre el que se
realiza la rotación pasa por el origen de coordenadas, que será el origen relativo del objeto
o el global de las escena. Si se traslada el objeto, el origen de coordenadas correspondera a
un punto distinto del objeto.

Construcción de la matriz de Transformación

Todo esta listo para construir la matriz de transformación, para ello utilizo las matrices Rx,
Ry, Rz y Tr :
void matriz_multiplicacion(MATRIZ *m1, MATRIZ *m2, MATRIZ *out)
que efectua el producto de dos matrices m1, m2, de 4x4 y almacena el resultado en una
matriz out de 4x4.

temp = Rx x Ry
matriz_multiplicacion(&Rx, &Ry, &temp)
Rot = temp x Rz
matriz_multiplicacion(&temp, &Rz, &Rot)
Mat = Rot x Tr
matriz_multiplicacion(&Rot, &Tr, &Mat)

donde temp, Rot y Mat son matrices de 4x4, Mat es la matriz de transformación.

Proyección en Perspectiva

Una vez construida la matriz de transformación Mat, tenemos que aplicarla a todos los
vertices del objeto, utilizamos para ello :
aplicar_matriz(&Mat, points[i].x, points[i].y, points[i].z, &outpoints[i].x,
&outpoints[i].y, &outpoints[i].z)
me multiplica cada uno de los vertices del objeto (points[]) por la matriz de transformación
Mat, el resultado es el vertice transformado (outpoints[]).

Proyección en Perspectiva

Esta proyección es una transformación que convierte una representación tridimencional en


bidimencional, para poder representarla en la pantalla, D es la distancia entre el plano de
proyeccion (pantalla) y el obeservador, con valores pequenos la imagen se distorciona, con
D=800, anda todo bien, persp_xoffset, persp_yoffset son las coordenadas del centro de la
pantalla, por ejemplo si trabajo en el modo 640x480, persp_xoffset=320
persp_yoffset=240.

void persp_projeccion(double x, double y, double z, double *xout, double *yout)


{
double z1 = 1.0 / z;
*xout = ((x * z1) * D) + persp_xoffset;
*yout = ((y * z1) * D) + persp_yoffset;
}

Ejemplo : persp_projeccion(outpoints[i].x, outpoints[i].y, outpoints[i].z,


&outpoints[i].x, &outpoints[i].y)

La salida son puntos que se pueden representar en la pantalla.

Determinación de las caras visibles del objeto

Primero realizó una clasificación por profundidad para cada polígono utilizando qsort,
ordenación rapida, y usando las coordenadas z. Luego para cada uno de estos polígonos uso
el algoritmo de Backface-Culling para determinar si es visible o no por el observador.
Backface-Culling de poligonos

Para determinar que polígonos son visibles desde el punto de vista del observador debemos
realizar los siguientes pasos :

 A partir de los 3 vertices del poligono (V1, V2, V3)se calcula el (vector normal) al
poligono (mediante el producto vectorial).
 Calcular el producto escalar de dicho vector con el vector que va desde el centro del
poligono hasta el punto de observacion (Vector de la vista del poligono) el cual es
un vector untitario.
 Si el producto escalar es positivo, el angulo entre dichos vectores es inferior a 90
grados, luego la superficie es visible.

double Hidden(VTX v1, VTX v2, VTX v3)


{
VTX u, v;
VTX out;
double xout, yout, zout;
double temp;

u.x = v2.x - v1.x;


u.y = v2.y - v1.y;
u.z = v2.z - v1.z;

v.x = v3.x - v1.x;


v.y = v3.y - v1.y;
v.z = v3.z - v1.z;

producto_vectorial(u, v, &out);
temp = producto_escalar(out.x, out.y, out.z, 0.0, 0.0, -1.0);
return temp;
}
Solo funciona bien si el modelo consiste en un unico solido convexo (esfera), pues si hay
mas de un solido, o si este no es convexo (toro), un poligono puede tapar parcialmente a
otro poligono (ambos visibles), por lo que es necesario utilizar otro metodo
complementario.

Clasificacion por profundidad de los poligonos

Consiste en trazar primero los poligonos situados más lejos. Para ello se ordenan los
poligonos en función de su profundidad media, utilizo para ello el metodo de ordenacion
rapida qsort.
No siempre funciona bien, porque no siempre todos los vertices de un poligono estan mas
cerca o mas lejos que todos los vertices de otro poligono. Aunque es inexacto
(especialmente en poligono de gran tamaño).

Iluminación

Este efecto se logra pintando los poligonos con diferentes tonos de grises, para ello utilizo
el vector normal al poligono, el cual tiene que ser normalizado, es decir dividir el vector por
su modulo, para que sea unitario,y el vector de componentes xlight, ylight, zlight que son
las coordenadas de la fuente de luz, este vector tambien tiene que ser normalizado, realizo
el producto_escalar entre ambos vectores el valor que me da como resultado me indica la
cantidad de luz que recibe cada poligono, 0.0 intensidad minima y 1.0 maxima
intensidad.
Utilizo una paleta de 256 colores, en este caso son niveles de grises 64 en total, como el
nivel de luz varia entre 0.0 y 1.0, lo escalo multiplicandolo por 256.0, que es la cantidad de
colores que tiene mi paleta.
La siguiente funcion me calcula el nivel de luz, que recibe un poligono.

int Light(VTX v1, VTX v2, VTX v3)


{
VTX u, v, out;
double temp;

u.x = v2.x - v1.x;


u.y = v2.y - v1.y;
u.z = v2.z - v1.z;
v.x = v3.x - v1.x;
v.y = v3.y - v1.y;
v.z = v3.z - v1.z;
//out es el vector normal al poligono
producto_vectorial(u, v, &out);
vector_normalizado(&out.x, &out.y, &out.z);
vector_normalizado(&xlight, &ylight, &zlight);
//El resultado de todas estas operaciones dar un valor comprendido
//entre 0.0 (m¡nima luz) y 1.0f (m xima luz)
temp = producto_escalar(out.x, out.y, out.z, xlight, ylight, zlight);
temp = 256.0*temp;
if (temp<0.0)
temp=0.0;
else
if (temp>255.0)
temp=255.0;
return (int) (temp);
}

Implementación en C

Se define el objeto a visualizar en un archivo de texto (toro.dat), el cual es leido desde el


programa, esta compuesto por 512 vertices y 1024 poligonos de tres vertices. La
representación es en modo Flat Shading.
Utilizo las librerias BGI de BorlandC++3.1, con el comando fillpoly() dibujo los
poligonos.

Estructura del archivo de texto toro.dat que contiene los datos del objeto.

512 (es el número de vértices que tiene el objeto)


-0.000003 75.000000 0.000000 (coordenadas de los vertices)
-0.000003 73.096985 9.567086
-0.000003 67.677666 17.677670
.......... .......... .........
1024 (es el numero de poligonos del objeto)
0 17 16 (indice de los vertices que forman cada poligono)
0 1 17
1 18 17

. . .....

Imagen generada por el programa, utilizando una paleta de 64 tonos de grises.


Código Fuente
/*
* Ejemplo de transformaciones 3D utilzando matrices 4x4
*
* Este programa carga la geometria del objeto, es decir
* las coordenadas de los vertices, y las caras desde una
* archivo de texto (toro.dat), y le aplica las transformaciones
* necesarias para lograr una proyeccion en perspectiva, para
* ello utiliza matrices 4x4.
* La representacion es en modo flat, son eliminadas las caras
* que no son visbles.
*
* El codigo no esta optimizdo, ya que la finalidad de este
* programa es mostrar el uso de las matrices de transformacion.
* Fue compilado con BorlandC++3.1, utiliza las librerias BGI
*
* www.geocities.com/valcoey/index.html
* valcoey@hotmail.com
* Ramiro Alcocer
* 12/01/2001
*/

#include <graphics.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include "svga256.h"

#define NUM_VERTICES 512


#define NUM_FACES 1024

typedef struct MATRIZ


{
double v[4][4];
};

typedef struct VTX


{
double x, y, z;
};

typedef struct TRI


{
int a, b, c;
};

typedef struct LSTRI


{
int d;
int index;
};

VTX points[NUM_VERTICES];
VTX outpoints[NUM_VERTICES];
TRI faces[NUM_FACES];
LSTRI ListFaces[NUM_FACES];
int vertices, poligonos;
//posicion de la fuente de luz
double xlight=1.0, ylight=-1.0, zlight=1.0;
unsigned char paleta[256][3];

MATRIZ matriz_identidad = {
{
{ 1.0, 0.0, 0.0, 0.0},
{ 0.0, 1.0, 0.0, 0.0},
{ 0.0, 0.0, 1.0, 0.0},
{ 0.0, 0.0, 0.0, 1.0}
}
};

double persp_xoffset;
double persp_yoffset;
double D;

int huge deteccion()


{
int modo;

clrscr();
printf("Selecciona un modo de video...\n");
printf(" 0) 320x200x256 VGA\n");
printf(" 1) 640x400x256 SVGA\n");
printf(" 2) 640x480x256 SVGA\n");
printf(" 3) 800x600x256 SVGA\n");
printf(" 4) 1024x768x256 SVGA\n\n>");
scanf("%d", &modo);
return modo;
}

void aplicar_matriz(MATRIZ *m, double x, double y, double z, double *xout, double


*yout, double *zout)
{
*xout = x*m->v[0][0] + y*m->v[1][0] + z*m->v[2][0] + 1.0*m->v[3][0];
*yout = x*m->v[0][1] + y*m->v[1][1] + z*m->v[2][1] + 1.0*m->v[3][1];
*zout = x*m->v[0][2] + y*m->v[1][2] + z*m->v[2][2] + 1.0*m->v[3][2];
}

void matriz_multiplicacion(MATRIZ *m1, MATRIZ *m2, MATRIZ *out)


{
int i, j, k;

for (i=0; i<4; i++) {


for (j=0; j<4; j++) {
out->v[i][j] = 0.0;
for (k=0; k<4; k++)
out->v[i][j] = out->v[i][j] + m1->v[i][k]*m2->v[k][j];
}
}
}

void matriz_traslacion(MATRIZ *m, double Tx, double Ty, double Tz)


{
*m = matriz_identidad;
m->v[3][0] = Tx;
m->v[3][1] = Ty;
m->v[3][2] = Tz;
}

void matriz_escalamiento(MATRIZ *m, double Ex, double Ey, double Ez)


{
*m = matriz_identidad;
m->v[0][0] = Ex;
m->v[1][1] = Ey;
m->v[2][2] = Ez;
}

void matriz_rotacion_x(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[1][1] = tmpcos;
m->v[1][2] = tmpsin;
m->v[2][1] = -tmpsin;
m->v[2][2] = tmpcos;
}

void matriz_rotacion_y(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[0][0] = tmpcos;
m->v[0][2] = -tmpsin;
m->v[2][0] = tmpsin;
m->v[2][2] = tmpcos;
}

void matriz_rotacion_z(MATRIZ *m, double angulo)


{
double tmpsin, tmpcos;

tmpsin=sin(angulo);
tmpcos=cos(angulo);
*m = matriz_identidad;
m->v[0][0] = tmpcos;
m->v[0][1] = tmpsin;
m->v[1][0] = -tmpsin;
m->v[1][1] = tmpcos;
}

void persp_projeccion(double x, double y, double z, double *xout, double *yout)


{
double z1 = 1.0 / z;
*xout = ((x * z1) * D) + persp_xoffset;
*yout = ((y * z1) * D) + persp_yoffset;
}

void set_projeccion_viewport(int w, int h)


{
D = 800;
persp_xoffset = w/2;
persp_yoffset = h/2;
}

void ver_matriz(MATRIZ *m)


{
printf("%lf %lf %lf %lf\n", m->v[0][0], m->v[0][1], m->v[0][2], m->v[0][3]);
printf("%lf %lf %lf %lf\n", m->v[1][0], m->v[1][1], m->v[1][2], m->v[1][3]);
printf("%lf %lf %lf %lf\n", m->v[2][0], m->v[2][1], m->v[2][2], m->v[2][3]);
printf("%lf %lf %lf %lf\n", m->v[3][0], m->v[3][1], m->v[3][2], m->v[3][3]);
}

double producto_escalar(double x1, double y1, double z1, double x2, double y2, double z2)
{
return ((x1 * x2) + (y1 * y2) + (z1 * z2));
}

void producto_vectorial(VTX v1, VTX v2, VTX *out)


{
out->x = (v1.y * v2.z) - (v1.z * v2.y);
out->y = (v1.z * v2.x) - (v1.x * v2.z);
out->z = (v1.x * v2.y) - (v1.y * v2.x);
}

double modulo_vector(double x, double y, double z)


{
return sqrt(x*x + y*y + z*z);
}

void vector_normalizado(double *x, double *y, double *z)


{
double length = 1.0 / modulo_vector(*x, *y, *z);

*x *= length;
*y *= length;
*z *= length;
}

//Esta funcion permite conocer si un poligono esta de cara


//o de espaldas al observador, segun devuelva un valor mayor
//o menor que cero
double Hidden(VTX v1, VTX v2, VTX v3)
{
VTX u, v;
VTX out;
double xout, yout, zout;
double temp;

u.x = v2.x - v1.x;


u.y = v2.y - v1.y;
u.z = v2.z - v1.z;
v.x = v3.x - v1.x;
v.y = v3.y - v1.y;
v.z = v3.z - v1.z;
producto_vectorial(u, v, &out);
temp = producto_escalar(out.x, out.y, out.z, 0.0, 0.0, -1.0);
return temp;
}

//funcion usada para calcular el nivel de intensidad de la


//luz que recibe un poligono
int Light(VTX v1, VTX v2, VTX v3)
{
VTX u, v, out;
double temp;

u.x = v2.x - v1.x;


u.y = v2.y - v1.y;
u.z = v2.z - v1.z;
v.x = v3.x - v1.x;
v.y = v3.y - v1.y;
v.z = v3.z - v1.z;
//out es el vector normal al poligono
producto_vectorial(u, v, &out);
vector_normalizado(&out.x, &out.y, &out.z);
vector_normalizado(&xlight, &ylight, &zlight);
//El resultado de todas estas operaciones dar un valor comprendido
//entre 0.0 (m¡nima luz) y 1.0f (m xima luz)
temp = producto_escalar(out.x, out.y, out.z, xlight, ylight, zlight);
temp = 256.0*temp;
if (temp<0.0)
temp=0.0;
else
if (temp>255.0)
temp=255.0;
return (int) (temp);
}

//me dibuja un poligono solido, el color lo determino


//de acuerdo al nivel de luz que recibe.
void DibujarPoligono(int num)
{
int A, B, C;
int poly[6];
int i, color;

i=ListFaces[num].index;
A=faces[i].a;
B=faces[i].b;
C=faces[i].c;
//verifico si el poligono es visible o no
if (Hidden(outpoints[A], outpoints[B], outpoints[C])<0.0)
{
//se llama a la funci¢n que calcula la luz de un pol¡gono
color = Light(outpoints[A], outpoints[B], outpoints[C]);
poly[0]=(int) outpoints[A].x;
poly[1]=(int) outpoints[A].y;
poly[2]=(int) outpoints[B].x;
poly[3]=(int) outpoints[B].y;
poly[4]=(int) outpoints[C].x;
poly[5]=(int) outpoints[C].y;
setfillstyle(SOLID_FILL, color);
setcolor(color);
fillpoly(3, poly);
}
}

int comparar(const void * e1, const void * e2)


{
int d1, d2;

LSTRI *q1 = (LSTRI *)e1;


LSTRI *q2 = (LSTRI *)e2;

d1=q1->d;
d2=q2->d;
return (d2-d1);
}

void setvgapalette256(DacPalette256 *PalBuf)


{
struct REGPACK reg;

reg.r_ax = 0x1012;
reg.r_bx = 0;
reg.r_cx = 256;
reg.r_es = FP_SEG(PalBuf);
reg.r_dx = FP_OFF(PalBuf);
intr(0x10,®);
}

void LeerObjeto(char *nombre)


{
int i;
FILE *in = fopen(nombre, "r");
if (!in)
return;
fscanf(in, "%d\n", &vertices);
//printf("%d\n", vertices);
for (i = 0; i<vertices; i++)
{
fscanf(in, "%lf %lf %lf\n", &points[i].x, &points[i].y, &points[i].z);
//printf("%lf %lf %lf\n", points[i].x, points[i].y, points[i].z);
};
fscanf(in, "%d\n", &poligonos);
//printf("%d\n", poligonos);
for (i = 0; i<poligonos; i++)
{
fscanf(in, "%d %d %d\n", &faces[i].a, &faces[i].b, &faces[i].c);
//printf("%d %d %d\n", faces[i].a, faces[i].b, faces[i].c);
}
//printf("Presionar una tecla para continuar...");
//getch();
fclose(in);
}

int main(void)
{
MATRIZ Rx, Ry, Rz, Rot;
MATRIZ Tr, Mat;
MATRIZ temp;
int i;

//Carga el modelo en memoria


LeerObjeto("toro.dat");

//Inicializa el modo grafico


int driver = DETECT, modo = DETECT;
installuserdriver("Svga256", deteccion);
initgraph(&driver, &modo, "");

for (i=0; i<256; i++)


{
paleta[i][0]=i/4;
paleta[i][1]=i/4;
paleta[i][2]=i/4;
}

//me cambia la paleta de colores a una escala de 64 tonos de grises


setvgapalette256(&paleta);

for (i=0; i<256; i++)


{
setcolor(i);
line(i,0,i,20);
};

set_projeccion_viewport(getmaxx(), getmaxy());

//Inicializa las matrices de rotacion y


//traslacion.
matriz_rotacion_x(&Rx, -0.785);
matriz_rotacion_y(&Ry, 0.523);
matriz_rotacion_z(&Rz, 0.0);
matriz_traslacion(&Tr, 0.0, 0.0, -350.0);
//multiplica las matrices
//Mat=Rx*Ry*Rz*Tr (matriz de transformacion)
matriz_multiplicacion(&Rx, &Ry, &temp);
matriz_multiplicacion(&temp, &Rz, &Rot);
matriz_multiplicacion(&Rot, &Tr, &Mat);
//aplica la matriz de transformacion a cada uno
//de los vertices del modelo.
for (i=0; i<vertices; i++)
{
aplicar_matriz(&Mat, points[i].x, points[i].y, points[i].z,
&outpoints[i].x, &outpoints[i].y, &outpoints[i].z);
persp_projeccion(outpoints[i].x, outpoints[i].y, outpoints[i].z,
&outpoints[i].x, &outpoints[i].y);
};
//construyo una tabla con las coordenadas z, de cada uno
//de los poligonos.
for (i=0; i<poligonos; i++)
{
ListFaces[i].d = (int) fabs(outpoints[faces[i].a].z + outpoints[faces[i].b].z +
outpoints[faces[i].c].z);
ListFaces[i].index=i;
}
//ordeno los poligonos de acuerdo a z.
qsort(ListFaces, poligonos, sizeof(ListFaces[0]), comparar);

//dibujo los poligonos


for (i=0; i<poligonos; i++)
DibujarPoligono(i);

getch();
closegraph();
return 0;
}

You might also like