Dervall
Dervall

Reputation: 5744

Getting the inverse projection matrix for mouse picking

I'm trying to implement mouse picking in a small application written in haskell. I want to retrieve the projection matrix that has been set with this code found in the resize function that gets called when the window resizes itself:

resize w h = do
   GL.viewport $= (GL.Position 0 0, GL.Size (fromIntegral w) (fromIntegral h))
   GL.matrixMode $= GL.Projection
   GL.loadIdentity
   GL.perspective 45 (fromIntegral w / fromIntegral h) 1 100

The best I've achieved so far is to set the current matrix to GL.Projection and then trying to read the GL.currentMatrix statevar like this:

GL.matrixMode $= GL.Projection
pm <- GL.get GL.currentMatrix
-- inverse the matrix, somehow, and multiply this with the clip plane position of
-- of the mouse

This doesn't work and produces this error:

Ambiguous type variable `m0' in the constraint:
  (GL.Matrix m0) arising from a use of `GL.currentMatrix'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `GL.get', namely `GL.currentMatrix'
In a stmt of a 'do' expression: pm <- GL.get GL.currentMatrix

I think I should be using some sort of type constraint when trying to get the matrix out of the StateVar, but changing the GL.get call to pm <- GL.get (GL.currentMatrix :: GL.GLfloat) just produces a different and equally puzzling message.

I know this is using the old deprecated OpenGL matrix stack and modern code should be using shaders and such to perform their own matrix handling, but I'm not quite comfortable enough in haskell to attempt to really do anything beyond the most basic of projects. If it's easy enough I would certainly try to convert what little rendering code I have to a more modern style, but I find it difficult to find suitable tutorials to help me along.

Upvotes: 2

Views: 1636

Answers (1)

Mokosha
Mokosha

Reputation: 2822

First thing is first: currentMatrix is deprecated and is removed in the most recent OpenGL package (2.9.2.0). In order to use the most recent version, you can upgrade the dependency in your .cabal file. If you look at the source, GL.currentMatrix is identical to calling GL.matrix Nothing.

Second: The error you're receiving is because Haskell doesn't know the type of matrix component (float or double) that you're trying to read from the GL state. You're on the right track about adding a type signature to the function call, but GL.currentMatrix has type

GL.Matrix m, GL.MatrixComponent c => GL.StateVar (m c)

Hence, you need to fully specify the type if you plan on using it in order to disambiguate it to haskell. If you're set on using the old fixed function pipeline, then the type signature should look something like this:

pm <- GL.get (GL.currentMatrix :: GL.StateVar (GL.GLmatrix GL.GLfloat))

That being said, your mouse picking code may still have problems because there're a couple of other factors that you need to account for:

  1. You need both the modelview and projection matrices to get the proper world-space position of the ray into your scene. The call to GL.currentMatrix just gets the current matrix for whatever the current matrix mode is.

  2. Inverting a 4x4 matrix isn't part of the OpenGL package, IIRC and you'll need your own inverting code.

  3. Once you get the proper matrices, the OpenGL.GLU package has an unproject function that might do what you need

Upvotes: 1

Related Questions