Re: [Plib-users] Window (x,y) to world coordinates
Brought to you by:
sjbaker
|
From: Steve B. <sjb...@ai...> - 2001-12-20 04:10:32
|
Ask For Joy wrote:
> I have a PLIB application in which my camera is facing down along the Z axis to
> look at a grid on the XY plane. I can move the camera up and down along the Z
> axis to effectively 'zoom' my view of the plane.
(Technically, that's not "zooming" - you have to change the camera's field of
view to make it zoom).
> I can also move the camera
> along the XY axis, but in all cases I am looking down square upon the XY axis .
That's probably because SG & SSG use a 'Z-is-up' coordinate system so the default
camera is looking along the Y axis towards Y==+infinity.
If you made your XY grid in a 3D modelling program then it's probably built
using Y-is-up and our model loaders will have switched the coordinates around
for you so it's now an XZ grid. Now, it's a vertical wall and we are staring
straight at it. When you move the camera in Z, you are getting higher in
altitude - which I think explains what you are seeing.
Of course this is all blown away as an explanation if you typed the grid into
your C++ code and stuffed the coordinates directly into SSG.
(Yes, I know that OpenGL uses Y-is-up - but I come from a flight simulation
background and we've always used Z-is-up. When I wrote SSG, I didn't really
intend for anyone else to ever use it - so I wrote it for *MY* personal
convenience...it doesn't matter at all in terms of functionality - but it
can be a little confusing for beginners and people who use Y-is-up routinely.)
> What I am looking for is a way to translate window coordinates obtained from the
> mouse to world coordinates, taking into account the window dimensions and
> current camera position.
Well, you can't do that for an arbitary setup - because there are an infinite
number of world coordinates that lie in a line from your eye through the mouse
position and out into the world.
However, if you just want to know where it hit your XY plane (or any other specific
plane for that matter) then you need to do this:
Figure out where the 'camera' is in your world.
Imagine that this is really where your eye is.
Imagine the screen sitting in your scene at an appropriate
distance and direction from your eye for the field of view
that you selected.
Imagine the mouse cursor stuck onto that little rectangle.
Draw a line from the eye, through the tip of the mouse out into
the scene.
Figure out where that line intersects your infinite plane...that's
the coordinate you need.
The routine:
sgIsectInfLinePlane ( sgVec3 dst,
sgVec3 l_org, sgVec3 l_vec,
sgVec4 plane ) ;
...computes the intersection of an infinite line with an infinite plane.
So 'dst' will be populated with the results.
'l_org' is the origin of your line (which in this case is
the position of the camera (your eye) in the scene.
'l_vec' is a unit vector pointing in the direction of the
line. This is going to be defined by the mouse position
rotated by the camera rotation.
'plane' is the plane equation of your infinite plane (you can
form the plane equation directly if you know what you are doing - if
not, pass three points from the plane into sgMakePlane and it'll
figure out the plane equation for you).
The hardest part of this is getting the 'l_vec' thing right. The
easy way is to create a 3D point that represents the mouse coordinate...
so if the mouse is at: ( mx, my ) then in 3D, it's at ( mx, screendist, my )
(remembering that Z-is-up in PLIB - and assuming your mouse coordinates are
(0,0) in the center of the screen with Y getting bigger towards the top of
the screen and X getting bigger to the right).
The 'screendist' thing is the distance of the screen from your eye.
You have to figure that out using the field of view angle and some
simple trig..
screendist = (screen_width/2) / tan ( horizontal_fov / 2 )
(Notice that the 'screen_width' term has to be in the same units as
your mouse coordinates).
*PHEW* nearly there!
Now you have to transform the 3D mouse coordinate by the current camera
(modelview) matrix to get it's position in World coordinates. Now subtract
the eyepoint position in the world to get a vector - normalize it to get
a unit vector. Now you have everything you need to call sgIsectInfLinePlane.
One slight 'gotcha' is that when you are flying over your infinite 'ground'
plane, you might point the mouse up into the 'sky' where it doesn't hit
the plane at all...well, actually it does because sgIsectInfLinePlane
intersects an INFINITE line - it's infinite in both directions so what you'll
actually get under these circumstances is a 'hit' on the 'ground' somewhere
behind the camera. What you want to do under these circumstances depends
on your application.
There are SG routines for all of those separate operations - but no single
function to do the entire thing (that I'm aware of).
If some kind soul were to write such a thing, it would be cool to put it
into the SSG camera class.
> Is there an easy formula or matrix operation in PLIB
> that will allow me to do this? I tried playing around with the ortho matrix,
> but my experimentation didn't get me very far.
Easy is a relative term...
In a program like PrettyPoly (http://prettypoly.sf.net), we do this by intersecting
a ray from the eye out through the mouse cursor and figuring out which polygon
it struck. Then we can find the plane equation of that polygon and figure out
where it was hit. That removes the limitation of only hitting a single plane -
but it's *MUCH* more complicated. We actually use OpenGL's 'pick' feature to
find out what we clicked the mouse on - there is special support for that in
SSG - but since PPE is the one thing it was written for, the documentation
is pretty much absent.
> BTW, PLIB is wonderful. Its very gradual learning curve and intutitive
> interface is the main reason why I switched back from Direct3D to OpenGL for my
> application.
<blush>
----------------------------- Steve Baker -------------------------------
Mail : <sjb...@ai...> WorkMail: <sj...@li...>
URLs : http://www.sjbaker.org
http://plib.sf.net http://tuxaqfh.sf.net http://tuxkart.sf.net
http://prettypoly.sf.net http://freeglut.sf.net
http://toobular.sf.net http://lodestone.sf.net
|