Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links
En el ejemplo anterior, la geometria del Cubo es decir los vertices, caras y
normales estaban en el codigo fuente. Las normales ya estaban precalculadas algo
facil de hacerlo en un cubo, ya que tienen la direccion de los ejes de cordenada
pero en objetos de geometria arbitraria esto no es tan facil, recuerden que las
normales me indican la cantidad de luz que recibe cada uno de los poligonos, por
lo tanto cada poligono tiene un vector normal asociado.
En este ejemplo, la informacion de los vertices y poligonos que forman el objeto
se encuentran en un archivo de texto, el cual es leido por el programa y los vectores
normales de cada uno de los poligonos es calculado a partir de los vertices que
lo forman, los poligonos estan compuestos por 3 vertices en este ejemplo.
A partir de los vértices V1, V2, V3 creo dos vectores P, Q que tras su producto vectorial me generan el vector normal, una vez calculada la normal tenemos que normalizar, es decir, dividir ese vector por su propio módulo para que sea unitario, de esta forma tenemos un vector normal de módulo igual a la unidad.
![]() |
Vertices del poligono (V1, V2, V3) V1 = (x1,y1,z1) V2 = (x2,y2,z2) V3 = (x3,y3,z3) V4 = (x4,y4,z4) P = (Px,Py,Pz) Q = (Qx,Qy,Qz) Vector Normal N = (Nx,Ny,Nz) |
Vertices de los poligonos V1, V2, V3, V4.
V1 = (x1,y1,z1)
V2 = (x2,y2,z2)
V3 = (x3,y3,z3)
V4 = (x4,y4,z4)
Obtengo los vectores P y Q, apartir de los vertices V1, V2, V3. diferencia de vectores.
P = V2-V1 = (x2,y2,z2)-(x1,y1,z1) = (x2-x1, y2-y1, z2-z1)Realizo el producto vectorial de los vectores P y Q, me da como
resultado un vector N, que es perpendicular al plano que forman los
vectores P y Q.
Nx = Py*Qz - Pz*Qy
Ny = Pz*Qx - Px*Qz
Nz = Px*Qy - Py*Qx
Modulo del vector N
Modulo = Sqrt(Nx*Nx + Ny*Ny + Nz*Nz)
Normalizo el vector N, es decir va a tener modulo 1, este es el vector
que utilizo para determinar el nivel de luz que recibe el poligono.
Nx = Nx/Modulo
Ny = Ny/Modulo
Nz = Nz/Modulo
La implementacion de estas rutinas en C, es la siguiente:
GLfloat Modulo(GLfloat x, GLfloat y, GLfloat z) { GLfloat len; len = x*x + y*y + z*z; return (sqrt(len)); } GLvoid Normaliza(GLfloat *x, GLfloat *y, GLfloat *z) { GLfloat len; len = Modulo(*x, *y, *z); len = 1.0/len; (*x) *= len; (*y) *= len; (*z) *= len; } GLvoid ProductoVectorial(GLfloat V1[], GLfloat V2[], GLfloat V3[], GLfloat *NormalX, GLfloat *NormalY, GLfloat *NormalZ) { GLfloat Qx, Qy, Qz, Px, Py, Pz; Px = V2[0]-V1[0]; Py = V2[1]-V1[1]; Pz = V2[2]-V1[2]; Qx = V3[0]-V1[0]; Qy = V3[1]-V1[1]; Qz = V3[2]-V1[2]; *NormalX = Py*Qz - Pz*Qy; *NormalY = Pz*Qx - Px*Qz; *NormalZ = Px*Qy - Py*Qx; }
OpenGL utiliza el siguiente comando para dibujar los poligonos, utilizando
la informacion del vector normal.
glBegin(GL_TRIANGLES); //le indico que son poligonos con 3 vertices for (i=0; i<NumPoligonos; i++) { glNormal3fv(Tri[i].N); //este es el vector normal que calcule glVertex3fv(Tri[i].V1); //primer vertice glVertex3fv(Tri[i].V2); //segundo vertice glVertex3fv(Tri[i].V3); //tercer vertice } glEnd();
La esfera esfera.txt esta compuesta por 266 vertices y 528 poligonos, y la cabeza head.txt por 2566 vertices y 4972 poligonos.
Para cargar y visualizar la esfera las modificaciones en el codigo son:
#define MaxVertices 266 #define MaxPoligonos 528 void init(void) { ... GargarPoligonos("esfera.txt"); ... } void display(void) { ... gluLookAt(1.75, 1.75, 1.75, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); ... }
y para la cabeza:
#define MaxVertices 2566 #define MaxPoligonos 4972 void init(void) { ... GargarPoligonos("head.txt"); ... } void display(void) { ... gluLookAt(22.0, 20, 22.0, 0.0, 12.5, 0.0, 0.0, 1.0, 0.0); ... }
![]() |
![]() |
En el archivo normales.zip se encuentra todo
lo necesario para la compilacion del codigo normales.c, Makefile, glutwin32.mak y esfera.txt, este ultimo es el archivo de texto que contiene los vertices y poligonos
que forman el objeto.
Este archivo contiene los datos de la cabeza Head.zip
/* librerias incluidas */ #include <GL/glut.h> #include <math.h> #include <stdio.h> #define MaxVertices 300 #define MaxPoligonos 600 struct Faces{ GLfloat V1[3]; GLfloat V2[3]; GLfloat V3[3]; GLfloat N[3]; }; struct Faces Tri[MaxPoligonos]; GLfloat Vertice[MaxVertices][3]; GLint Poli[MaxPoligonos][3]; GLint NumPoligonos; GLint NumVertices; float LightPos[] = { 1.0f, 0.5f, 1.0f, 0.0f}; // Light Position float LightAmb[] = { 0.2f, 0.2f, 0.2f, 1.0f}; // Ambient Light Values float LightDif[] = { 1.0f, 1.0f, 1.0f, 1.0f}; // Diffuse Light Values float LightSpc[] = { 1.0f, 1.0f, 1.0f, 1.0f}; // Specular Light Values void GargarPoligonos(char *nombre) { int i; FILE *in = fopen(nombre, "r"); if (!in) return; fscanf(in, "%d\n", &NumVertices); for (i = 0; i<NumVertices; i++) fscanf(in, "%f %f %f\n", &Vertice[i][0], &Vertice[i][1], &Vertice[i][2]); fscanf(in, "%d\n", &NumPoligonos); for (i = 0; i<NumPoligonos; i++) fscanf(in, "%d %d %d\n", &Poli[i][0], &Poli[i][1], &Poli[i][2]); fclose(in); } //Calcula el modulo de un vector (longitud) GLfloat Modulo(GLfloat x, GLfloat y, GLfloat z) { GLfloat len; len = x*x + y*y + z*z; return (sqrt(len)); } //Normaliza el vector a mudulo 1 GLvoid Normaliza(GLfloat *x, GLfloat *y, GLfloat *z) { GLfloat len; len = Modulo(*x, *y, *z); len = 1.0/len; (*x) *= len; (*y) *= len; (*z) *= len; } //Calcula el producto vectorial de dos vectores GLvoid CalculateVectorNormal(GLfloat V1[], GLfloat V2[], GLfloat V3[], GLfloat *NormalX, GLfloat *NormalY, GLfloat *NormalZ) { GLfloat Qx, Qy, Qz, Px, Py, Pz; Px = V2[0]-V1[0]; Py = V2[1]-V1[1]; Pz = V2[2]-V1[2]; Qx = V3[0]-V1[0]; Qy = V3[1]-V1[1]; Qz = V3[2]-V1[2]; *NormalX = Py*Qz - Pz*Qy; *NormalY = Pz*Qx - Px*Qz; *NormalZ = Px*Qy - Py*Qx; } //Calculo el vector normal a cada uno de los poligonos void CalcularNormales(void) { GLfloat NormalX, NormalY, NormalZ; GLint i,j; for (i=0; i<NumPoligonos; i++) { //Vertice 1 j=Poli[i][0]; Tri[i].V1[0] = Vertice[j][0]; Tri[i].V1[1] = Vertice[j][1]; Tri[i].V1[2] = Vertice[j][2]; //Verice 2 j=Poli[i][1]; Tri[i].V2[0] = Vertice[j][0]; Tri[i].V2[1] = Vertice[j][1]; Tri[i].V2[2] = Vertice[j][2]; //Vertice 3 j=Poli[i][2]; Tri[i].V3[0] = Vertice[j][0]; Tri[i].V3[1] = Vertice[j][1]; Tri[i].V3[2] = Vertice[j][2]; //Calcula el vector Normal CalculateVectorNormal(Tri[i].V1, Tri[i].V2, Tri[i].V3, &NormalX, &NormalY, &NormalZ); //nos retorna un vector unitario, es decir de modulo 1 Normaliza(&NormalX, &NormalY, &NormalZ); //almacena los vectores normales, para cada poligono Tri[i].N[0] = NormalX; Tri[i].N[1] = NormalY; Tri[i].N[2] = NormalZ; }; } void reshape(int w, int h) { if (!h) return; glViewport(0, 0, (GLsizei) w, (GLsizei) h); /* Activamos la matriz de proyeccion. */ glMatrixMode(GL_PROJECTION); /* "limpiamos" esta con la matriz identidad.*/ glLoadIdentity(); /* Campo de vision 45.0 * radio de aspecto 1.0 * Z near 1.0 * Z far 10.0 */ gluPerspective( 45.0, 1.0, 1.0, 20.0); /* Activamos la matriz de modelado/visionado. */ glMatrixMode(GL_MODELVIEW); /* "Limpiamos" la matriz */ glLoadIdentity(); } void display(void) { /* Propiedades del material del Objeto*/ GLfloat mat_ambient[] = { 0.04f, 0.28f, 0.36f, 1.0f }; GLfloat mat_diffuse[] = { 0.05f, 0.5f, 0.9f, 1.0f }; GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat mat_shininess[] = { 128.0f }; int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //Coordenadas del "ojo", es la posicion donde se encuentra la camara 1.75, 1.75, 1.75 //lugar a donde se mira 0, 0, 0 gluLookAt(1.75, 1.75, 1.75, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //Dibujo el objeto glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glBegin(GL_TRIANGLES); for (i=0; i<NumPoligonos; i++) { glNormal3fv(Tri[i].N); glVertex3fv(Tri[i].V1); glVertex3fv(Tri[i].V2); glVertex3fv(Tri[i].V3); } glEnd(); glPopMatrix(); glFlush(); } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glCullFace(GL_BACK); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); /* Activo la fuente de luz */ glLightfv(GL_LIGHT0, GL_POSITION, LightPos); // Set Light1 Position glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb); // Set Light1 Ambience glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif); // Set Light1 Diffuse glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpc); // Set Light1 Specular glEnable(GL_LIGHT0); // Enable Light1 glEnable(GL_LIGHTING); /* Uso depth buffering para la eliminacion de superficies ocultas */ glEnable(GL_DEPTH_TEST); GargarPoligonos("esfera.txt"); CalcularNormales(); } /* Termina la ejecucion del programa cuando se presiona ESC */ void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(300, 300); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow("Normales"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); /* ANSI C requiere que main retorne un valor entero. */ return 0; } |
valcoey@hotmail.com
Ramiro Alcocer, 2001
Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links