# OpenGL "dragging" a distant point under the mouse

This topic is 4557 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello all I'm trying to work out a problem - I want to click on an object and drag it under the mouse. Currently, I can select the object using the OpenGL selection buffer, and I can use gluUnProject() to figure the exact coordinates of the hit on the object in question... but because the viewing frustum is not a cube, but a trapezoid... it's not trivial to simply "drag" the object along the camera's perpendicular vectors. So, here's how I envision solving this one: I can get the "depth" of the object easily. I'm aware the the near and far "squares" of the frustum can be obtained. I suspect I can take the X and Y coordinates of the mouse, convert them to percentages (0 in x is far left, 1 is far right), calculate the extremities at the depth of the object in question, and apply those percentages to the extremities to obtain new coordinates. For this, I would need only to know how to find the frustum coordinates. Any ideas? Is there a better way?

##### Share on other sites
What you'll want to do is generate a pick ray form the eye of the camera to where the screen is and intersect that with the deisred plane of movement.

This pseudocode assumes you are using perspective projection.
Note: matrices are the usual column-major format.
M.e refers to the ith element of M in that format.
Vectors presumably initialize to zero.
Vector versus Matrix multiplies occurr in the usual way.

// utilities that make life easier// linear interpolationfloat lerp(float t, float a, float b){    return a+t*(b-a);}// invert an orthonormal matrixvoid invertM(matrix &M){// lots of code}// intersect a ray with a planevector &isect_rayplane(ray &r, plane &n){// will post separately}// somewhere in your program:int width = SCREEN_WIDTHint height = SCREEN_HEIGHTfloat aspect = float(width)/float(height);...// DV_out is the direction of the ray// BP_out is the base point of the ray// output coordinates are located conveniently in object spacevoid pick_ray(int x, int y, vector &DV_out, vector &BP_out){    matrix TM, PM;    glGetFloatv(GL_MODELVIEW_MATRIX,&TM.e[0]);    invertM(TM);    BP_out = TM.column(3); // the translation column, or rightmost of                           // the modelview matrix    glGetFloatv(GL_PROJECTION_MATRIX,&PM.e[0]);    vector DVtmp;    // normalize the input screen coords (you may have to invert the Y axis here)    DVtmp.x = aspect * lerp(float(x)/float(width),-1.0f,1.0f);    DVtmp.y = aspect * lerp(float(y)/float(height),-1.0f,1.0f);    DVtmp.z = -PM.e[5]; // this is the distance from the camera's "eye"                        // to the screen, or what I believe is                        // called the "rasterization plane"    DV_out = (DVtmp * TM) - BP_out;}/*Now we want to keep trak of the cursor coordinates for the current and previous program cycles, as well as their corresponding pick rays and their intersections with our plane of choice.*/int CCX, CCY;  // current cursor positionint LCX = 0, LCY = 0; // last cursor positionray CR, LR;// intersection points of both raysvector ixC, ixL;// the plane of choiceplane PlaneOfChoice;// much later on, say in WndProc():    case WM_LBUTTONDOWN: // or the button of your choice        {            LR = CR;  // reset the last recorded pick ray            ixL = ixC; // reset the last intersection point        };    case WM_MOUSEMOVE:        {            CCX = LOWORD(lParam);            CCY = HIWORD(lParam);            if(left_button_is_down) // or some other button            {                // create the pick ray from these mouse coordinates                pick_ray(CCX,CCY,CR.direction,CR.base);                // intersect the current ray with the plane of choice                ixC = isect_rayplane(CR,PlaneOfChoice);                // handle dragging (move objects by adding the delta vector to                 // their position)                vector DV = ixC - ixL;                // do the moving here                ...                // record intersection points and pick ray                ixL = ixC;                LR = CR;            }            // save mouse coordinates            LCX = CCX;            LCY = CCY;        };

[Edited by - i-photon on July 28, 2006 4:24:06 AM]

##### Share on other sites
I think the matrix inverter is too big to post here. Just consider looking it up online.

As far as the ray/plane intersector goes:
vector &isect_rayplane(ray &r, plane &p){    float t = -dot(p.normal,r.base + r.direction)/dot(p.normal,ray.direction);    return vector(t*r.direction + r.base);}

I hope this helps :)

[Edited by - i-photon on July 28, 2006 1:50:22 AM]

##### Share on other sites
On second thought, here ya go:

// returns the determinant of a 4x4 column-major matrixfloat detM(matrix &M){	float *e = &M->e[0];	return e[1]*e[11]*e[14]*e[4]-	e[1]*e[10]*e[15]*e[4]-	e[11]*e[13]*e[2]*e[4]+	e[10]*e[13]*e[3]*e[4]-	e[0]*e[11]*e[14]*e[5]+	e[0]*e[10]*e[15]*e[5]+	e[11]*e[12]*e[2]*e[5]-	e[10]*e[12]*e[3]*e[5]-	e[1]*e[11]*e[12]*e[6]+	e[0]*e[11]*e[13]*e[6]+	e[1]*e[10]*e[12]*e[7]-	e[0]*e[10]*e[13]*e[7]-	e[15]*e[2]*e[5]*e[8]+	e[14]*e[3]*e[5]*e[8]+	e[1]*e[15]*e[6]*e[8]-	e[13]*e[3]*e[6]*e[8]-	e[1]*e[14]*e[7]*e[8]+	e[13]*e[2]*e[7]*e[8]+	e[15]*e[2]*e[4]*e[9]-	e[14]*e[3]*e[4]*e[9]-	e[0]*e[15]*e[6]*e[9]+	e[12]*e[3]*e[6]*e[9]+	e[0]*e[14]*e[7]*e[9]-	e[12]*e[2]*e[7]*e[9];}// inverts a 4x4 orthogonal column-major matrixvoid invertM(matrix &M){	matrix TMP = M;	float *e = &TMP.e[0];	float d = detM(M); // get the determinant	if(d != 0.0f)		d = 1.0f/d;        else // edit: woops! forgot this...	        d = 1.0f;	M->e[0] = (-e[11]*e[14]*e[5]+e[10]*e[15]*e[5]+e[11]*e[13]*e[6]-e[10]*e[13]*e[7]-e[15]*e[6]*e[9]+e[14]*e[7]*e[9])*d;	M->e[1] = (e[1]*e[11]*e[14]-e[1]*e[10]*e[15]-e[11]*e[13]*e[2]+e[10]*e[13]*e[3]+e[15]*e[2]*e[9]-e[14]*e[3]*e[9])*d;	M->e[2] = (-e[15]*e[2]*e[5]+e[14]*e[3]*e[5]+e[1]*e[15]*e[6]-e[13]*e[3]*e[6]-e[1]*e[14]*e[7]+e[13]*e[2]*e[7])*d;	M->e[3] = (e[11]*e[2]*e[5]-e[10]*e[3]*e[5]-e[1]*e[11]*e[6]+e[1]*e[10]*e[7]+e[3]*e[6]*e[9]-e[2]*e[7]*e[9])*d;	M->e[4] = (e[11]*e[14]*e[4]-e[10]*e[15]*e[4]-e[11]*e[12]*e[6]+e[10]*e[12]*e[7]+e[15]*e[6]*e[8]-e[14]*e[7]*e[8])*d;	M->e[5] = (-e[0]*e[11]*e[14]+e[0]*e[10]*e[15]+e[11]*e[12]*e[2]-e[10]*e[12]*e[3]-e[15]*e[2]*e[8]+e[14]*e[3]*e[8])*d;	M->e[6] = (e[15]*e[2]*e[4]-e[14]*e[3]*e[4]-e[0]*e[15]*e[6]+e[12]*e[3]*e[6]+e[0]*e[14]*e[7]-e[12]*e[2]*e[7])*d;	M->e[7] = (-e[11]*e[2]*e[4]+e[10]*e[3]*e[4]+e[0]*e[11]*e[6]-e[0]*e[10]*e[7]-e[3]*e[6]*e[8]+e[2]*e[7]*e[8])*d;	M->e[8] = (-e[11]*e[13]*e[4]+e[11]*e[12]*e[5]-e[15]*e[5]*e[8]+e[13]*e[7]*e[8]+e[15]*e[4]*e[9]-e[12]*e[7]*e[9])*d;	M->e[9] = (-e[1]*e[11]*e[12]+e[0]*e[11]*e[13]+e[1]*e[15]*e[8]-e[13]*e[3]*e[8]-e[0]*e[15]*e[9]+e[12]*e[3]*e[9])*d;	M->e[10] = (-e[1]*e[15]*e[4]+e[13]*e[3]*e[4]+e[0]*e[15]*e[5]-e[12]*e[3]*e[5]+e[1]*e[12]*e[7]-e[0]*e[13]*e[7])*d;	M->e[11] = (e[1]*e[11]*e[4]-e[0]*e[11]*e[5]+e[3]*e[5]*e[8]-e[1]*e[7]*e[8]-e[3]*e[4]*e[9]+e[0]*e[7]*e[9])*d;	M->e[12] = (e[10]*e[13]*e[4]-e[10]*e[12]*e[5]+e[14]*e[5]*e[8]-e[13]*e[6]*e[8]-e[14]*e[4]*e[9]+e[12]*e[6]*e[9])*d;	M->e[13] = (e[1]*e[10]*e[12]-e[0]*e[10]*e[13]-e[1]*e[14]*e[8]+e[13]*e[2]*e[8]+e[0]*e[14]*e[9]-e[12]*e[2]*e[9])*d;	M->e[14] = (e[1]*e[14]*e[4]-e[13]*e[2]*e[4]-e[0]*e[14]*e[5]+e[12]*e[2]*e[5]-e[1]*e[12]*e[6]+e[0]*e[13]*e[6])*d;	M->e[15] = (-e[1]*e[10]*e[4]+e[0]*e[10]*e[5]-e[2]*e[5]*e[8]+e[1]*e[6]*e[8]+e[2]*e[4]*e[9]-e[0]*e[6]*e[9])*d;}

I copy/pasted this from my vector library. I hope it works for you.

[Edited by - i-photon on July 28, 2006 6:04:18 PM]

##### Share on other sites
please use [ &source ] tags when posting code.
without & and spaces.

##### Share on other sites
Hmm... I think I see what you're suggesting. Instead of taking the depth and a parametric equation of the frustum, you're taking the depth and using a pick ray to find the new location. I should have taken that approach to begin with - I have to do the pick ray anyway to find the exact depth of the object at the point in question.

In my case, I don't use column-major matrices... but that's not that much of a problem, now that I see what I should be doing. Thanks for the pointer :)

##### Share on other sites
You're welcome! :)

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 9
• 13
• 9
• 9
• 15
• ### Forum Statistics

• Total Topics
634076
• Total Posts
3015355
×