I'm using the Haskell code below to get the OpenGL world coordinates from the mouse coordinates (the code is a bit long but this is a minimal code to draw a cube). My expectation is that the function worldFromScreen
given at the end returns the world coordinates from the mouse coordinates (given in pixels from the top-left corner). Thanks to the keyboard-mouse callback I defined, these supposed world coordinates are printed in the terminal when the user right-clicks the mouse.
The code generates a cube of length 1 in front view:
The cube has length 1 and is centered at the origin, so the (x,y) coordinates of the vertices of this face should be (+/-0.5,+/-0.5). However when I right-click on a vertex of this face, I get coordinates (+/-0.2,+/-0.2) approximately. What is this 0.2 ? Is it possible to get (+/-0.5,+/-0.5) by changing something in my code ?
module Basic
where
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
white,black,red :: Color4 GLfloat
white = Color4 1 1 1 1
black = Color4 0 0 0 1
red = Color4 1 0 0 1
display :: DisplayCallback
display = do
clear [ColorBuffer, DepthBuffer]
loadIdentity
preservingMatrix $ do
materialDiffuse Front $= red
renderObject Solid $ Cube 1
swapBuffers
resize :: Size -> IO ()
resize s@(Size w h) = do
viewport $= (Position 0 0, s)
matrixMode $= Projection
loadIdentity
perspective 45.0 (w'/h') 1.0 100.0
lookAt (Vertex3 0 0 (-3)) (Vertex3 0 0 0) (Vector3 0 1 0)
matrixMode $= Modelview 0
where
w' = realToFrac w
h' = realToFrac h
keyboardMouse :: KeyboardMouseCallback
keyboardMouse key state _ position@(Position x y) =
case (key,state) of
(MouseButton LeftButton, Down) -> print (x,y)
(MouseButton RightButton, Down) -> do
(sx, sy, sz) <- worldFromScreen position
print (sx, sy, sz)
_ -> return ()
main :: IO ()
main = do
_ <- getArgsAndInitialize
_ <- createWindow ""
windowSize $= Size 500 500
initialDisplayMode $= [RGBAMode, DoubleBuffered, WithDepthBuffer]
clearColor $= black
materialAmbient FrontAndBack $= black
lighting $= Enabled
light (Light 0) $= Enabled
position (Light 0) $= Vertex4 200 200 (-500) 1
ambient (Light 0) $= white
diffuse (Light 0) $= white
specular (Light 0) $= white
depthFunc $= Just Less
shadeModel $= Smooth
displayCallback $= display
reshapeCallback $= Just resize
keyboardMouseCallback $= Just keyboardMouse
idleCallback $= Nothing
mainLoop
worldFromScreen :: Position -> IO (GLdouble, GLdouble, GLdouble)
worldFromScreen (Position sx sy) = do
viewport@(_, Size _ viewSizeY) <- get viewport
projectionMatrix <- get (matrix $ Just Projection) :: IO (GLmatrix GLdouble)
modelviewMatrix <- get (matrix $ Just $ Modelview 0) :: IO (GLmatrix GLdouble)
let screenPos = Vertex3 (fromIntegral sx) (fromIntegral ((viewSizeY - 1) - sy)) 0
(Vertex3 wx wy wz) <- unProject screenPos projectionMatrix modelviewMatrix viewport
return (wx, wy, wz)
0.5/(h-0.5)
whereh
is the z coordinate of the camera position. I observed that for different values ofh
. – Stéphane Laurent