OpenGL world coordinates from mouse coordinates
我使用下面的haskell代码从鼠标坐标中获取OpenGL世界坐标(代码有点长,但这是绘制立方体的最小代码)。我的期望是,在最后给出的函数
代码在前视图中生成长度为1的多维数据集:
立方体的长度为1,并以原点为中心,因此该面顶点的(x,y)坐标应为(+/-0.5,+/-0.5)。然而,当我右击这个面的顶点时,我得到的坐标(+/-0.2,+/-0.2)大约是。这是什么0.2?是否可以通过更改我的代码来获得(+/-0.5,+/-0.5)?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 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) |
我不认识Haskell,所以我无法提供工作代码,但我想我理解您的问题。
你有一个二维屏幕的位置,你取消投影到三维,得到一个点。这个点是相机在世界空间中的近平面上的位置。这就是你的"0.2"。现在您还没有指定z值,但是我可以计算它在
当你点击角时,你会得到一个立方体的(+/-0.2,+/-0.2),这个立方体的世界长度是1,所以角应该是(+/-0.5,+/-0.5)。
Note that what you get is a point on camera's near plane in world
space, it is NOT a point on your cube.
该点可与相机位置一起用于生成光线,然后将该光线与平面相交,以获得该平面上的实际位置。
从您的代码中,
1 | lookAt (Vertex3 0 0 (-3)) (Vertex3 0 0 0) (Vector3 0 1 0) |
摄像机在
如果我们考虑你的立方体的右上角,假设你得到的三维点是
1 | Ray( (0.0, 0.0, -3.0), (0.2, 0.2, -1.8) ) |
然后,该光线可以与立方体所在的平面相交,从而获得要查找的点。当你的立方体在原点的中心,并且你正直视它时,平面可以由正常的
1 | Plane(Normal (0.0, 0.0, 1.0), Point (0.0, 0.0, 0.0)). |
现在,如果我们把射线与平面相交,我们得到:
(0.5, 0.5, 0.0)
大概是你想要的。
PS:我用这个链接"平面线相交"来快速测试光线/平面相交。
希望这有帮助。