Para rotar un objeto sobre uno de los 3 ejes de coordenadas, o sobre cualquier otro vector definido V (x,y,z), OpenGL nos permite utilizar la función:
El ángulo de rotación es siempre un ángulo en sentido en contra de las agujas del reloj y medido en grados. Si por ejemplo quisieramos rotar 45 grados nuestro cubo sobre el eje x el código sería el siguiente:
Concepto pila (stack en inglés) es una lista ordenada o estructura de datos en la que el modo de acceso a sus elementos es de tipo LIFO (del inglés Last In First Out,último en entrar, primero en salir) que permite almacenar y recuperar datos. Esta estructura se aplica en multitud de ocasiones en el área de informática debido a su simplicidad y ordenación implícita de la propia estructura.
Para el manejo de los datos se cuenta con dos operaciones básicas: apilar (push), que coloca un objeto en la pila, y su operación inversa, retirar (o desapilar, pop), que retira el último elemento apilado.
En cada momento sólo se tiene acceso a la parte superior de la pila, es decir, al último objeto apilado (denominado TOS, Top of Stack en inglés). La operación retirarpermite la obtención de este elemento, que es retirado de la pila permitiendo el acceso al siguiente (apilado con anterioridad), que pasa a ser el nuevo TOS.
Por analogía con objetos cotidianos, una operación apilar equivaldría a colocar un plato sobre una pila de platos, y una operación retirar a retirarlo.
Las pilas suelen emplearse en los siguientes contextos:
- Evaluación de expresiones en notación postfija (notación polaca inversa).
- Reconocedores sintácticos de lenguajes independientes del contexto
- Implementación de recursividad.
SECUENCIA Y MANEJO DE PILAS EN OPENGL
Cuando se trata de aplicar una sola transformación no hay ningún problema con las funciones anteriormente comentadas, pero en el caso de que queramos realizar varias transformaciones a un objeto tendremos que entender mejor cómo las gestiona y lleva a cabo OpenGL. La idea principal es que OpenGL utiliza una pila (LIFO) para almacenar las transformaciones.
En la imagen anterior vemos la diferencia entre ejecutar una traslación primeramente y un escalado en segundo lugar, y ejecutar primero un escalado y luego una traslación:
En el primer caso, la primera transformación que se ejecuta es la Traslación y posteriormente el Escalado, aunque en el código lo veamos al revés. ¿Cuál es la razón? La razón está en el comportamiento de la pila. Al ejecutar secuencialmente el código la primera transformación es el Escalado, que es la primera en entrar en la pila, mientras que la Traslación entra después. La traslación está encima del Escalado y por eso se ejecutará antes.
OpenGL tiene una pila para las transformaciones geométricas y de la cámara llamadaGL_MODELVIEW, y otra para las proyecciones denominada GL_PROYECTION. Para indicar sobre qué pila estamos trabajando se utiliza la función glMatrixMode(Nombre_Pila).
Si quisieramos realizar diversas transformes a diferentes objetos la situación se nos complicaría ya que las transformaciones se irían acumulando en la pila. Si se quieren aplicar distintas transformaciones a distintos objetos sería necesario poder modificar el contenido de la pila. OpenGL nos ofrece 3 funciones para manejar las pilas:glLoadIdentity(), glPushMatrix() y glPopMatrix().
La función glLoadIdentity sustituye el contenido de la pila por la matriz de identidad.
La función glPushMatrix() realiza una copia de la matriz superior y la pone encima de la pila, de tal forma que las dos matrices superiores son iguales. De esta forma al llamara a la función glPushMatrix() se duplica la matriz superior y por tanto las siguientes transformaciones que se realizan se aplicarán sólo a la matriz superior de la pila, quedando la anterior con los valores que tenía en el momento de llamar a la función glPushMatrix().
La función glPopMatrix() elimina la matriz superior, quedando en la parte superior de la pila la matriz que estaba en el momento de llamar a la función glPushMatrix().
----------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------
EJEMPLOS (PROGRAMAS)
#include<windows.h>
#include <GL/glut.h>
#include<iostream>
#include <stdlib.h>
using namespace std;
void handleKeypress(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
exit(0);
}
}
void initRendering()
{
glEnable(GL_DEPTH_TEST);
}
void handleResize(int w,int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(double)w/(double)h,1.0,200.0);
}
float _angle=0.0;
float _cameraangle=30.0;
void drawScene()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(_cameraangle,0.0f,1.0f,0.0f); //ROTAR OBJETO 30 GRADOS CON RESPECTO A "Y"
glTranslatef(0.0f, 0.0f, -10.0f);
glPushMatrix();
glTranslatef(5.0f, -1.0f, 0.0f);
glScalef(2.0f,2.0f,2.0f);
glRotatef(_angle,1.0f,3.0f,2.0f); //ROTACION CONTINUA DE 2 GRADOS
glBegin(GL_QUADS);
glVertex3f(-0.7f,0.0f,0.0);
glVertex3f(0.7f,0.0f,0.0);
glVertex3f(0.5f,2.0f,0.0);
glVertex3f(-0.5f,2.0f,0.0);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
void update(int value)
{
_angle+=2.0f;
if(_angle>360.f)
{
_angle-=360;
}
glutPostRedisplay();
glutTimerFunc(25,update,0);
}
int main(int argc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(600,600);
glutCreateWindow("rotate");
initRendering();
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
glutTimerFunc(25,update,0);
glutMainLoop();
return 0;
}
|
Ejemplo 2
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
static GLfloat spin = 0.0;
static GLfloat speed = 0.0;
static int running = 0;
float lngh ; float width ; float depth ;
int i;
void box(float lngh,float width,float depth);
void Fan_Physics();
void Fan_Render();
void init(void)
{
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light_position[] = { 5.0, 1.0, 5.0, 0.0 };
GLfloat mat_amb_diff_color_red[] = {1.0, 0.5, 0.0, 0.5};
GLfloat mat_amb_diff_color_green[] = {0.0, 1.0, 0.0, 0.5};
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_ambient[] = {0.15, 0.15, 0.15, 0.15};
GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_amb_diff_color_green);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
void display(void)
{
//glClear (GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glColor3f (1.0, 1.0, 1.0);
glLoadIdentity (); /* clear the matrix */
/* viewing transformation */
//gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -4.0);
gluLookAt(5,5,5,0,1.5,0,0,1,0);
//Fan_Physics();
Fan_Render();
glutSwapBuffers();
glutPostRedisplay();
}
void Fan_Physics(void)
{
if (running == 1)
speed = speed + 0.9;
if (speed > 360.0)
speed = 360.0;
if (running == 0)
speed = speed - 1.8;
if (speed < 0)
speed = 0;
spin = spin + speed/100;
//glutPostRedisplay();
}
void Fan_Render(void)
{
glPushMatrix();
/* Fan*/
glPushMatrix();
GLfloat mat_amb_diff_color_red[] = {1.0, 0.5, 0.0, 0.5};
GLfloat mat_amb_diff_color_green[] = {0.0, 1.0, 0.0, 0.5};
glTranslatef(0.0, 2.0, 0.5);
glRotatef(spin, 0.0, 0.0, 1.0 );
for (i = 1; i<=360; i=i+60)
{
glPushMatrix();
glRotatef( i, 0.0, 0.0, 1.0 );///ROTACION CON RESPECTO A X
glTranslatef(1.5, 0.0, 0.0);
glRotatef( -45, 1.0, 0.0, 0.0 );
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_amb_diff_color);
glPushMatrix();
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_amb_diff_color_green);
box(1.0,0.3,0.01);
//glEnable(GL_LIGHTING);
glPopMatrix();
glPopMatrix();
}
glPopMatrix();
glPopMatrix();
glPopMatrix();
}
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode (GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
case 32:
if (running == 0)
{running = 1;glutIdleFunc(Fan_Physics);}
else {running = 0;glutIdleFunc(Fan_Physics);}
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize (640, 480);
glutInitWindowPosition (0, 0);
glutCreateWindow (" press SpaceBar to toggle fan rotation");
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
void box(float lngh, float width, float depth)
{
float a = lngh; float b = width; float c = depth;
glBegin(GL_QUADS);
/* Top face of box*/
glVertex3f(a, b, -c);
glVertex3f(-a, b, -c);
glVertex3f(-a, b, c);
glVertex3f(a, b, c);
// Bottom face of box
glVertex3f(a, -b, -c);
glVertex3f(-a, -b, -c);
glVertex3f(-a, -b, c);
glVertex3f( a, -b, c);
glColor3f(1.0,0.0,0.0);
// Front of box
glVertex3f(a, b, c);
glVertex3f(-a, b, c);
glVertex3f(-a, -b, c);
glVertex3f(a, -b, c);
glColor3f(1.0,0.0,0.0);
// Back of box
glVertex3f(a, -b, -c);
glVertex3f(-a, -b, -c);
glVertex3f(-a, b, -c);
glVertex3f(a, b, -c);
glColor3f(1.0,0.0,0.0);
// Left of box
glVertex3f(-a, b, c);
glVertex3f(-a, b, -c);
glVertex3f(-a, -b, -c);
glVertex3f(-a, -b, c);
glColor3f(1.0,0.0,0.0);
// Right of box
glVertex3f(a, b, -c);
glVertex3f(a, b, c);
glVertex3f(a, -b, c);
glColor3f(1.0,0.0,0.0);
// End drawing the box
glEnd();
//return TRUE;
}
---------------------------------------------------------------------------------
EJEMPLO 3 Muestra cubo girando en origen y una esfera girando en un punto fijo
#include <GL/glut.h>
GLfloat anguloCuboX = 0.0f;
GLfloat anguloCuboY = 0.0f;
GLfloat anguloEsfera = 0.0f;
GLint ancho=400;
GLint alto=400;
int hazPerspectiva = 0;
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(hazPerspectiva)
gluPerspective(60.0f, (GLfloat)width/(GLfloat)height, 1.0f, 20.0f);
else
glOrtho(-4,4, -4, 4, 1, 10);
glMatrixMode(GL_MODELVIEW);
ancho = width;
alto = height;
}
void drawCube(void)
{
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_QUADS); //cara frontal
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glEnd();
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_QUADS); //cara trasera
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glEnd();
glColor3f(0.0f, 0.0f, 1.0f);
glBegin(GL_QUADS); //cara lateral izq
glVertex3f(-1.0f,-1.0f, -1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glColor3f(1.0f, 1.0f, 0.0f);
glBegin(GL_QUADS); //cara lateral dcha
glVertex3f(1.0f, -1.0f, 1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glEnd();
glColor3f(0.0f, 1.0f, 1.0f);
glBegin(GL_QUADS); //cara arriba
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glColor3f(1.0f, 0.0f, 1.0f);
glBegin(GL_QUADS); //cara abajo
glVertex3f( 1.0f,-1.0f, -1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, -1.0f);
glEnd();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-3.0f, 0.0f, -5.0f);
glRotatef(anguloCuboX, 1.0f, 0.0f, 0.0f);
glRotatef(anguloCuboY, 0.0f, 1.0f, 0.0f);
glScalef(0.5f, 0.5f, 0.5f);
drawCube();
glLoadIdentity();
glTranslatef(-1.0f, 0.0f, -1.0f);
glRotatef(anguloEsfera, 0.0f, 1.0f, 0.0f);//ROTACION PUNTO FIJO
glTranslatef(0.0f, 0.0f, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glutWireSphere(0.9f, 8, 8);
glFlush();
glutSwapBuffers();
anguloCuboX+=0.1f;
anguloCuboY+=0.1f;
anguloEsfera+=0.1f;
}
void init()
{
glClearColor(0,0,0,0);
glEnable(GL_DEPTH_TEST);
ancho = 400;
alto = 400;
}
void idle()
{
display();
}
void keyboard(unsigned char key, int x, int y)
{
switch(key)
{
case 'p':
case 'P':
hazPerspectiva=1;
reshape(ancho,alto);
break;
case 'o':
case 'O':
hazPerspectiva=0;
reshape(ancho,alto);
break;
// case 27: // escape
//exit(0);
// break;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(ancho, alto);
glutCreateWindow("Cubo 1");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}