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


Trackball (rotacion)

Este ejemplo muestra como se puede manipular un objeto 3D, utilizando el mouse para simular un Tracknall, esto me permite rotar el objeto en torno a un eje arbitrario es decir el movimiento de rotacion no esta limitado a los ejes X, Y, Z.
Para rotar el objeto solo basta tener presionado el boton del medio del mouse y arrastrar en la direccion de rotacion.


trackball.jpg


Codigo Fuente

Codigo fuente y ejecutable trackball.zip


trackball.h

/* 
 *  Simple trackball-like motion adapted (ripped off) from projtex.c
 *  (written by David Yu and David Blythe).  See the SIGGRAPH '96
 *  Advanced OpenGL course notes.
 *
 *
 *  Usage:
 *  
 *  o  call gltbInit() in before any other gltb call
 *  o  call gltbReshape() from the reshape callback
 *  o  call gltbMatrix() to get the trackball matrix rotation
 *  o  call gltbStartMotion() to begin trackball movememt
 *  o  call gltbStopMotion() to stop trackball movememt
 *  o  call gltbMotion() from the motion callback
 *  o  call gltbAnimate(GL_TRUE) if you want the trackball to continue 
 *     spinning after the mouse button has been released
 *  o  call gltbAnimate(GL_FALSE) if you want the trackball to stop 
 *     spinning after the mouse button has been released
 *
 *  Typical setup:
 *
 *
    void
    init(void)
    {
      gltbInit(GLUT_MIDDLE_BUTTON);
      gltbAnimate(GL_TRUE);
      . . .
    }

    void
    reshape(int width, int height)
    {
      gltbReshape(width, height);
      . . .
    }

    void
    display(void)
    {
      glPushMatrix();

      gltbMatrix();
      . . . draw the scene . . .

      glPopMatrix();
    }

    void
    mouse(int button, int state, int x, int y)
    {
      gltbMouse(button, state, x, y);
      . . .
    }

    void
    motion(int x, int y)
    {
      gltbMotion(x, y);
      . . .
    }

    int
    main(int argc, char** argv)
    {
      . . .
      init();
      glutReshapeFunc(reshape);
      glutDisplayFunc(display);
      glutMouseFunc(mouse);
      glutMotionFunc(motion);
      . . .
    }
 ***/


/* functions */
void gltbInit(GLuint button);

void gltbMatrix(void);

void gltbReshape(int width, int height);

void gltbMouse(int button, int state, int x, int y);

void gltbMotion(int x, int y);

void gltbAnimate(GLboolean animate);

trackball.cpp

/*
 *  Simple trackball-like motion adapted (ripped off) from projtex.c
 *  (written by David Yu and David Blythe).  See the SIGGRAPH '96
 *  Advanced OpenGL course notes.
 */


#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <GL/glut.h>
#include "trackball.h"


#define GLTB_TIME_EPSILON  10


static GLuint    gltb_lasttime;
static GLfloat   gltb_lastposition[3];

static GLfloat   gltb_angle = 0.0;
static GLfloat   gltb_axis[3];
static GLfloat   gltb_transform[4][4];

static GLuint    gltb_width;
static GLuint    gltb_height;

static GLint     gltb_button = -1;
static GLboolean gltb_tracking = GL_FALSE;
static GLboolean gltb_animate = GL_TRUE;


static void
_gltbPointToVector(int x, int y, int width, int height, float v[3])
{
  float d, a;

  /* project x, y onto a hemi-sphere centered within width, height. */
  v[0] = (2.0 * x - width) / width;
  v[1] = (height - 2.0 * y) / height;
  d = sqrt(v[0] * v[0] + v[1] * v[1]);
  v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0));
  a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  v[0] *= a;
  v[1] *= a;
  v[2] *= a;
}

static void
_gltbAnimate(void)
{
  glutPostRedisplay();
}

void
_gltbStartMotion(int x, int y, int button, int time)
{
  assert(gltb_button != -1);

  gltb_tracking = GL_TRUE;
  gltb_lasttime = time;
  _gltbPointToVector(x, y, gltb_width, gltb_height, gltb_lastposition);
}

void
_gltbStopMotion(int button, unsigned time)
{
  assert(gltb_button != -1);

  gltb_tracking = GL_FALSE;

  if (time - gltb_lasttime < GLTB_TIME_EPSILON && gltb_animate) {
      glutIdleFunc(_gltbAnimate);
  } else {
    gltb_angle = 0;
    if (gltb_animate)
      glutIdleFunc(0);
  }
}

void
gltbAnimate(GLboolean animate)
{
  gltb_animate = animate;
}

void
gltbInit(GLuint button)
{
  gltb_button = button;
  gltb_angle = 0.0;

  /* put the identity in the trackball transform */
  glPushMatrix();
  glLoadIdentity();
  glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)gltb_transform);
  glPopMatrix();
}

void
gltbMatrix(void)
{
  assert(gltb_button != -1);

  glPushMatrix();
  glLoadIdentity();
  glRotatef(gltb_angle, gltb_axis[0], gltb_axis[1], gltb_axis[2]);
  glMultMatrixf((GLfloat*)gltb_transform);
  glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)gltb_transform);
  glPopMatrix();

  glMultMatrixf((GLfloat*)gltb_transform);
}

void
gltbReshape(int width, int height)
{
  assert(gltb_button != -1);

  gltb_width  = width;
  gltb_height = height;
}

void
gltbMouse(int button, int state, int x, int y)
{
  assert(gltb_button != -1);

  if (state == GLUT_DOWN && button == gltb_button)
    _gltbStartMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
  else if (state == GLUT_UP && button == gltb_button)
    _gltbStopMotion(button, glutGet(GLUT_ELAPSED_TIME));
}

void
gltbMotion(int x, int y)
{
  GLfloat current_position[3], dx, dy, dz;

  assert(gltb_button != -1);

  if (gltb_tracking == GL_FALSE)
    return;

  _gltbPointToVector(x, y, gltb_width, gltb_height, current_position);

  /* calculate the angle to rotate by (directly proportional to the
     length of the mouse movement) */
  dx = current_position[0] - gltb_lastposition[0];
  dy = current_position[1] - gltb_lastposition[1];
  dz = current_position[2] - gltb_lastposition[2];
  gltb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);

  /* calculate the axis of rotation (cross product) */
  gltb_axis[0] = gltb_lastposition[1] * current_position[2] - 
               gltb_lastposition[2] * current_position[1];
  gltb_axis[1] = gltb_lastposition[2] * current_position[0] - 
               gltb_lastposition[0] * current_position[2];
  gltb_axis[2] = gltb_lastposition[0] * current_position[1] - 
               gltb_lastposition[1] * current_position[0];

  /* XXX - constrain motion */
  gltb_axis[2] = 0;

  /* reset for next time */
  gltb_lasttime = glutGet(GLUT_ELAPSED_TIME);
  gltb_lastposition[0] = current_position[0];
  gltb_lastposition[1] = current_position[1];
  gltb_lastposition[2] = current_position[2];

  /* remember to draw new position */
  glutPostRedisplay();
}

main.cpp

/* 

Este programa permite simular el movimiento de un
trackball, utilizando el mouse, la ventaja es que
puedo rotar el modelo en torno a un eje arbitrario.
El codigo del manipulador es una daptacion projtex.c 
(written by David Yu and David Blythe), SIGGRAPH '96 
Advanced OpenGL course notes.

autor: Ramiro Alcocer
email: 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>
//------ trackball----------
#include "trackball.h" //implementacion del Trackball
//--------------------------

//------ Trackball ------------
static GLint      mouse_state;
static GLint      mouse_button;
GLdouble   pan_x = 0.0;
GLdouble   pan_y = 0.0;
GLdouble   pan_z = 0.0;
//-----------------------------

//parametros de la fuente de luz
float LightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f};  
float LightAmb[] = { 0.5f, 0.5f, 0.5f, 1.0f}; 
float LightDif[] = { 1.0f, 1.0f, 1.0f, 1.0f};   
float LightSpc[] = { 1.0f, 1.0f, 1.0f, 1.0f}; 

//los materiales que utilizo
//Rojo
float mat_ambient_rojo[]= {0.25, 0.0, 0.0, 1.0};
float mat_diffuse_rojo[]= {1.0, 0.0, 0.0, 1.0};
float mat_specular_rojo[]= {1.0, 1.0, 1.0, 1.0};
float mat_shininess_rojo= 100.0;
//Verde
float mat_ambient_verde[]={0.0, 0.25, 0.0, 1.0};
float mat_diffuse_verde[]={0.0, 1.0, 0.0, 1.0};
float mat_specular_verde[]={1.0, 1.0, 1.0, 1.0};
float mat_shininess_verde=100.0;
//Azul
float mat_ambient_azul[]={0.0, 0.0, 0.25, 1.0};
float mat_diffuse_azul[]={0.0, 0.0, 1.0, 1.0};
float mat_specular_azul[]={1.0, 1.0, 1.0, 1.0};
float mat_shininess_azul=100.0;
//Blanco
float mat_ambient_blanco[]={0.25, 0.25, 0.25, 1.0};
float mat_diffuse_blanco[]={1.0, 1.0, 1.0, 1.0};
float mat_specular_blanco[]={1.0, 1.0, 1.0, 1.0};
float mat_shininess_blanco=100.0;
//Amarillo
float mat_ambient_amarillo[]={0.25, 0.25, 0.0, 1.0};
float mat_diffuse_amarillo[]={1.0, 1.0, 0.0, 1.0};
float mat_specular_amarillo[]={1.0, 1.0, 1.0, 1.0};
float mat_shininess_amarillo=100.0;

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, 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);
 //------ Trackball -----------
 gltbInit(GLUT_MIDDLE_BUTTON);
 //----------------------------
}

void display(void)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glPushMatrix();
 
 //------ Trackball -----
 gltbMatrix();
 //----------------------
 
 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_rojo);
 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_rojo);
 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_rojo);
 glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess_rojo);
 glPushMatrix();
 glTranslatef(0.0,-2.5,5.0);
 glutSolidSphere(1.0,20,20);
 glPopMatrix();
 
 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_verde);
 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_verde);
 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_verde);
 glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess_verde);
 glPushMatrix();
 glTranslatef(4.33,-2.5,-2.5);
 glutSolidSphere(1.0,20,20);
 glPopMatrix();
 
 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_azul);
 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_azul);
 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_azul);
 glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess_azul);
 glPushMatrix();
 glTranslatef(-4.33,-2.5,-2.5);
 glutSolidSphere(1.0,20,20);
 glPopMatrix();

 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_blanco);
 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_blanco);
 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_blanco);
 glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess_blanco);
 glPushMatrix();
 glTranslatef(0.0,0.0,0.0);
 glutSolidSphere(1.25,20,20);
 glPopMatrix();

 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_amarillo);
 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse_amarillo);
 glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular_amarillo);
 glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess_amarillo);
 glPushMatrix();
 glTranslatef(0.0,5.0,0.0);
 glutSolidSphere(1.0,20,20);
 glPopMatrix();

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

void reshape(int w, int h)
{
 if (!h)
	return;

 //------ Trackball --------
 gltbReshape(w, h);
 //-------------------------

 glViewport(0, 0,  (GLsizei) w, (GLsizei) h);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluPerspective(45.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();

 //------ Trackball -----------
 glTranslatef(0.0, 0.0, -18.0);
 //----------------------------
}

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

//----- Tracknall -----------
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();
}

//------ Trackball--------------------
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(380, 380);
 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
 glutCreateWindow("Trackball en OpenGL");
 init();
 glutDisplayFunc(display);
 glutReshapeFunc(reshape);
 glutKeyboardFunc(keyboard);
 //----- Trackball --------
 glutMouseFunc(mouse);
 glutMotionFunc(motion);
 //------------------------
 glutMainLoop();
 return 0;
}

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