c# opentk - converting screen coords to world coords

Started by
7 comments, last by zgintasz 11 years ago

I'm making a windows forms application with opengl view and I'm using c#, openTK . I need to get the mouse coords converted to the opengl world coords. Well, my Y coord gets converted wrong. It's hard to explain, so here is the video: http://tinypic.com/r/23sal8k/6. I'm constantly pressing left mouse button and the red dot should be where the mouse is(but it isn't). How to fix this? Here is the code:


       private void glview_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point worldCoords = convertScreenToWorldCoords(e.X, e.Y);
                shitx = worldCoords.X;
                shity = worldCoords.Y;
            }
        }




        // functions:
        public static Point convertScreenToWorldCoords(int x, int y)
        {
            int[] viewport = new int[4];
            Matrix4 modelViewMatrix, projectionMatrix;
            GL.GetFloat(GetPName.ModelviewMatrix, out modelViewMatrix);
            GL.GetFloat(GetPName.ProjectionMatrix, out projectionMatrix);
            GL.GetInteger(GetPName.Viewport, viewport);
            Vector2 mouse;
            mouse.X = x;
            mouse.Y = viewport[3] - y;
            Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse);
            Point coords = new Point((int)vector.X, (int)vector.Y);
            return coords;
        }
        public static Vector4 UnProject(ref Matrix4 projection, Matrix4 view, Size viewport, Vector2 mouse)
        {
            Vector4 vec;


            vec.X = 2.0f * mouse.X / (float)viewport.Width - 1;
            vec.Y = -(2.0f * mouse.Y / (float)viewport.Height - 1);
            vec.Z = 0;
            vec.W = 1.0f;


            Matrix4 viewInv = Matrix4.Invert(view);
            Matrix4 projInv = Matrix4.Invert(projection);


            Vector4.Transform(ref vec, ref projInv, out vec);
            Vector4.Transform(ref vec, ref viewInv, out vec);


            if (vec.W > float.Epsilon || vec.W < float.Epsilon)
            {
                vec.X /= vec.W;
                vec.Y /= vec.W;
                vec.Z /= vec.W;
            }


            return vec;
        }
 

Game I'm making - GANGFORT, Google Play, iTunes

Advertisement

Try inverting your Y coordinate before using it.

I had this same problem when using my own customized routine to project vertices. It wasn't until I set the Y coordinate to -Y that it finally worked right. Tbh, I've never actually had to unproject a vertex as of yet, but I'm quite sure that it's similar to projecting a vertex in OpenGL w/ RH matrices. So, given that, I'm not 100% sure how you should do it in your code, but I suggest trying this:

mouse.Y = -( viewport[3] - y );

or this:

mouse.Y = viewport[3] + y;

I assume the first one would do the trick.

Also, I'm assuming this might not apply to you, but I had to invert one component of my modelview matrix as well in order for it to work.

modelview[13] = -modelview[13];

So, like I said, I'm familiar with your problem, just not 100% sure what order the steps need to be taken to fix it. I gave it my best shot, so let us know if this works. smile.png

Shogun.

Thanks for reply. Strange but it doesn't work. Using both methods the dot just shows at a bigger distance of mouse:

iLLjgBu.png

and I can't do modelview[13] = -modelview[13] because modelview variable is Matrix4, not array of integers or something else...

Game I'm making - GANGFORT, Google Play, iTunes

I just noticed one thing, it's hard to explain in words, so here it is sleep.png:

6Lp1c0c.png

Game I'm making - GANGFORT, Google Play, iTunes

Okay then, my next guess would be to change this (but after reverting the previous changes I suggested).

vec.Y = (2.0f * mouse.Y / (float)viewport.Height - 1);

Try removing the '-' and see if that works.

Also, sorry I didn't better explain what I was doing with the matrix suggestion. 13 is the column based matrix's location of the Y translation coordinate.

| 1 0 0 X |
| 0 1 0 -Y |
| 0 0 1 Z |
| 0 0 0 1 |

I simply suggested you invert it. I also had to do this to get my vertex projection code to work properly.

Hopefully, my suggestion helps a bit better this time. Sorry for any confusion.

Shogun.

EDIT: This may or may not matter for you, but I had to invert the incoming Y coordinate and the Y component of the translation vector in my modelview matrix in order to fix the problem.

I actually understood what you meant by inverting one of the component of matrix but I don't know how to do that in opentk because modelViewMatrix variable is a Matrix4 struct. This doesn't change anything:

modelViewMatrix.M13 = -modelViewMatrix.M13;

I removed that minus in UnProject function, so now:

zf7bMpq.png

and if I change

mouse.Y = viewport[3] - y;

to

mouse.Y = viewport[3] - y - 130;

then it gets converted almost fine. I've implemented zooming, so when I zoom in the view, I can see that X coord isn't very accurate too.

1ZwrDlI.png

maybe there is another way to convert that?

Also, I forgot to mention that my application is 2D if that makes any sense.

EDIT: it's also possible that unproject function is wrong, I took it from opentk forum written by someone... I see learning opengl is really difficult dry.png.

Game I'm making - GANGFORT, Google Play, iTunes

Finally, I got this fixed. I just changed

mouse.Y = viewport[3] - y;

to

mouse.Y = y + (ClientRectangle.Height - glview.Size.Height);

still not very accurate but not very bad.

Game I'm making - GANGFORT, Google Play, iTunes

Glad you got it fixed. Sorry I couldn't have been more helpful.

Just curious, how "not very accurate is it"? Are you accounting for the window's height and the title bar?

Shogun.

I have implemented zooming, so when I zoom in I see that it isn't very accurate(sometimes dot gets in a right place, sometimes not):

1ZwrDlI.png

When I zoom out, I see it's accurate enough. This is how I implemented zooming:


        // zoom in: zoom *= 2;
        // zoom out: zoom /= 2;
        public void UpdateCameraZoom()
        {
            Matrix4 projection = Matrix4.CreateOrthographic(ClientRectangle.Width * 5 / zoom, ClientRectangle.Height * 5 / zoom, 0.0f, 64.0f);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }

What I did to fix this, I just increased the width and height of projection volume(as you can see I multiply by 5) and increased other objects size(so they won't be so small) :).

Game I'm making - GANGFORT, Google Play, iTunes

This topic is closed to new replies.

Advertisement