Skip to main content
gamedev.net
🔒 Locked

Reverse mouse picking

Started by thatguyfromthething 2 replies 1.6k views
Original Post
thatguyfromthething
thatguyfromthething
I'm making a 3D game with an overhead freeranging camera. I have a method to mouse pick that works correctly, creating a ray for the mouse point then projecting it til it collides with something. I know it works properly because any markers I create show up at the right places.

Several times I've tried to go the other direction, though, and always had problems. Using the rays and camera focus and all that crap is very error prone. I don't even know for sure all of it works correctly in the engine. Most likely it does but there's a chance I am using something wrong or whatever. At any rate, i've given up on the recommended method it just doesn't seem to work.

Instead I want to just compute it using geometry. However, that seems to be failing too, but hopefully it's failing in a way that someone else can point out.

So using that method to project into the game world, I am projecting out from each of the corner mouse positions into the plane where z = 0. That is projecting from 3D perspective to a 2D plane.

From there I take the x and y axes, and call a method to find the closest point on each axis to the reverse pick point. Then I find the distance from the origin and use this to calculate the mouse cursor location for that point. Seems like it should work, but somehow it fails. Does this approach have something wrong with it? If not I guess there can be a bug somewhere else. Now the dummy case should be to project the cursor out to the plane, then project it back but it always fails and I can't see what's wrong. In practice there's a reason for doing this that can't be ignored, though, that's just the test case.

If I print out everything it seems if I project every mouse point to the plane the distances between them are regular and describe lines as I'd expect them to. So it seems like my method should be workable but it completely fails. I know the plane can be skewed but (or so I think) it should not matter.

Here is the code. Maybe something obvious is there? Been screwing with this 14 hours today so at this point a fresh pair of eyes would be helpful.



//first, I have this method which I know works
Point3 CollisionUtil::projectCursorPointToGround(Point screenPoint)


//this method fails
Point CollisionUtil::screenPointForWorldPoint(Point3 worldPoint)
{
Point cursorPoint;

float screenWidth = getDisplayWidth();
float screenHeight = getDisplayHeight();


Point3 last = projectCursorPointToGround(Point(0, 0));

Point3 ul = projectCursorPointToGround(Point(0, 0));
Point3 ur = projectCursorPointToGround(Point(screenWidth, 0));
Point3 ll = projectCursorPointToGround(Point(0, screenHeight));
Point3 lr = projectCursorPointToGround(Point(screenWidth, screenHeight));

Point3 xAxis = ur-ul;
Point3 yAxis = ll-ul;

Point3 pointOnXAxis = closestPointOnLine(worldPoint, ul, ur);
Point3 pointOnYAxis = closestPointOnLine(worldPoint, ul, ll);


Point3 xProjection = pointOnXAxis-ul;
Point3 yProjection = pointOnYAxis-ul;


float xAxisMagnitude = magnitude(xAxis);
float yAxisMagnitude = magnitude(yAxis);

float xRatio = screenWidth/xAxisMagnitude;
float yRatio = screenHeight/yAxisMagnitude;

float xMagnitude = magnitude(xProjection);
float yMagnitude = magnitude(yProjection);

long pointX = round(xMagnitude*xRatio);
long pointY = round(yMagnitude*yRatio);

cursorPoint.x=pointX;
cursorPoint.y=pointY;

return cursorPoint;
}

This is my thread. There are many threads like it, but this one is mine.
thatguyfromthething
thatguyfromthething
It turns out the problem is the step where I adjust the values based on the length of the axes. Of course since the top and the bottom can be different lengths you have to determine the position in Y and the corresponding axis length for the actual axis. A simple error but unfortunately pretty hard to debug.
This is my thread. There are many threads like it, but this one is mine.
Hodgman
Hodgman
If you want to convert a 3d-world position into a 2d-screen position -- your renderer does this for every vertex.

If you can get the view-projection matrix used by your camera, then the code is something likeVec3 worldPos = ...
Vec4 temp( worldPos.x, worldPos.y, worldPos.z, 1.0f );
temp = temp * matViewProjection;//projection
Vec2 results( temp.x, temp.y );
results /= temp.w;//perspective divide
results = results*0.5 + 0.5;//convert to 0,0 -- 1,1 range
thatguyfromthething
thatguyfromthething
Yeah, it should be simple. Unfortunately I have trouble using the scene graph at times. Like if you have getWorldRay it's actually the opposite of world ray, for example. It's probably some simple error or step I'm missing but I can't seem to get a straight answer on the engine's forums and am sick of the same circular conversation about it.

At any rate, this works now, and it's probably faster anyway.
This is my thread. There are many threads like it, but this one is mine.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.