How to unproject the center coordinate of my screen to world space?(and why do I need to do that at all? )

Started by
10 comments, last by SeanMiddleditch 7 years, 4 months ago

Guys, I use basic ray casting in order to detect whether I've shot somebody in my first person shooter. But I found out that when I'm really close to the enemy, there are some small inaccuracies ( my crosshair is on the enemy, but there is no collision between the ray and the AABB ).

My first step was to actually draw the AABB, and draw the ray that I'm casting on screen in order to try and debug. And to my surprise, the AABB was perfectly fine, but the ray was totally wrong because it doesn't even start from the center of my screen, it starts from some bullsh*t place somewhere around my camera, although I used the camera's position as a startPoint of the ray.

Either I'm crazy or the camera position in world space and the center of the screen seem to be two completely different things. I have no idea wtf is happening here. SOMEONE HEEELP!

Advertisement
The camera position and the center of the screen are naturally separate places. That's what the "near" value in your projection matrix is for: the distance from the camera to the plane of projection along the view vector.

You're working with a 3D projection. The camera and plane of projection forms a pyramid. Consider i1LDS.png. The plane is the screen and the origin of the rays is the camera position.

That said, you've described very little useful information about your actual problem. The camera location may not really be a problem. Generally the correct way to cast this ray is to start it at the camera position and cast it in the direction of the cross hair, which may not be the same as the camera view direction for off center cross hairs.

So far as the unprojection, you might find guides like http://www.toymaker.info/Games/html/picking.html helpful. (I'm honestly having trouble finding a clear explanation; the Web is saturated these days with tutorials on using engine's builtin screen-to-world functions and few guides on the math. The gist is use the inverse of the projection matrix to convert a coordinate of <x, y, near> in NDC coordinates to world space.)

Sean Middleditch – Game Systems Engineer – Join my team!

Generally the correct way to cast this ray is to start it at the camera position and cast it in the direction of the cross hair, which may not be the same as the camera view direction for off center cross hairs.

Sean, my crosshair is exactly on the center of the screen. I cast the ray from the camera position and it's inaccurate, I'm not sure that this is the correct way, maybe because I did something wrong.

I think I did something very wrong, because your explanation doesn't apply to my case.

EDIT: You were right, casting from camera position works. I can theoretically get the x and y coordinates of the middle pixel and normalize it openGL screen coordinates and then use all the inverse matrices to unproject it to world space. But actually I don't need that at all. I can just use the camera position. I don't understand why it didn' t work yesterday, but maybe I forgot to put the matrices in the shader or something like that.

Nevermind, thanks for the explanation, and the nice picture.

If it doesn't work, and you don't understand how or why, your setup is too complicated. Simplify it. remove useless clutter, move things to known positions, use known orientations, etc.

Strip the problem until you can do the calculations yourself, and compare those with the computer results. There must be a difference somewhere.

Haha, that's exactly what I did. You probably won't believe me, but I was in a mood for debugging.

I decided to spend some time to make a DebugDraw class that can draw some points for me on the screen. Then I declared it global, so I can use all variables(coordinates) from all objects and just put them into the global debugDraw object, and then draw whatever points I want in whatever order on the screen.

Then I created a Spectator class that basically works as a spectator in counter-strike. I can just fly around the world with w,a,s,d and look at everything from different sides. And it fixed the problem, it was a really stupid problem, I put all my matrices in the shader before assigning them the new values and I fixed it now, thanks guys.

Random question: Guys, is the thing I use called raycasting?

What I do is to cast a line with length 100.0f and then I just calculate at what point the line collided with some plane.

And if this is raycasting, then it's not at all as hard as people say. Is this how people make global illumination algorithms, just casting a ray and calculating the reflection? I can even use it for making line of sight for the enemies, if it's dark, for example.

If this is raycasting, either I'm doing some very basic stuff, or the term is overrated.

Haha, that's exactly what I did. You probably won't believe me, but I was in a mood for debugging.

Now you're making me curious, is there any reason why I should not believe you? :D

Sounds like a good solution for debugging, I must remember that when I need to debug something 3D-ish. I only recently started using OpenGL, and the scene is just mostly a flat surface so far, I haven't got myself into deep enough trouble yet to have to debug like what you did.

it was a really stupid problem, I put all my matrices in the shader before assigning them the new values

Yet another form of "save your files before a compile" case

Glad you figured it out, and it turned out to be a simple problem.

What I do is to cast a line with length 100.0f and then I just calculate at what point the line collided with some plane

Don't know exactly, but it sounds like ray-casting to me.

Your "just" is not so "just" for many. If you hate math, don't understand matrices, or have trouble envision how it works in 3 dimensions, ray-casting becomes a dark art quite quickly.

Imagine you copy/pasted the code from somewhere without understanding how it works, and it fails. Trial and error fixing doesn't work, as the individual numbers have no meaning. You can spend days trying to make it work, but without deeper understanding of it, the only possible outcome is failure, which is then blamed on complexity of ray-casting.

Yet another form of "save your files before a compile" case

It wasn't in the shader file(although I've done that too ), it was the function that puts the matrices from the cpu to the gpu. Basically i first put them in the gpu, and them assign them, and I think it's changed but it's not: ( or when I forgot to say what shader I use and I assign to a shader and it doesn't work, need to keep eye on the states, because opengl works like that. )

But basically what I did was:

int number = 2;

//some code

shader.get( number ); //send to gpu

number = 5;

And I'm thinking the shader has the number 5 until 4 A.M yesterday.

What I do is to cast a line with length 100.0f and then I just calculate at what point the line collided with some plane

Don't know exactly, but it sounds like ray-casting to me.

Your "just" is not so "just" for many. If you hate math, don't understand matrices, or have trouble envision how it works in 3 dimensions, ray-casting becomes a dark art quite quickly.

Imagine you copy/pasted the code from somewhere without understanding how it works, and it fails. Trial and error fixing doesn't work, as the individual numbers have no meaning. You can spend days trying to make it work, but without deeper understanding of it, the only possible outcome is failure, which is then blamed on complexity of ray-casting.

True.

EDIT: There were 2 problems, guys, not one.

When I translate an object, I need to multiply the object vertices by some translation matrix in order to get them in world space right? What I did was that I multiplied the plane normal by that same translation matrix. And them from vecNormal( 1.0f, 0.0f, 0.0f ) I get something like ( 0.5312, 0.0f, -0.8621 ). And this is why the AABB was drawn correctly on screen, but it didn't work. Stupid normals. And I actually remember fixing that 2 months ago, but then I messed up my code really hard and had to use a backup code, and I forgot that this error wasn't fixed in the back up code and spend even more amount of time to fix it again, 2 months later. And I just got reminded of that when I already fixed it...brain problems.

But basically what I did was: int number = 2; //some code shader.get( number ); //send to gpu number = 5;


It's usually a good idea to always declare your variables as const unless you absolutely need them to be mutable. (There's a ton of other benefits, too.)

Sean Middleditch – Game Systems Engineer – Join my team!

shader.get( number ); //send to gpu

Ah magic numbers eh?

Why don't you use an enum to translate the numbers to names, so you have nice readable names everywhere else?

And I actually remember fixing that 2 months ago, but then I messed up my code really hard and had to use a backup code, and I forgot that this error wasn't fixed in the back up code and spend even more amount of time to fix it again, 2 months later. And I just got reminded of that when I already fixed it...brain problems.

Instead of backup code, use a version control system (VCS), where you can save every little change, and it keeps all history for you.

In addition you can go back to any point in the past, or browse changes, or revert bad changes, or ...

It also supports co-operation between team members, where it handles synchronizing changes between all team members.

The popular VCS nowadays is Git, not in the last place due to Github, a git-project hosting site. Plain git is somewhat of a pain to work with if you don't understand how it works. There are also Guis for Git, never used them for real work (they seem to be too primitive), but it may work for you. Also, many development IDEs have git support.

Alternative VCSes are Mercurial (also known as hg), or Subversion (svn). Svn is the simpler solution, but only works in situations where everybody in the project has access to the same machine (with svn on it). hg and git are more comparable, but hg focuses more on the user interaction. It is easier to work with from the command-line. TortoiseHg (a hg Gui frontend) is awesome too, although I mostly use it for browsing and searching history.

Haha, I just gave an example with the word "number", actually that was the MVP matrix. :D

Yes, version control is on my list, but last time I checked I had to pay in order to have a private project and I kind of didn't like it, that's why I don't use it. Need to check again if some guys offer free private projects. Thanks for the suggestion.

This topic is closed to new replies.

Advertisement