Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links

Smooth, por grupos de suavizado

Los grupos de suavizado o smooth, determinan que en el objeto se aprecien perfectamente las caras que lo componen o que, por lo contrario, aparesca una superficie lisa dandole mayor calidad al objeto.


ship_smooth.jpg


Geometria del modelo 3D

El modelo tiene 140 vertices y 276 poligonos, tiene 4 diferentes materiales, y varios grupos de suavizado.

Formato del archivo del modelo

Vertices: 140
-2.565938 2.352102 -6.527843
-2.595936 2.372203 -5.197637
-1.844158 2.311115 -6.988675
......
......
......
3.885235 -2.020434 -2.251750
-4.062057 -1.503610 0.278006
3.996690 -1.510068 0.255300
Faces: 276
1 4 19
MaterialID: 0
Smoothing: 1
10 41 0
MaterialID: 1
Smoothing: 2
......
......
......
80 139 136
MaterialID: 2
Smoothing: 3

Materiales del modelo 3D

En este ejemplo el modelo tiene aplicado varios materiales las propiedades de estos, se encuentran en un archivo de texto el cual, es leido por el programa, para aplicarlo a cada uno de los poligonos del modelo.

material.mat

Material: 4
ambient 0.25 0.25 0.25 1.0
diffuse 0.0 0.8 0.25 1.0
specular 1.0 1.0 1.0 1.0
shininess 128.0
ambient 0.25 0.25 0.25 1.0
diffuse 0.0 0.25 1.0 1.0
specular 1.0 1.0 1.0 1.0
shininess 128.0
ambient 0.1745 0.01175 0.01175 1.0
diffuse 0.61424 0.04136 0.04136 1.0
specular 1.0 1.0 1.0 1.0
shininess 100.0
ambient 0.229412 0.123529 0.027451 1.0
diffuse 0.780392 0.568627 0.113725 1.0
specular 1.0 1.0 1.8 1.0
shininess 100.0

Código Fuente

Codigo Fuente, archivo con los datos del modelo, de los materiales y el ejecutable : ejemplo4.zip
Las rutinas del manejo del mouse las podes ver en trackball.html.

main.cpp

/*
Aplicacion de los grupos de suavizado

autor	: Alcocer Ramiro
emeil 	: valcoey@hotmail.com
www	: www.oocities.org/valcoey/index.html
*/

#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "trackball.h"

struct Point3f
	{
	float x, y, z;
	};

struct Face
	{
	int material;				
	int vertexIndices[3];
	int smoothingGroup;
	Point3f normal[3];
	Point3f faceNormal;
	};

struct Object3D
	{
	int nVertices;
	Point3f *pVertices;			
	int nFaces;
	Face *pFaces;						
	};

struct Material
{
  float diffuse[4];          
  float ambient[4];         
  float specular[4];        
  float shininess;           
};

float LightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f};  
float LightAmb[] = { 0.25f, 0.25f, 0.25f, 1.0f}; 
float LightDif[] = { 1.0f, 1.0f, 1.0f, 1.0f};   
float LightSpc[] = { 1.0f, 1.0f, 1.0f, 1.0f};  

static GLint      mouse_state;
static GLint      mouse_button;
GLdouble   pan_x = 0.0;
GLdouble   pan_y = 0.0;
GLdouble   pan_z = 0.0;

Object3D	obj;
Material	*pMaterial;

void ReadMaterial(char *filename)
{
FILE	*f;
char	line[80];
char	mode[15];
char	trash[9];
int		i,numMaterial;

if((f = fopen(filename, "rt"))==NULL)
	{
	printf("File Not Found : %s\n",filename);
	exit(1);
	}
fgets(line, 80, f );
sscanf(line,"%s %d", &mode, &numMaterial);
pMaterial= new Material[numMaterial];
for (i=0; i<numMaterial; i++)
	{
	fgets(line, 80, f);
	sscanf(line, "%s %f %f %f %f",&trash, &pMaterial[i].ambient[0], &pMaterial[i].ambient[1], 
		                                  &pMaterial[i].ambient[2], &pMaterial[i].ambient[3]);
	fgets(line, 80, f);
	sscanf(line, "%s %f %f %f %f",&trash, &pMaterial[i].diffuse[0], &pMaterial[i].diffuse[1], 
		                                  &pMaterial[i].diffuse[2], &pMaterial[i].diffuse[3]);
	fgets(line, 80, f);
	sscanf(line, "%s %f %f %f %f",&trash, &pMaterial[i].specular[0], &pMaterial[i].specular[1], 
		                                  &pMaterial[i].specular[2], &pMaterial[i].specular[3]);
	fgets(line, 80, f);
	sscanf(line, "%s %f", &trash, &pMaterial[i].shininess);
	}
fclose(f);
}


void CargarModelo(char *filename, Object3D &object)
{
 FILE  *file;
 char  *tempString = new char [80];
 char  trash[15];
 float tempX, tempY, tempZ;
 int   tempA, tempB, tempC;
 int   indexMaterial, indexSmoothing;
 int   i;
 
 if((file = fopen(filename, "rt"))==NULL)
	{
	printf("File Not Found : %s\n",filename);
	exit(1);
	}
 while(strncmp(tempString, "Vertices",8))
	{
	fscanf(file, "%s", tempString);
	if (feof(file))
		{
		printf("String \"Vertices\" no existe\n");
		exit(1);
		}
	}
 fgetc(file);				
 fscanf(file, "%d", &object.nVertices);
 object.pVertices = new Point3f[object.nVertices];
 for (i=0; i<object.nVertices; i++)
	{
 	fscanf(file, "%f %f %f\n", &tempX, &tempY, &tempZ);
	object.pVertices[i].x=tempX;
	object.pVertices[i].y=tempY;
	object.pVertices[i].z=tempZ;
	}
 while(strncmp(tempString, "Faces",5))
	{
	fscanf(file, "%s", tempString);
	if (feof(file))
		{
		printf("String \"Faces\" no existe\n");
		exit(1);
		}
	}
 fgetc(file);				
 fscanf(file, "%d", &object.nFaces);
 object.pFaces = new Face[object.nFaces];
 for (i=0; i<object.nFaces; i++)
	{
 	fscanf(file, "%d %d %d\n", &tempA, &tempB, &tempC);
	fscanf(file, "%s %d\n", &trash, &indexMaterial);
	fscanf(file, "%s %d\n", &trash, &indexSmoothing);
	object.pFaces[i].vertexIndices[0]=tempA;
	object.pFaces[i].vertexIndices[1]=tempB;
	object.pFaces[i].vertexIndices[2]=tempC;
	object.pFaces[i].material=indexMaterial;
	object.pFaces[i].smoothingGroup=indexSmoothing;
	}
}

float Max(float a, float b) 
{
if (b > a)
       return b;
return a;
}

void CalcularNormales(Object3D &object)
{
 float x1, y1, z1;
 float x2, y2, z2;
 float x3, y3, z3;
 float length;
 int   a, b, c;
 int   i;

 for (i=0; i<object.nFaces; i++)
	{
	Face& face = object.pFaces[i];
	a = face.vertexIndices[0];
	b = face.vertexIndices[1];
	c = face.vertexIndices[2];
	x1 = object.pVertices[b].x - object.pVertices[a].x;
	y1 = object.pVertices[b].y - object.pVertices[a].y;
	z1 = object.pVertices[b].z - object.pVertices[a].z;
	x2 = object.pVertices[c].x - object.pVertices[a].x;
	y2 = object.pVertices[c].y - object.pVertices[a].y;
	z2 = object.pVertices[c].z - object.pVertices[a].z;
	z3 = x1*y2 - y1*x2;
	x3 = y1*z2 - z1*y2;
	y3 = z1*x2 - x1*z2;
	length = sqrt(x3*x3 + y3*y3 + z3*z3);
	if (length == 0)
		{
		face.faceNormal.x=1;
		face.faceNormal.y=1;
		face.faceNormal.z=1;
		}
	else
		{
		face.faceNormal.x=x3/length;
		face.faceNormal.y=y3/length;
		face.faceNormal.z=z3/length;
		}
	face.normal[0].x=face.normal[1].x=face.normal[2].x=face.faceNormal.x;
	face.normal[0].y=face.normal[1].y=face.normal[2].y=face.faceNormal.y;
	face.normal[0].z=face.normal[1].z=face.normal[2].z=face.faceNormal.z;
	}
}

void applySmoothingGroups(Object3D &object)
{
int i,j,k,l,smoothingGroup;
float length;

for (i=0; i<object.nFaces; i++)
	{
	smoothingGroup = object.pFaces[i].smoothingGroup;
	for (j=i+1; j<object.nFaces; j++)
		{
		if (smoothingGroup == object.pFaces[j].smoothingGroup)
			{
			for (k=0; k<3; k++)
				{
				for (l=0; l<3; l++)
					{
					if (object.pFaces[i].vertexIndices[k] == object.pFaces[j].vertexIndices[l])
						{
						object.pFaces[i].normal[k].x += object.pFaces[j].faceNormal.x;
						object.pFaces[i].normal[k].y += object.pFaces[j].faceNormal.y;
						object.pFaces[i].normal[k].z += object.pFaces[j].faceNormal.z;
						object.pFaces[j].normal[l].x += object.pFaces[i].faceNormal.x;
						object.pFaces[j].normal[l].y += object.pFaces[i].faceNormal.y;
						object.pFaces[j].normal[l].z += object.pFaces[i].faceNormal.z;
						}
					}
				}
			}
		}
	for (k=0; k<3; k++)
		{
		length = sqrt(pow(object.pFaces[i].normal[k].x,2.0) +
				      pow(object.pFaces[i].normal[k].y,2.0) +
				      pow(object.pFaces[i].normal[k].z,2.0));

		if (length == 0)
			{
			object.pFaces[i].normal[k].x = 1;
			object.pFaces[i].normal[k].y = 1;
			object.pFaces[i].normal[k].z = 1;
			}
		else
			{
			object.pFaces[i].normal[k].x /= length;
			object.pFaces[i].normal[k].y /= length;
			object.pFaces[i].normal[k].z /= length;
			}
		}
	}
}

void EscalarModelo(Object3D &object)
{
int  i;
float maxx, minx, maxy, miny, maxz, minz;
float cx, cy, cz, w, h, d;
float scale;
    
maxx = minx = object.pVertices[0].x;
maxy = miny = object.pVertices[0].y;
maxz = minz = object.pVertices[0].z;
for (i=0; i<object.nVertices; i++) 
	{
      if (maxx < object.pVertices[i].x )
      	    maxx = object.pVertices[i].x;
      if (minx > object.pVertices[i].x)
            minx = object.pVertices[i].x;
      if (maxy < object.pVertices[i].y)
            maxy = object.pVertices[i].y;
      if (miny > object.pVertices[i].y )
            miny = object.pVertices[i].y;
      if (maxz < object.pVertices[i].z)
            maxz = object.pVertices[i].z;
      if (minz > object.pVertices[i].z)
            minz = object.pVertices[i].z;
      } 
w = (float) (fabs(maxx) + fabs(minx));
h = (float) (fabs(maxy) + fabs(miny));
d = (float) (fabs(maxz) + fabs(minz));
cx = (maxx + minx) / 2.0f;
cy = (maxy + miny) / 2.0f;
cz = (maxz + minz) / 2.0f;
scale = 2.0f/ Max(Max(w, h), d);
for (i=0; i<object.nVertices; i++) 
	{
    object.pVertices[i].x  -= cx;
    object.pVertices[i].y  -= cy;
    object.pVertices[i].z  -= cz;
    object.pVertices[i].x  *= scale;
    object.pVertices[i].y  *= scale;
    object.pVertices[i].z  *= scale;
    }
}

void killObject(Object3D &object)
{
 delete[] object.pFaces;
 object.pFaces = NULL;
 object.nFaces = 0;
 delete[] object.pVertices;
 object.pVertices = NULL;
 object.nVertices = 0;
 delete[] pMaterial;
 pMaterial = NULL;
}

void reshape(int w, int h)
{
 if (!h)
	return;
 gltbReshape(w, h);
 glViewport(0, 0,  (GLsizei) w, (GLsizei) h);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 glTranslatef(0.0, 0.0, -2.5);
}

void display(void)
{
 int a, b, c;
 int i;
 int j;

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glPushMatrix();
 gltbMatrix();
 
 glBegin(GL_TRIANGLES);
 for (i=0; i<obj.nFaces; i++)
	{
	const Face& face = obj.pFaces[i];
	j=face.material;
	glMaterialfv(GL_FRONT, GL_AMBIENT, pMaterial[j].ambient);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, pMaterial[j].diffuse);
	glMaterialfv(GL_FRONT, GL_SPECULAR, pMaterial[j].specular);
	glMaterialf(GL_FRONT, GL_SHININESS, pMaterial[j].shininess);
	a=face.vertexIndices[0];
	b=face.vertexIndices[1];
	c=face.vertexIndices[2];
	glNormal3f(face.normal[0].x, face.normal[0].y, face.normal[0].z); 
	glVertex3f(obj.pVertices[a].x, obj.pVertices[a].y, obj.pVertices[a].z);
	glNormal3f(face.normal[1].x, face.normal[1].y, face.normal[1].z); 
    glVertex3f(obj.pVertices[b].x, obj.pVertices[b].y, obj.pVertices[b].z);
	glNormal3f(face.normal[2].x, face.normal[2].y, face.normal[2].z); 
    glVertex3f(obj.pVertices[c].x, obj.pVertices[c].y, obj.pVertices[c].z);
	}
 glEnd();

 glPopMatrix();
 glFlush();
 glutSwapBuffers();
}

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);
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);     
 glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb);         
 glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif);        
 glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpc);       
 glEnable(GL_LIGHT0);                               
 glEnable(GL_LIGHTING);
 glEnable(GL_DEPTH_TEST);
 CargarModelo("ship.dat", obj);
 ReadMaterial("material.mat");
 CalcularNormales(obj);
 applySmoothingGroups(obj);
 EscalarModelo(obj);
 gltbInit(GLUT_MIDDLE_BUTTON);
}

void keyboard(unsigned char key, int x, int y)
{
 switch (key)
   {
   case 27: exit(0);
             break;
   }
}

void mouse(int button, int state, int x, int y)
{
 GLdouble model[4*4];
 GLdouble proj[4*4];
 GLint view[4];
    
 /* fix for two-button mice -- left mouse + shift = middle mouse */
 if (button == GLUT_LEFT_BUTTON && glutGetModifiers() & GLUT_ACTIVE_SHIFT)
	button = GLUT_MIDDLE_BUTTON;
 gltbMouse(button, state, x, y);
 mouse_state = state;
 mouse_button = button;
 if (state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON) 
	{
    glGetDoublev(GL_MODELVIEW_MATRIX, model);
    glGetDoublev(GL_PROJECTION_MATRIX, proj);
    glGetIntegerv(GL_VIEWPORT, view);
    gluProject((GLdouble)x, (GLdouble)y, 0.0,
                model, proj, view,
                &pan_x, &pan_y, &pan_z);
    gluUnProject((GLdouble)x, (GLdouble)y, pan_z,
                 model, proj, view,
                 &pan_x, &pan_y, &pan_z);
    pan_y = -pan_y;
    }
 glutPostRedisplay();
}

void motion(int x, int y)
{
 GLdouble model[4*4];
 GLdouble proj[4*4];
 GLint view[4];
    
 gltbMotion(x, y);
 if (mouse_state == GLUT_DOWN && mouse_button == GLUT_MIDDLE_BUTTON) 
	{
    glGetDoublev(GL_MODELVIEW_MATRIX, model);
    glGetDoublev(GL_PROJECTION_MATRIX, proj);
    glGetIntegerv(GL_VIEWPORT, view);
    gluProject((GLdouble)x, (GLdouble)y, 0.0,
                model, proj, view,
                &pan_x, &pan_y, &pan_z);
    gluUnProject((GLdouble)x, (GLdouble)y, pan_z,
                model, proj, view,
                &pan_x, &pan_y, &pan_z);
    pan_y = -pan_y;
    }
 glutPostRedisplay();
}

int main(int argc, char **argv)
{
 glutInit(&argc, argv);
 glutInitWindowSize(400, 400);
 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
 glutCreateWindow("Modelo 3D (smooth)");
 init();
 glutDisplayFunc(display);
 glutReshapeFunc(reshape);
 glutKeyboardFunc(keyboard);
 glutMouseFunc(mouse);
 glutMotionFunc(motion);
 glutMainLoop();
 killObject(obj);
 return 0;
}

Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links