Archived

This topic is now archived and is closed to further replies.

Kaesebrot

converting screen coordinates to 3D coordinates

Recommended Posts

Kaesebrot    122
hi.. I want to write a small editor and now I need to convert the Cursor-Coordinatesn in 3D-Coordinates.. no matter what perspective is set.. I just want to know which point of the near-clipping plane is projected to the cursor-position... I hope you know what I mean...

Share this post


Link to post
Share on other sites
JuNC    236
This is taken from my sources, I've notated it a bit


      
void ScreenToWorld(Vector3 &out,const ViewParameters& view,float x,float y)
{
Vector3 ax(view.viewMatrix(0,0),view.viewMatrix(0,1),view.viewMatrix(0,2));
Vector3 ay(view.viewMatrix(1,0),view.viewMatrix(1,1),view.viewMatrix(1,2));
Vector3 az(view.viewMatrix(2,0),view.viewMatrix(2,1),view.viewMatrix(2,2));


float xmul = x * view.nearPlane * tan( (view.fov/2.0) * 3.14/180.0);
float ymul = y * ((view.nearPlane * tan( (view.fov/2.0) * 3.14/180.0))/( (float)view.w/(float)view.h));


out.Set(0,0,0);
out += ax * xmul;
out += ay * (-ymul);
out += -az * (view.nearPlane + 0.001); // 0.001 is an epsilon, probably not needed.



out += view.viewPoint;
}


view.viewMatrix is a 3X3 matrix representing the 'tumble' of the world about the camera (the top row gives the x axis pointing right, the middle row gives the y axis pointing up and the bottom row gives the z axis, pointing away from the view vector) and is consistent with OpenGL.

view.viewPoint is a 3 vector representing the camera position.

view.nearPlane is a float value for the distance of the near plane along the view vector (ie the -ve z row of the viewMatrix).

ax,ay,az then represent the three rows of the matrix (extracted by the element accessors viewMatrix(row,col) ).

out is the point on the near plane.

x and y are the NDC space coordinates and range from -1.0 to 1.0 across the screen. The centre of the screen is at (0,0), (-1.0,-1.0) is the top left of the screen.

view.fov is the field of view

view.w, view.h are the width and height of the viewport in pixels (these are float values).

[edited by - JuNC on June 9, 2002 10:24:20 AM]

[edited by - JuNC on June 9, 2002 10:25:37 AM]

Share this post


Link to post
Share on other sites
Kaesebrot    122
I figured out my own function and compared it with JuNC's function. I think they are mostly the same. It works fine until I use glTranslate or glRotate. I don't find the error, maybe my extraction of the achsis-vectors is wrong.. does anyone see my fault?


    
TVector vXAchsis, vYAchsis, vZAchsis, vViewPos;
float vViewMatrix[16];
float vAspect = vFrontView->vWidth / vFrontView->vHeight;
float vFOV = 45.0f * (PI / 180.0f) / 2.0f;
float vNearPlane = 20.0f;//0.01 * 50.1f;

float vXPos, vYPos;

vXPos = (float)(X - vFrontView->vWidth / 2) / (float)(vFrontView->vWidth / 2);
vYPos = -(float)(Y - vFrontView->vHeight / 2) / (float)(vFrontView->vHeight / 2);

glGetFloatv(GL_MODELVIEW_MATRIX, vViewMatrix);
vXAchsis = TVector(vViewMatrix[ 0], vViewMatrix[ 1], vViewMatrix[ 2]);
vYAchsis = TVector(vViewMatrix[ 4], vViewMatrix[ 5], vViewMatrix[ 6]);
vZAchsis = TVector(vViewMatrix[ 8], vViewMatrix[ 9], vViewMatrix[10]);
vViewPos = TVector(vViewMatrix[12], vViewMatrix[13], vViewMatrix[14]);


v3DPos = vViewPos +
vZAchsis * (vNearPlane * -1.0f) +
vXAchsis * (tan(vFOV) * vXPos * vNearPlane) +
vYAchsis * ((vYPos * tan(vFOV) * vNearPlane) / vAspect);


[edited by - Kaesebrot on June 9, 2002 2:05:03 PM]

Share this post


Link to post
Share on other sites
JuNC    236
If it''s screwing up with glRotate it might be the case that you need to transpose the 3X3 matrix indices, OpenGL uses the rows of the matrix for the axes and stores it in column major format:

[ a1 a5 a9 a13 ]
[ a2 a6 a10 a14 ]
[ a3 a7 a11 a15 ]
[ a4 a8 a12 a16 ]

(Which I assume you know from the extraction of the view pos)

Thus you should be using [0] [4] [8] for the x axis etc. unless anyone can see different.

I think the glTranslate should work correctly when used on it''s own.

Share this post


Link to post
Share on other sites
Kaesebrot    122
I got it

If I call glTranslate it transforms the world not the position of the camera. I just have to invert my extractet vector of the viewpos. The problem with glRotate can be solved the same way.


  

vXAchsis = TVector(vViewMatrix[ 0], -vViewMatrix[ 1], -vViewMatrix[ 2]);
vYAchsis = TVector(-vViewMatrix[ 4], vViewMatrix[ 5], -vViewMatrix[ 6]);
vZAchsis = TVector(-vViewMatrix[ 8], -vViewMatrix[ 9], vViewMatrix[10]);
vViewPos = TVector(-vViewMatrix[12], -vViewMatrix[13], -vViewMatrix[14]);

Share this post


Link to post
Share on other sites
gerogerber    147
Just use gluUnProject(). It takes the current modelview matrix, projection matrix, viewport and screen coords and returns object coords. You get the point on the near plane if you pass 0.0f for winz.
And invert your current y-screen-coord as following: viewport.bottom - y

Gero Gerber

Share this post


Link to post
Share on other sites
Dracle    122
"Just use gluUnProject(). It takes the current modelview matrix, projection matrix, viewport and screen coords and returns object coords. You get the point on the near plane if
you pass 0.0f for winz.
And invert your current y-screen-coord as following: viewport.bottom - y

Gero Gerber"

I have been using gluUnProject() and gluProject() to convert between mouse coordinates and world coordinates. It took me a long time to figure out how to get gluProject() to give me the correct windows coordinates at any rotation(full 3D rotation around X and Y axis), but I eventually figured out a way to do that. So my problem is this...

I''m trying to make a 3D space based RTS, similar to Homeworld or Fargate. I want to be able to move my units in the world the same way they do in these games. If you haven''t played either of these games, first you select the units you want to move, then you press ''M'' or whatever and you move the mouse around to select a coordinate in the X/Z plane for the unit to move to. By holding down SHIFT and moving the mouse you can change which Y coordinate the unit is supposed to go to. Once you click the mouse it combines the information to get one 3D coordinate and the unit begins to move.

What I need to know how to do is how to convert my mouse coordinates into world X and Z coordinates instead of X and Y coordinates. And of course it needs to work at any rotation.

Any help would be greatly appreciated.

Dracle

Share this post


Link to post
Share on other sites
invective    118

//Grab Matrices and Viewport Values
GLdouble model[16];
glGetDoublev ( GL_MODELVIEW_MATRIX, model);

GLdouble projection[16];
glGetDoublev ( GL_PROJECTION_MATRIX, projection);

GLint viewport [4];
glGetIntegerv (GL_VIEWPORT, viewport);

//Read the depth buffer
GLfloat depth;
glReadPixels(mouse_x, mouse_y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);

//Unproject
GLdouble worldX, worldY, worldZ;
gluUnProject (mouse_x, mouse_y, &depth, model, projection, viewport,
&worldX, &worldY, &worldZ);

Share this post


Link to post
Share on other sites
JuNC    236
An easy way to do a homeworld like control thing is to

1. convert your screen coordinates into world space (using gluUnProject or whatever you like)

2. trace a ray from the view point through the worldspace point corresponding to the mouse

3. intersect the ray with a plane - say a horizontal plane y=1

4. take the coordinates of that point, fix them and when the user moves the mouse up and down (holding shift or whatever) simply add an offset along the planes normal to that point.

Share this post


Link to post
Share on other sites
Dracle    122
Thanks invective and JuNC. I was able to get it working using invectine''s method after playing with things for a while. Its a simple solution that I can understand, and it works, so its perfect for the time being. However I would like to understand how to do what JuNC suggested and I''m guessing that his way is faster and possibly more accurate too. Could someone please explain JuNC''s method to me from steps 2 to 4, and include code if possible? I''d like to be able to do stuff like that, but even though I have take linear algebra, I never understand what is happening or how to get it to work in my programs.

Again, thanks a lot.

Dracle

Share this post


Link to post
Share on other sites