home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <graph.h>
-
- #define CUAD(a) a*a
- #define NUMVERT 8
- #define TRUE 1
- #define FALSE 0
- #define ROUNDOFF 1.e-6
- #define vec4_set(a,b,c,d,e) {a[0]=b;a[1]=c;a[2]=d;a[3]=e;}
-
- void calcula_tras_a_camara();
- void calcula_camrot();
- void calcula_proy_a_camara();
- void calcula_perspectiva(float p);
- void calcula_mat_rot(double cx,double cy,double cz,double angrot);
- void V4XM44(float a[4], float b[4][4], float c[4]);
- void M44XM44(float a[4][4], float b[4][4], float c[4][4]);
- void M44XM44a(float a[4][4], float b[4][4]);
- void rellena_vertices(float lad );
- void rellena_caras();
- int normaliza(float *x, float *y, float *z);
- void cross(float *a, float *b, float *c);
- void boundig_box(float V[NUMVERT][4],float *xmin,float *xmax,float *ymin,float *ymax);
- int interior_a_poly(float x, float y, int i );
-
- float zoom;
- float culling;
- float mat_rot[4][4]; //matriz de rotaci¢n
- float VERTICES[NUMVERT][4]; //array inicial de vertices
- float VERTransf[NUMVERT][4]; //array de vertices rotados
- int CARAS[6][5]; //array de caras. Por cada cara contiene el indice
- //de los vertices que la componen y un flag de visibilidad
- //0 -cara aculta
- //1 -cara visible
-
- float mat_tras[4][4];
- float mat_rotcam[4][4];
- float mat_proy[4][4];
- float mat_fin[4][4];
- float mat_d[4][4];
- float N[3];
- float V[3];
- float U[3];
- //float v[3];
- float veccamera[3];
- float vecfoco[3];
- float ang; //angulo de rotacion de camara
-
- main(){
- float vecrot[3]; //vector del eje de rotaci¢n
- float normal[3]; //vector normal
- float angrot; //angulo de rotaci¢n en radianes
- float vectemp1[3],vectemp2[3],vectemp3[3]; //vectores temporales
- float modulo;
- float xmin,xmax,ymin,ymax;
- int ind, ind1,ind3;
- int ejey, ejex;
-
- _setvideomode( _VRES16COLOR);
- _setvieworg(320,200);
- //factor de zoom de camara
- zoom = 200;
- //Se define el vector del eje de rotacion
- vecrot[0]=1.;
- vecrot[1]=0.5;
- vecrot[2]=0.5;
- printf("Introduce el punto del camara\n");
- scanf("%f, %f, %f",&veccamera[0],&veccamera[1],&veccamera[2]);
- printf("Introduce el punto del foco\n");
- scanf("%f, %f, %f",&vecfoco[0],&vecfoco[1],&vecfoco[2]);
- _clearscreen(_GCLEARSCREEN);
- rellena_vertices(5); //rellenamos con un cubo de lado 5
- rellena_caras();
-
- ind3=0;
- N[0]=vecfoco[0]-veccamera[0];
- N[1]=vecfoco[1]-veccamera[1];
- N[2]=vecfoco[2]-veccamera[2];
- normaliza( &N[0],&N[1],&N[2]);
-
- V[0]=0-N[2]*N[0];
- V[1]=0-N[2]*N[1];
- V[2]=1-N[2]*N[2];
- normaliza( &V[0],&V[1],&V[2]);
- cross(N,V,U);
- normaliza( &U[0],&U[1],&U[2]);
- for(; ;){ //ciclo de rotacion
- angrot=3.1416*ind3/180.;
- //Normalizaci¢n del vector de rotaci¢n
- normaliza( &vecrot[0],&vecrot[1],&vecrot[2]);
- //C†lculo de la matriz de rotaci¢n
- calcula_mat_rot(vecrot[0],vecrot[1],vecrot[2],angrot);
- //Se aplica la transformacion de rotacion a los vertices
- for(ind=0;ind<8; ind++)
- V4XM44(VERTICES[ind], mat_rot, VERTransf[ind]);
- for(ind=0;ind<6; ind++){
- for(ind1=0;ind1<3; ind1++){
-
- vectemp1[ind1]=VERTransf[CARAS[ind][1]][ind1]-
- VERTransf[CARAS[ind][0]][ind1];
- vectemp2[ind1]=VERTransf[CARAS[ind][2]][ind1]-
- VERTransf[CARAS[ind][1]][ind1];
- vectemp3[ind1]=veccamera[ind1]-VERTransf[CARAS[ind][0]][ind1];
-
- }
- cross(vectemp1,vectemp2,normal);
- culling=normal[0]*vectemp3[0]+normal[1]*vectemp3[1]+normal[2]*vectemp3[2];
- if(culling < 0.) CARAS[ind][4]=0.; //cara oculta
- else CARAS[ind][4]=1.; //cara visible
- }
-
-
- calcula_tras_a_camara();
- calcula_proy_a_camara();
- M44XM44(mat_tras,mat_proy,mat_fin);
- for(ind=0;ind<8;ind++)
- {
-
- V4XM44(VERTransf[ind],mat_fin,VERTransf[ind]);
- //linea alternativa para no rotar
- //V4XM44(VERTICES[ind], mat_fin, VERTransf[ind]);
- calcula_perspectiva(VERTransf[ind][2]);
- V4XM44(VERTransf[ind],mat_d,VERTransf[ind]);
- }
- // Selecci¢n del boundig box del cubo (xmax,xmin,ymax,ymin)
- boundig_box(VERTransf,&xmin,&xmax,&ymin,&ymax);
-
- // C†lculo de las normales por cara
- _setcolor(8);
-
- //ciclo de barrido de pantalla por el bounding box
-
- for(ejex=xmin; ejex<=xmax; ejex++)
- for(ejey=ymin; ejey<=ymax; ejey++)
- for(ind=0;ind<6; ind++){//ciclo por las caras
- if(CARAS[ind][4]==1.){ //filtro de caras visibles
- if( interior_a_poly((float)ejex, (float)ejey, ind )==1)
- _setpixel(ejex,ejey);
- }
- }
-
- // Se dibujan las aristas visibles del cubo
-
- _setcolor(10);
-
- for(ind=0;ind<6; ind++) {
- if(CARAS[ind][4]==1.){
- _moveto( (int)VERTransf[ CARAS[ind][0] ][0], (int) VERTransf[ CARAS[ind][0] ][1]);
- for(ind1=1;ind1<4; ind1++)
- _lineto( (int)VERTransf[ CARAS[ind][ind1] ][0], (int) VERTransf[ CARAS[ind][ind1]][1]);
- _lineto( (int)VERTransf[ CARAS[ind][0] ][0], (int) VERTransf[ CARAS[ind][0] ][1]);
- }
- }
- ind3++;
-
- if (getch()==27)
- break;
- _clearscreen(_GCLEARSCREEN);
-
- }//fin de ciclo de angulo
- _setvideomode(_DEFAULTMODE);
- }//fin de main
-
-
- //Funci¢n para la obtencion de la matriz concatenada de rotaci¢n
- //alrededor de un eje arbitrario con cosenos directores cx,cy,cz, en
- //un †ngulo de rotacion angrot.
-
- void calcula_mat_rot(double cx,double cy,double cz,double angrot)
- {
- double d;
- float Rx[4][4],Rxinv[4][4],Ry[4][4],Ryinv[4][4],Rdelta[4][4];
-
- if(angrot==0.)
- {//Devuelve la matriz identidad si angrot=0
- vec4_set(mat_rot[0],1.,0.,0.,0.);
- vec4_set(mat_rot[1],0.,1.,0.,0.);
- vec4_set(mat_rot[2],0.,0.,1.,0.);
- vec4_set(mat_rot[3],0.,0.,0.,1.);
- }
-
- else
- {
- d=sqrt(cy*cy + cz*cz);
-
- if(d==0.0)
- {//si el eje de rotaci¢n coincide con el eje x
- vec4_set(mat_rot[0],1.,0.,0.,0.);
- vec4_set(mat_rot[1],0.,cos(angrot),sin(angrot),0.);
- vec4_set(mat_rot[2],0.,-sin(angrot),cos(angrot),0.);
- vec4_set(mat_rot[3],0.,0.,0.,1.);
- }
-
- else
- {
- //Formacion de las matrices de rotacion
-
- //Matriz de transformacion alrededor del eje x
- vec4_set(Rx[0],1.0,0.,0.,0.);
- vec4_set(Rx[1],0.,cz/d,cy/d,0.);
- vec4_set(Rx[2],0.,-cy/d,cz/d,0.);
- vec4_set(Rx[3],0.,0.,0.,1.);
-
- //Inversa de la matriz de transformacion alrededor del eje x
- vec4_set(Rxinv[0],1.0,0.,0.,0.);
- vec4_set(Rxinv[1],0.,cz/d,-cy/d,0.);
- vec4_set(Rxinv[2],0.,cy/d,cz/d,0.);
- vec4_set(Rxinv[3],0.,0.,0.,1.);
-
- //Matriz de transformacion alrededor del eje y
- vec4_set(Ry[0],d,0.,cx,0.);
- vec4_set(Ry[1],0.,1.,0.,0.);
- vec4_set(Ry[2],-cx,0.,d,0.);
- vec4_set(Ry[3],0.,0.,0.,1.);
-
- //Inversa de la matriz de transformacion alrededor del eje y
- vec4_set(Ryinv[0],d,0.,-cx,0.);
- vec4_set(Ryinv[1],0.,1.,0.,0.);
- vec4_set(Ryinv[2],cx,0.,d,0.);
- vec4_set(Ryinv[3],0.,0.,0.,1.);
-
- //Matriz de rotacion alrededor del eje arbitrario
- vec4_set(Rdelta[0],cos(angrot),sin(angrot),0.,0.);
- vec4_set(Rdelta[1],-sin(angrot),cos(angrot),0.,0.);
- vec4_set(Rdelta[2],0.,0.,1.,0.);
- vec4_set(Rdelta[3],0.,0.,0.,1.);
-
- //Obtencion de la matriz concatenada de transformacion
- M44XM44(Rx, Ry,mat_rot);
- M44XM44a(mat_rot, Rdelta);
- M44XM44a(mat_rot, Ryinv);
- M44XM44a(mat_rot, Rxinv);
- }
- }
- }
-
- //----------------------------------------------------
- // Multiplica un vector a[4] por una matriz 4x4:
- // c = a*b;
- // El resultado se almacena en el vector c
- // -----------------------------------------------------
-
- void V4XM44(float a[4], float b[4][4], float c[4])
- {
- int j;
- float work[4];
-
- for (j=0; j<4; j++) {
- work[j] = a[0]*b[0][j] + a[1]*b[1][j] + a[2]*b[2][j] + a[3]*b[3][j];
- }
- memcpy(c, work, 4*sizeof(float));
- }
-
- //----------------------------------------------------
- // Multiply dos matrices matrices 4x4:
- // c = a*b;
- // El resultado se almacena en c
- // -----------------------------------------------------
- void M44XM44(float a[4][4], float b[4][4], float c[4][4])
- {
- int j;
- float work[4][4];
-
- for (j=0; j<4;j++) {
- work[0][j] = a[0][0]*b[0][j] + a[0][1]*b[1][j] + a[0][2]*b[2][j] + a[0][3]*b[3][j];
- work[1][j] = a[1][0]*b[0][j] + a[1][1]*b[1][j] + a[1][2]*b[2][j] + a[1][3]*b[3][j];
- work[2][j] = a[2][0]*b[0][j] + a[2][1]*b[1][j] + a[2][2]*b[2][j] + a[2][3]*b[3][j];
- work[3][j] = a[3][0]*b[0][j] + a[3][1]*b[1][j] + a[3][2]*b[2][j] + a[3][3]*b[3][j];
- }
- memcpy(c, work, 16*sizeof(float));
- }
-
- //----------------------------------------------------
- // Multiplica dos matrices 4x4:
- // a = a*b;
- // El resultado se almacena en a
- // -----------------------------------------------------
- void M44XM44a(float a[4][4], float b[4][4])
- {
- int j;
- float work[4][4];
-
- for (j=0; j<4;j++) {
- work[0][j] = a[0][0]*b[0][j] + a[0][1]*b[1][j] + a[0][2]*b[2][j] + a[0][3]*b[3][j];
- work[1][j] = a[1][0]*b[0][j] + a[1][1]*b[1][j] + a[1][2]*b[2][j] + a[1][3]*b[3][j];
- work[2][j] = a[2][0]*b[0][j] + a[2][1]*b[1][j] + a[2][2]*b[2][j] + a[2][3]*b[3][j];
- work[3][j] = a[3][0]*b[0][j] + a[3][1]*b[1][j] + a[3][2]*b[2][j] + a[3][3]*b[3][j];
- }
- memcpy(a, work, 16*sizeof(float));
- }
-
- void rellena_vertices(float lad )
- {
- int ind;
- //Rellena el array de VERTICES con las coordenadas de los vertices del cubo
-
- vec4_set(VERTICES[0],lad, lad, -lad, 1.);
- vec4_set(VERTICES[1],-lad, lad, -lad, 1.);
- vec4_set(VERTICES[2],-lad, lad, lad, 1.);
- vec4_set(VERTICES[3],lad, lad, lad, 1.);
- vec4_set(VERTICES[4],lad, -lad, -lad, 1.);
- vec4_set(VERTICES[5],lad, -lad, lad, 1.);
- vec4_set(VERTICES[6],-lad, -lad, lad, 1.);
- vec4_set(VERTICES[7],-lad, -lad, -lad, 1.);
- }
- void rellena_caras()
- {
- //Rellena el aray de CARAS con el indice de los vertices que componen cada cara
- vec4_set(CARAS[0],0,1,2,3); //superior
- vec4_set(CARAS[1],4,5,6,7); //inferior
- vec4_set(CARAS[2],5,3,2,6); //delantera
- vec4_set(CARAS[3],4,7,1,0); //trasera
- vec4_set(CARAS[4],4,0,3,5); //derecha
- vec4_set(CARAS[5],7,6,2,1); //izquierda
- }
-
- //Normaliza al vector de componentes (x,y,z)
- normaliza(float *x, float *y, float *z)
- {
- //se devuelve el vector normalizado
- double modulo,xx,yy,zz;
- xx=(*x);
- yy=(*y);
- zz=(*z);
- modulo=sqrt(CUAD(xx)+CUAD(yy)+CUAD(zz));
- if (modulo<ROUNDOFF) {
- return(FALSE);
- }
- *x = (xx/modulo);
- *y = (yy/modulo);
- *z = (zz/modulo);
- return(TRUE);
- }
-
- //Calcula el producto vectorial de dos vectores c=a x b
- void cross(float *a, float *b, float *c)
- {
- c[0] = a[1]*b[2] - a[2]*b[1];
- c[1] = a[2]*b[0] - a[0]*b[2];
- c[2] = a[0]*b[1] - a[1]*b[0];
- }
-
- //Determina el bounding box de un conjunto de puntos
- void boundig_box(float V[NUMVERT][4],float *xmin,float *xmax,float *ymin,float *ymax)
- {
- int ind;
- *ymin=999999.;
- *ymax=-999999.;
- *xmin=999999.;
- *xmax=-999999.;
-
- for(ind=0;ind<NUMVERT; ind++)
- {
- *ymin=*ymin>V[ind][1]?V[ind][1]:*ymin;
- *ymax=*ymax<V[ind][1]?V[ind][1]:*ymax;
- *xmin=*xmin>V[ind][0]?V[ind][0]:*xmin;
- *xmax=*xmax<V[ind][0]?V[ind][0]:*xmax;
- }
- }
-
- // Rutina que determina si un punto es interior o exterior al poligono
- //de cuatro lados formado por los cuatro vertices de cada cara
- //proyectados en el plano xy
-
- int interior_a_poly(float x, float y, int i )
- {
- unsigned ss,cort;
- float trasl[4][2];
-
- for(ss=0 ; ss<4 ; ss++)
- {
- trasl[ss][0]=VERTransf[ CARAS[i][ss] ][0]- x ;
- trasl[ss][1]=VERTransf[ CARAS[i][ss] ][1] - y ;
- }
- for (cort=ss=0;ss<4;ss++)
- if ((trasl[ss][1]*trasl[(ss+1)%4][1]<0.0) && (( (trasl[ss][0]>0.0) &&
- (trasl[(ss+1)%4][0]>0.0)) ||
- ((trasl[ss][0]-(trasl[ss][1]*(trasl[(ss+1)%4][0]-trasl[ss][0]))/(trasl[(ss+1)%4][1]-
- trasl[ss][1]))>0.0) ) ) cort ++;
-
- if ((cort%2) !=0)
- return(1); //pto. interior
-
- return(0); //pto. exterior
- }
-
- void calcula_proy_a_camara()
- {
- vec4_set(mat_proy[0],U[0],V[0],N[0],0);
- vec4_set(mat_proy[1],U[1],V[1],N[1],0);
- vec4_set(mat_proy[2],U[2],V[2],N[2],0);
- vec4_set(mat_proy[3],0,0,0,1);
- }
-
- void calcula_camrot()
- {
- vec4_set(mat_rotcam[0],cos(ang),sin(ang),0,0);
- vec4_set(mat_rotcam[1],-sin(ang),cos(ang),0,0);
- vec4_set(mat_rotcam[2],0,0,1,0);
- vec4_set(mat_rotcam[3],0,0,0,1);
- }
- void calcula_tras_a_camara()
- {
- vec4_set(mat_tras[0],1,0,0,0);
- vec4_set(mat_tras[1],0,1,0,0);
- vec4_set(mat_tras[2],0,0,1,0);
- vec4_set(mat_tras[3],-veccamera[0],-veccamera[1],-veccamera[2],1);
- }
- void calcula_perspectiva(float d)
- {
- vec4_set(mat_d[0],zoom/d/1.333,0,0,0);
- vec4_set(mat_d[1],0,zoom/d,0,0);
- vec4_set(mat_d[2],0,0,1,0);
- vec4_set(mat_d[3],0,0,0,1);
- }
- /*
- intersect( float a[2], float b[2], int caso, int wMin[2], int wMax[2],float salida[2])
- {
- float m;
- if (a[0]!=b[0]) m=(a[1]-b[1])/(a[0]-b[0]);
- else m=1;
- switch (caso){
- case 1: //LEFT
- salida[0]=wMin[0];
- salida[1]=b[1]+(wMin[0]-b[0])*m;
- break;
- case 2: //RIGHT
- salida[0]=wMax[0];
- salida[1]=b[1]+(wMax[0]-b[0])*m;
- break;
- case 3: //BOTTOM
- salida[1]=wMin[1];
- if(a[0]!=b[0]) salida[0]=b[1]+(wMin[1]-b[0])/m;
- else salida[0]=b[0];
- break;
- case 4: //TOP
- salida[1]=wMax[1];
- if(a[0]!=b[0]) salida[0]=b[1]+(wMax[1]-b[0])/m;
- else salida[0]=b[0];
- break;
- }
- }
- */
-