Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Trackball issue with Raypicking

  1. #1
    Junior Member Newbie
    Join Date
    Oct 2013
    Posts
    4

    Trackball issue with Raypicking

    I'm trying to develop a 3D raypicking in my OpenGL scene.

    I have a working OBJ loader with a trackball.

    Code :
    char*      model_file = NULL;       /* name of the obect file */
    GLuint     model_list = 0;      /* display list for object */
    GLMmodel*  model;               /* glm model data structure */
    GLfloat    scale;               /* original scale factor */
    GLfloat    smoothing_angle = 90.0;  /* smoothing angle */
    GLfloat    weld_distance = 0.00001; /* epsilon for welding vertices */
    GLboolean  facet_normal = GL_FALSE; /* draw with facet normal? */
    GLboolean  bounding_box = GL_FALSE; /* bounding box on? */
    GLboolean  spheres = GL_FALSE;
    GLboolean  performance = GL_FALSE;  /* performance counter on? */
    GLboolean  stats = GL_FALSE;        /* statistics on? */
    GLuint     material_mode = 0;       /* 0=none, 1=color, 2=material, 3=texture */
    GLint      entries = 0;         /* entries in model menu */
    GLdouble   pan_x = 0.0;
    GLdouble   pan_y = 0.0;
    GLdouble   pan_z = 0.0;
    char texnames[1][64] = {"foto_rgb.ppm"};
    //char texnames[1][64] = {"grid.ppm"};
    GLint w,h;
    GLubyte* texture;
     
     
     
    void line (void) {
     
        glLineWidth(10);
        //glPointSize(50.2);
        glColor3f(0.0f, 1.0f, 0.0f);      
        glBegin(GL_LINES);
            glVertex3f( m_start.x, m_start.y, m_start.z );
            glVertex3f( m_end.x, m_end.y, m_end.z );
        glEnd();
        glColor3f(1.0f,1.0f,1.0f);
        glLineWidth(1);
     
    }
     
     
    void lists(void){
        GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };
        GLfloat diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
        GLfloat specular[] = { 0.0, 0.0, 0.0, 1.0 };
        GLfloat shininess = 65.0;
     
        glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
        glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
        glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
        glMaterialf(GL_FRONT, GL_SHININESS, shininess);
     
        if (model_list)
            glDeleteLists(model_list, 1);
     
        glDisable(GL_TEXTURE_2D);
        /* generate a list */
        switch (material_mode)
        {
         case 0:
            if (facet_normal)
                model_list = glmList(model, GLM_FLAT);
            else
                model_list = glmList(model, GLM_SMOOTH);
         break;
         case 1:
            if (facet_normal)
                model_list = glmList(model, GLM_FLAT | GLM_COLOR);
            else
                model_list = glmList(model, GLM_SMOOTH | GLM_COLOR);
         break;
         case 2:
            if (facet_normal)
                model_list = glmList(model, GLM_FLAT | GLM_MATERIAL);
            else
                model_list = glmList(model, GLM_SMOOTH | GLM_MATERIAL);
         break;
         case 3:
            glEnable(GL_TEXTURE_2D);
            model_list = glmList(model, GLM_TEXTURE);
    //        glDisable(GL_TEXTURE_2D);
         break;
        }
    }
     
    void init(void){
        gltbInit(GLUT_LEFT_BUTTON);
     
        /* read in the model */
        model = glmReadOBJ(model_file);
        scale = glmUnitize(model);
        glmFacetNormals(model);
        glmVertexNormals(model, smoothing_angle);
     
        if (model->nummaterials > 0)
            material_mode = 2;
     
        /* create new display lists */
        lists();
     
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
        glEnable(GL_DEPTH_TEST);
    }
     
    void reshape(int width, int height){
        gltbReshape(width, height);
     
        glViewport(0, 0, width, height);
     
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0, 0.0, -3.0);
    }
     
    void display(void){
        static char s[256], t[32];
        static char* p;
        static int frames = 0;
        int i=0,j=0;
     
        glClearColor(1.0, 1.0, 1.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
        glPushMatrix();
     
        glTranslatef(pan_x, pan_y, 0.0);
     
        gltbMatrix();
     
        if(mouseClicked){
            line();
        }
     
        glCallList(model_list);
     
        glPopMatrix();
     
        glutSwapBuffers();
        glEnable(GL_LIGHTING);
    }
     
    static GLint      mouse_state;
    static GLint      mouse_button;
     
    void mouse(int button, int state, int x, int y){
        GLdouble model_project[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_project);
            glGetDoublev(GL_PROJECTION_MATRIX, proj);
            glGetIntegerv(GL_VIEWPORT, view);
     
            gluProject((GLdouble)x, (GLdouble)y, 0.0,
                model_project, proj, view,
                &pan_x, &pan_y, &pan_z);
            gluUnProject((GLdouble)x, (GLdouble)y, pan_z,
                model_project, proj, view,
                &pan_x, &pan_y, &pan_z);
            pan_y = -pan_y;
        }
     
        if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && glutGetModifiers() & GLUT_ACTIVE_CTRL) {
            convert2dto3D(x,y);
        }
        else if(button == GLUT_WHEEL_UP){ // Wheel up
            glmScale(model, 1.25);
            lists();
        }
        else if(button == GLUT_WHEEL_DOWN){ // Wheel down
            glmScale(model, 0.8);
            lists();
        }
     
        glutPostRedisplay();
    }
     
    void motion(int x, int y){
        GLdouble model[4*4];
        GLdouble proj[4*4];
        GLint view[4];
     
        gltbMotion(x, y);
     
     
        glutPostRedisplay();
    }
     
    int main(int argc, char** argv){
        int buffering = GLUT_DOUBLE;
        struct dirent* direntp;
        DIR* dirp;
        int models;
     
        glutInitWindowSize(512, 512);
        glutInit(&argc, argv);
     
        while (--argc) {
            if (strcmp(argv[argc], "-sb") == 0)
                buffering = GLUT_SINGLE;
            else
                model_file = argv[argc];
        }
     
        if (!model_file) {
    //        model_file = "data/dolphins.obj";
            model_file = "data/boeing_2.obj";
        }
     
        glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | buffering);
        glutCreateWindow("Smooth");
     
        glutReshapeFunc(reshape);
        glutDisplayFunc(display);
        glutKeyboardFunc(keyboard);
        glutMouseFunc(mouse);
        glutMotionFunc(motion);
     
    /* Image data packed tightly. */
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     
        textures();
     
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    //    glEnable(GL_TEXTURE_2D);
     
        models = glutCreateMenu(menu);
        dirp = opendir(DATA_DIR);
        if (!dirp) {
            fprintf(stderr, "%s: can't open data directory.\n", argv[0]);
        } else {
            while ((direntp = readdir(dirp)) != NULL) {
                if (strstr(direntp->d_name, ".obj")) {
                    entries++;
                    glutAddMenuEntry(direntp->d_name, -entries);
                }
            }
            closedir(dirp);
        }
     
     
        init();
     
        glutMainLoop();
        return 0;
    }

    Code :
    void convert2dto3D(int xMouse, int YMouse){
        double matModelView[16], matProjection[16]; 
        int viewport[4]; 
     
        glGetDoublev( GL_MODELVIEW_MATRIX, matModelView ); 
        glGetDoublev( GL_PROJECTION_MATRIX, matProjection ); 
        glGetIntegerv( GL_VIEWPORT, viewport );
     
        double winX = (double)xMouse; 
        double winY = viewport[3] - (double)YMouse; 
        gluUnProject(winX, winY, 0.0, matModelView, matProjection, viewport, &m_start.x, &m_start.y, &m_start.z); 
        gluUnProject(winX, winY, 1.0, matModelView, matProjection,  viewport, &m_end.x, &m_end.y, &m_end.z);
        mouseClicked = GL_TRUE;
     
    }

    Here trackball's functions:

    Code :
    /*
         *  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 "gltb.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();
        }

    If I cast a ray (CTRL + Left_click) at the beginning It works with correct 3D far_point and near_point

    Image:

    If I rotate the object (use Trackball), the ray doesn't use real eye/far points and I can't figure out why.

    Image:

    I've tried with GluLookAt instead of glRotatef, but I can't figure out how to move camera with mouse like this trackball does.
    Last edited by Dark Photon; 01-25-2014 at 05:43 PM.

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,124
    So what is your question? Your ray picking isn't working? Or you trackball doesn't work? I'd fix these separately.

    First, I don't see a VIEWING transform here. It looks like what you have for a viewing transform is a -3 translate along Z, which isn't that useful, particularly if you want to virtual trackball around an object. Would use gluLookAt as it's intuitive (where are you, where are you looking, what direction is up).

    As to the ray picking question, it doesn't look like you're being very deliberate what MODELVIEW transform is active when you do your back transform. What space do you want the backprojected points to be in?

  3. #3
    Junior Member Newbie
    Join Date
    Oct 2013
    Posts
    4
    My teacher gave me the obj viewer and I need to develop a mesh rayPicking.
    Trackball works very well until I cast my ray:
    If I load the scene (the object) the ray picks correct farPlane point (in fact I don't see the ray..It's in front of me); If I flip the object with trackball and I retry to cast, the ray is wrong (image 2).

    I think that gltbMatrix()'s transformations are the problem but I'm an openGL beginner and I don't know how to fix that. gltbMatrix() should change the View using gltbMotion() data.

    About second question, I don't understand you. Are you talking about convert2dto3d()?
    I'm following this tutorial (h**p://antongerdelan.net/opengl/raycasting.html) and some other like that to develop my rayPicking.

    Here (h**ps://www.dropbox.com/s/7y2f1ainvntfttn/gc_smooth_Aguiari.tar.gz) you can try a demo.
    Ctrl+left_click to cast the ray, just the left_click to interact with object.

    Sorry about my english too Tnks for the help

  4. #4
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,124
    Quote Originally Posted by Gorghino View Post
    About second question, I don't understand you. Are you talking about convert2dto3d()?
    I'm talking about when you do "glGetDoublev(GL_MODELVIEW_MATRIX, ... )" followed by "gluUnProject( ... )". What MODELVIEW is active here? Is it the one you want to land your backprojected position in the right space?

  5. #5
    Junior Member Newbie
    Join Date
    Oct 2013
    Posts
    4
    Quote Originally Posted by Dark Photon View Post
    I'm talking about when you do "glGetDoublev(GL_MODELVIEW_MATRIX, ... )" followed by "gluUnProject( ... )". What MODELVIEW is active here? Is it the one you want to land your backprojected position in the right space?
    I don't think so because gltbMatrix() changes that.
    The problem is that I can't figure out when/how cast my ray with updated PoV after a rotation with gltb trackball

  6. #6
    Junior Member Newbie
    Join Date
    Oct 2013
    Posts
    4
    Solved

    The problem was the pushMatrix()/popMatrix() at beginning/end in display().

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •