Articles:
OpenGL:
GL : Mouse Position to 3d Space

JA/JO:
JA : Getting Started
All : Qboolean
All : Bit Flags
All : Vector Math
JKA : Saber Cycle BugFix
JK2 : Classes
JK2 : Ladders
All : FontDat File Info
JK2 : Breakdown
JK2 : PM_ Anim

Dox:
JK2 : Source
JKA : Source

Related:
LF : JA Coding
LF : OJP Forum
LF : General Editing
Code3Arena
Stanford CS Library

Ancient
3.2004
2.2004
1.2004
12.2003

You are visitor #140029.
(since 11/01/2005).
You are unique visitor #32745.
(since 11/01/2005).
Getting a 3d point from the Mouse Position - Wudan

Here it is, my first OpenGL tutorial. If you do a google search for projecting a ray through the mouse position, you'll find many helpful places that will tell you about OpenGL's selection buffer or the gluProject() and gluUnproject functions. It almost seems like nobody wants to tell you how the math works, or doesn't want to explain it.

It seems logical that what we're trying to do should be simple enough - you can guestimate that it has something to do with the field of vision and the aspect ratio, and maybe it was just me that had a hard time coming up with something to get that precious ray (here I'm only generating a 3d point on a specific z-plane, not a ray. To get a ray from what I've got you only need to normalize the vector generated here.)

void wuRayFromMousePos( int x, int y )
{
    float value_fov = 0.7853;
        //this is 45 degrees converted to radians

    float value_aspect = 1.3333;
        //the aspect ratio for a 640 x 480 window

    float half_window_width = 320.0;
    float half_window_height = 240.0;
        //set to half of your window width
        //here i've set it to 320 - half of 640
        //same for window height

    float modifier_x;
    float modifier_y;
        //mathematical handling of the difference between
        //your mouse position and the 'center' of the window

    float point[3];
        //the untransformed ray will be put here

    float point_dist = 10.0;
        //it'll be put this far on the Z plane

    float camera_origin[3];
        //this is where the camera sits, in 3dspace

    float point_xformed[3];
        //this is the transformed point

    GLfloat pulledMatrix[16];
        //pulledMatrix is the OpenGL matrix.

    float final_point[3];
    float color[4] = { 0.0, 1.0, 0.0, 1.0 };
        //for the wuDrawSprite call.

    //These lines are the biggest part of this function.
    //This is where the mouse position is turned into a mathematical
    //'relative' of 3d space. The conversion to an actual point
    modifier_x = tan( value_fov * 0.5 )
        * (( 1.0 - x / half_window_width ) * ( value_aspect ) );
    modifier_y = tan( value_fov * 0.5 )
        * -( 1.0 - y / half_window_height );

    //These 3 take our modifier_x/y values and our 'casting' distance
    //to throw out a point in space that lies on the point_dist plane.
    //If we were using completely untransformed, untranslated space,
    //this would be fine - but we're not :)
    point[0] = modifier_x * point_dist;
    point[1] = modifier_y * point_dist;
    point[2] = point_dist;

    //Next we make an openGL call to grab our MODELVIEW_MATRIX -
    //This is the matrix that rasters 3d points to 2d space - which is
    //kinda what we're doing, in reverse
    glGetFloatv(GL_MODELVIEW_MATRIX, pulledMatrix);
    //Some folks would then invert the matrix - I invert the results.

    //First, to get the camera_origin, we transform the 12, 13, 14
    //slots of our pulledMatrix - this gets us the actual viewing
    //position we are 'sitting' at when the function is called
    camera_origin[0] = -(
        pulledMatrix[0] * pulledMatrix[12] +
        pulledMatrix[1] * pulledMatrix[13] +
        pulledMatrix[2] * pulledMatrix[14]);
    camera_origin[1] = -(
        pulledMatrix[4] * pulledMatrix[12] +
        pulledMatrix[5] * pulledMatrix[13] +
        pulledMatrix[6] * pulledMatrix[14]);
    camera_origin[2] = -(
        pulledMatrix[8] * pulledMatrix[12] +
        pulledMatrix[9] * pulledMatrix[13] +
        pulledMatrix[10] * pulledMatrix[14]);

    //Second, we transform the position we generated earlier - the '3d'
    //mouse position - by our viewing matrix.
    point_xformed[0] = -(
        pulledMatrix[0] * point[0] +
        pulledMatrix[1] * point[1] +
        pulledMatrix[2] * point[2]);
    point_xformed[1] = -(
        pulledMatrix[4] * point[0] +
        pulledMatrix[5] * point[1] +
        pulledMatrix[6] * point[2]);
    point_xformed[2] = -(
        pulledMatrix[8] * point[0] +
        pulledMatrix[9] * point[1] +
        pulledMatrix[10] * point[2]);

    //That's pretty much that. Using the camera origin and the
    //transformed ray, you can now do ray-triangle collision
    //detection, which i'll leave up to you.

    //so you can see this function in action, i've included a second
    //function to draw a sprite (billboard)
    final_point[0] = point_xformed[0] + camera_origin[0];
    final_point[1] = point_xformed[1] + camera_origin[1];
    final_point[2] = point_xformed[2] + camera_origin[2];

    wuDrawSprite( final_point, color, 0.25 );
}
Well, that was pretty swell, right? Ok, now for that wuDrawSprite function I promised:

void wuDrawSprite( float pos[3], float color[4], float scale )
{
    float tl[3];
    float tr[3];
    float bl[3];
    float br[3];
    float rup[3];
    float rrt[3];
    GLfloat Matrix[16];

    glGetFloatv(GL_MODELVIEW_MATRIX, Matrix);

    rrt[0] = Matrix[0];
    rrt[1] = Matrix[4];
    rrt[2] = Matrix[8];

    rup[0] = Matrix[1];
    rup[1] = Matrix[5];
    rup[2] = Matrix[9];

    tl[0] = pos[0] + ( (rup[0] + -rrt[0]) * scale );
    tl[1] = pos[1] + ( (rup[1] + -rrt[1]) * scale );
    tl[2] = pos[2] + ( (rup[2] + -rrt[2]) * scale );
    tr[0] = pos[0] + ( (rup[0] + rrt[0]) * scale );
    tr[1] = pos[1] + ( (rup[1] + rrt[1]) * scale );
    tr[2] = pos[2] + ( (rup[2] + rrt[2]) * scale );
    bl[0] = pos[0] + ( (-rup[0] + -rrt[0]) * scale );
    bl[1] = pos[1] + ( (-rup[1] + -rrt[1]) * scale );
    bl[2] = pos[2] + ( (-rup[2] + -rrt[2]) * scale );
    br[0] = pos[0] + ( (-rup[0] + rrt[0]) * scale );
    br[1] = pos[1] + ( (-rup[1] + rrt[1]) * scale );
    br[2] = pos[2] + ( (-rup[2] + rrt[2]) * scale );

    glColor4f( color[0], color[1], color[2], color[3] );
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f( bl[0], bl[1], bl[2] );
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f( tl[0], tl[1], tl[2] );
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f( tr[0], tr[1], tr[2] );
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f( br[0], br[1], br[2] );
    glEnd();
}
Comments and Suggestions Follow: