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