Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links
Cada poligono del modelo, tiene un vector normal asociado, el que me sirve para saber de que color debo "pintarlo", estos vectores tiene que tener modulo 1, es decir estan normalizados, por ejemplo en esta imagen se utilizaron estos vectores para "pintar" los poligonos, se pueden ver las facetas, es decir los poligonos, para que el modelo tenga una apariencia mas "suave", voy a utilizar lo que se llama "Smooth Shading", este metodo me elimina la diferencia de color entre poligonos y el modelo toma una apariencia mas "suave", como si estaria compuesto por una gran cantidad de poligonos, el codigo es similar al del ejemplo anterior.
![]() |
El siguiente codigo me calcula los vectores normales para cada uno de los vertices, las promedia y despues normaliza el resultado con lo que ese vertice presentara un vector normal al cual han contribuido todas las caras a las que pertenece.
... for (i=0; i<NumVertices; i++) { for (j=0; j<NumPoligonos; j++) { if (Poli[j][0]==i || Poli[j][1]==i || Poli[j][2]==i) { sumx = sumx + Tri[j].N[0]; sumy = sumy + Tri[j].N[1]; sumz = sumz + Tri[j].N[2]; shared ++; } } vnormales[i][0] = sumx / (float) shared; vnormales[i][1] = sumy / (float) shared; vnormales[i][2] = sumz / (float) shared; Normalizar(&vnormales[i][0], &vnormales[i][1], &vnormales[i][2]); sumx=0.0; sumy=0.0; sumz=0.0; shared=0.0; } ...
El codigo que me dibuja las caras es el siguiente, alli utilizo los vectores normales para cada uno de los vertices del poligono.
glBegin(GL_TRIANGLES); for (i=0; i<NumPoligonos; i++) { glNormal3fv(vnormales[Poli[i][0]]); glVertex3fv(Tri[i].V1); glNormal3fv(vnormales[Poli[i][1]]); glVertex3fv(Tri[i].V2); glNormal3fv(vnormales[Poli[i][2]]); glVertex3fv(Tri[i].V3); } glEnd();
![]() |
Codigo fuente, ejecutable (Win95), makefile smooth.zip
Archivo de texto que contiene, los datos del modelo Head.zip
#include <GL/glut.h> #include <stdlib.h> #include <math.h> #include <stdio.> #define MaxVertices 2467 #define MaxPoligonos 4834 struct Faces{ GLfloat V1[3]; GLfloat V2[3]; GLfloat V3[3]; GLfloat N[3]; }; struct Faces Tri[MaxPoligonos]; GLfloat Vertices[MaxVertices][3]; GLfloat vnormales[MaxVertices][3]; GLint Poli[MaxPoligonos][3]; GLint NumPoligonos=0; GLint NumVertices=0; float LightPos[] = { 0.8f, 0.8f, 1.0f, 0.0f}; // Light Position float LightAmb[] = { 0.4f, 0.4f, 0.4f, 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", &Vertices[i][0], &Vertices[i][1], &Vertices[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 Normalizar(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 VectorNormal(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; GLfloat sumx=0.0, sumy=0.0, sumz=0.0; int shared=0; GLint i,j; for (i=0; i<NumPoligonos; i++) { //Vertice 1 j=Poli[i][0]; Tri[i].V1[0] = Vertices[j][0]; Tri[i].V1[1] = Vertices[j][1]; Tri[i].V1[2] = Vertices[j][2]; //Verice 2 j=Poli[i][1]; Tri[i].V2[0] = Vertices[j][0]; Tri[i].V2[1] = Vertices[j][1]; Tri[i].V2[2] = Vertices[j][2]; //Vertice 3 j=Poli[i][2]; Tri[i].V3[0] = Vertices[j][0]; Tri[i].V3[1] = Vertices[j][1]; Tri[i].V3[2] = Vertices[j][2]; //Calcula el vector Normal VectorNormal(Tri[i].V1, Tri[i].V2, Tri[i].V3, &NormalX, &NormalY, &NormalZ); //nos retorna un vector unitario, es decir de modulo 1 Normalizar(&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; }; for (i=0; i<NumVertices; i++) { for (j=0; j<NumPoligonos; j++) { if (Poli[j][0]==i || Poli[j][1]==i || Poli[j][2]==i) { sumx = sumx + Tri[j].N[0]; sumy = sumy + Tri[j].N[1]; sumz = sumz + Tri[j].N[2]; shared ++; } } vnormales[i][0] = sumx / (float) shared; vnormales[i][1] = sumy / (float) shared; vnormales[i][2] = sumz / (float) shared; Normalizar(&vnormales[i][0], &vnormales[i][1], &vnormales[i][2]); sumx=0.0; sumy=0.0; sumz=0.0; shared=0.0; } } 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(); gluPerspective( 45.0, 1.0, 1.0, 100.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.3945f, 0.1718f, 0.1289f, 1.0f }; GLfloat mat_diffuse[] = { 0.8231f, 0.67f, 0.574f, 1.0f }; GLfloat mat_specular[] = { 0.8125f, 0.6406f, 0.5898f, 1.0f }; GLfloat mat_shininess[] = { 128.0f }; int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); gluLookAt(30.0, 12.5, 10.0, 0.0, 12.5, 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(vnormales[Poli[i][0]]); glVertex3fv(Tri[i].V1); glNormal3fv(vnormales[Poli[i][1]]); glVertex3fv(Tri[i].V2); glNormal3fv(vnormales[Poli[i][2]]); 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("head.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(400, 400); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow("Smooth Shading"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } |
valcoey@hotmail.com
Ramiro Alcocer, 2001
Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links