Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links
Cámara en OpenGLAqui vamos a ver como visualizar y recorrer un mundo tridimencional que
nosotros mismo creamos usando una sencilla camara para ello, esta se puede
desplazar en el plano XZ, puede avanzar, retroceder, desplazarce
lateralmente al estilo del Quake, rotar la camara, es decir nos permite
ver en cualquier direccion. En el movimiento de la camara se distinguen claramente en dos partes:
Los controles de la camara son : |
La escena fue modelada en el 3D Studio MAX, aqui una vista en moco wireframe que nos permite ver los poligonos que la forman. |
Esta es la salida del programa. |
Código FuenteTodos los archivos necesarios para la compilación, el código fuente,
el ejecutable, la archivo con los objetos de la escena, y los materiales: camara.zip |
/* Autor = Ramiro Alcocer email = valcoey@hotmail.com web = www.oocities.org/valcoey/index.html */ #include <GL/glut.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define M_PI 3.141592653 #define DEF_dollyStepSize 1.0 #define DEF_angleSensitivity 1.0 struct Point3f { float x, y, z; float u, v; }; 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; }; Object3D *object=NULL; int nObjetos=0; Material *pMaterial; float LightPos0[] = { 0.75f, 1.0f, 1.0f, 0.0f}; float LightAmb0[] = { 0.75f, 0.75f, 0.75f, 1.0f}; float LightDif0[] = { 1.0f, 1.0f, 1.0f, 1.0f}; float LightSpc0[] = { 1.0f, 1.0f, 1.0f, 1.0f}; GLfloat camX = 0.0; GLfloat camY = 8.0; GLfloat camZ = -40.0; GLfloat camYaw = 180.0; GLfloat camPitch = 0.0; int isInMouseDrag = false; int mouseIsInverted = true; int viewPortCenterX = -1; int viewPortCenterY = -1; int oldCursorID = 0; int oldCursorX = 0; int oldCursorY = 0; 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) { FILE *file; char *tempString = new char [80]; char trash[15]; float tempX, tempY, tempZ; int tempA, tempB, tempC; int indexMaterial, indexSmoothing; int i,j; if ((file = fopen(filename, "rt"))==NULL) { printf("No puedo abrir el archivo\n"); exit(1); } while(strncmp(tempString, "Objetos",7)) { fscanf(file, "%s", tempString); if (feof(file)) { printf("String \"Objetos\" no existe\n"); exit(1); } } fgetc(file); fscanf(file, "%d", &nObjetos); object=new Object3D[nObjetos]; printf("Objetos en la escena : %d\n", nObjetos); for (j=0; j<nObjetos; j++) { 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[j].nVertices); object[j].pVertices = new Point3f[object[j].nVertices]; for (i=0; i<object[j].nVertices; i++) { //si mi archivo tiene las coordenadas de mapeo de textura utilizo : //fscanf(file, "%f %f %f %f %f\n", &tempX, &tempY, &tempZ, &tempU, &tempV); fscanf(file, "%f %f %f\n", &tempX, &tempY, &tempZ); object[j].pVertices[i].x=tempX; object[j].pVertices[i].y=tempY; object[j].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[j].nFaces); object[j].pFaces = new Face[object[j].nFaces]; printf("objeto: %d vertices: %d faces: %d\n",j, object[j].nVertices, object[j].nFaces); for (i=0; i<object[j].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[j].pFaces[i].vertexIndices[0]=tempA; object[j].pFaces[i].vertexIndices[1]=tempB; object[j].pFaces[i].vertexIndices[2]=tempC; object[j].pFaces[i].material=indexMaterial; object[j].pFaces[i].smoothingGroup=indexSmoothing; } } } void CalcularNormales(void) { float x1, y1, z1; float x2, y2, z2; float x3, y3, z3; float length; int a, b, c; int i, j; for (j=0; j<nObjetos; j++) { for (i=0; i<object[j].nFaces; i++) { Face& face = object[j].pFaces[i]; a = face.vertexIndices[0]; b = face.vertexIndices[1]; c = face.vertexIndices[2]; x1 = object[j].pVertices[b].x - object[j].pVertices[a].x; y1 = object[j].pVertices[b].y - object[j].pVertices[a].y; z1 = object[j].pVertices[b].z - object[j].pVertices[a].z; x2 = object[j].pVertices[c].x - object[j].pVertices[a].x; y2 = object[j].pVertices[c].y - object[j].pVertices[a].y; z2 = object[j].pVertices[c].z - object[j].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 killObject(void) { for (int i=0; i<nObjetos; i++) { delete[] object[i].pFaces; object[i].pFaces = NULL; object[i].nFaces = 0; delete[] object[i].pVertices; object[i].pVertices = NULL; object[i].nVertices = 0; } delete [] object; delete[] pMaterial; pMaterial = NULL; } void enterMouseDrag( int x, int y ) { if( isInMouseDrag ) return; isInMouseDrag = true; if( viewPortCenterX < 0 ) { viewPortCenterX = glutGet( GLUT_WINDOW_WIDTH ) / 2; viewPortCenterY = glutGet( GLUT_WINDOW_HEIGHT ) / 2; } oldCursorID = glutGet( GLUT_WINDOW_CURSOR ); oldCursorX = x; oldCursorY = y; glutSetCursor( GLUT_CURSOR_NONE ); glutWarpPointer( viewPortCenterX, viewPortCenterY ); } void exitMouseDrag( int x, int y ) { if( !isInMouseDrag ) return; isInMouseDrag = false; glutSetCursor( oldCursorID ); glutWarpPointer( oldCursorX, oldCursorY ); } void clampCamera() { if( camPitch > 90.0 ) camPitch = 90.0; else if( camPitch < -90.0 ) camPitch = -90.0; while( camYaw < 0.0 ) camYaw += 360.0; while( camYaw >= 360.0 ) camYaw -= 360.0; } void dollyCamera( GLfloat dollyBy, GLfloat dollyAngle ) { GLfloat actualAngleInRadians; actualAngleInRadians = ( ( camYaw + dollyAngle ) * M_PI / 180.0 ); camX -= sin( actualAngleInRadians ) * dollyBy * DEF_dollyStepSize; camZ -= cos( actualAngleInRadians ) * dollyBy * DEF_dollyStepSize; } void keyboard(unsigned char key, int x, int y) { switch (key) { // Movimiento hacia adelante case 'w': case 'W': dollyCamera( DEF_dollyStepSize, 0.0 ); break; // Movimiento hacia atras case 's': case 'S': dollyCamera( DEF_dollyStepSize, 180.0 ); break; // Strafe hacia la izquierda case 'a': case 'A': dollyCamera( DEF_dollyStepSize, 90.0 ); break; // Strafe derecha case 'd': case 'D': dollyCamera( DEF_dollyStepSize, 270.0 ); break; // Toggle 'inverted' mouse. case 'i': case 'I': mouseIsInverted = !mouseIsInverted; break; //Esc salir case 27: exitMouseDrag( 0, 0 ); exit( 0 ); break; } } void specialFunc( int key, int x, int y ) { switch( key ) { //giro a la izquierda case GLUT_KEY_LEFT: camYaw += 1.0; clampCamera(); break; // giro a la derecha. case GLUT_KEY_RIGHT: camYaw -= 1.0; clampCamera(); break; // mirar hacia arriba. case GLUT_KEY_UP: camPitch += 1.0; clampCamera(); break; // mirar hacia abajo case GLUT_KEY_DOWN: camPitch -= 1.0; clampCamera(); break; } } void mouseFunc( int button, int state, int x, int y ) { if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) { if( !isInMouseDrag ) enterMouseDrag( x, y ); else exitMouseDrag( x, y ); } } void allMotionFunc( int x, int y ) { int deltaX, deltaY; if( !isInMouseDrag ) return; deltaX = x - viewPortCenterX; deltaY = y - viewPortCenterY; if( deltaX == 0 && deltaY == 0 ) return; glutWarpPointer( viewPortCenterX, viewPortCenterY ); camYaw -= DEF_angleSensitivity * deltaX; camPitch -= DEF_angleSensitivity * deltaY * ( mouseIsInverted ? -1.0 : 1.0 ); clampCamera(); glutPostRedisplay(); } void reshape(int w, int h) { if (!h) return; glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 1000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); viewPortCenterX = w / 2; viewPortCenterY = h / 2; } void display(void) { int a, b, c; int i, j, k; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef( -camPitch, 1.0, 0.0, 0.0 ); glRotatef( -camYaw, 0.0, 1.0, 0.0 ); glTranslatef( -camX, -camY, -camZ ); glBegin(GL_TRIANGLES); for (j=0; j<nObjetos; j++) { for (i=0; i<object[j].nFaces; i++) { const Face& face = object[j].pFaces[i]; k=face.material; glMaterialfv(GL_FRONT, GL_AMBIENT, pMaterial[k].ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, pMaterial[k].diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, pMaterial[k].specular); glMaterialf(GL_FRONT, GL_SHININESS, pMaterial[k].shininess); a=face.vertexIndices[0]; b=face.vertexIndices[1]; c=face.vertexIndices[2]; glNormal3f(face.faceNormal.x, face.faceNormal.y, face.faceNormal.z); glVertex3f(object[j].pVertices[a].x, object[j].pVertices[a].y, object[j].pVertices[a].z); glVertex3f(object[j].pVertices[b].x, object[j].pVertices[b].y, object[j].pVertices[b].z); glVertex3f(object[j].pVertices[c].x, object[j].pVertices[c].y, object[j].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); glLightfv(GL_LIGHT0, GL_POSITION, LightPos0); glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb0); glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif0); glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpc0); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); CargarModelo("quake.dat"); ReadMaterial("material.mat"); CalcularNormales(); enterMouseDrag( 0, 0 ); } void idle(void) { glutPostRedisplay(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitWindowSize(500, 375); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutCreateWindow("Test 3D"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc( specialFunc ); glutMouseFunc( mouseFunc ); glutMotionFunc( allMotionFunc ); glutPassiveMotionFunc( allMotionFunc ); glutIdleFunc(idle); glutMainLoop(); killObject(); return 0; } |
Principal | Gráficos 3D | Gráficos 2D | Fractales | Math | Códigos | Tutoriales | Links