Jump to content
  • Advertisement
Sign in to follow this  
pancomplex

Picking with a 2d mouse in a 3d world

This topic is 3666 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello out there! :) My friend and I are currently developing a 3d RTS game in XNA. So far, we've got the camera and some basic stuff going. I have figured out how to make a selection bar with 2d graphics, but my problem starts when I have to figure out how to select units in the 3d world that uses floating points when the mouse spits out x and y integers. What is the most suitable way to accomplish this? Regards, Christian

Share this post


Link to post
Share on other sites
Advertisement
Picking algorithms are fairly common place, albeit I don't know of any XNA specific example code.

Simply put you need to convert your 2D mouse coordinate into a 3D ray - unproject <x,y,0.0> and <x,y,1.0> into world space and you can define a line segment. You then do collision detection along this line with any pickable objects - returning on the first/closest intersection.

By the looks of thing, Viewport.Unproject() is the method you'll be wanting to use.

hth
Jack

Share this post


Link to post
Share on other sites
This is basically what I use for picking in my level editor:


/// <summary>
/// Casts a ray and returns the closest object that the ray intersects
/// (if it intersects one at all)
/// </summary>
/// <param name="x">Normalized screen-space X</param>
/// <param name="y">Normalized screen-space Y</param>
/// <returns>Returns the intersected object if successful, otherwise returns false.</returns>
public GameObject ClickTest(float x, float y)
{
Vector4 positionSS = new Vector4(x, y, 1.0f, 1.0f);
Matrix viewProjMatrix = camera.ViewProjectionMatrix;
Matrix invViewProjMatrix = Matrix.Invert(viewProjMatrix);
Vector4 positionWS = Vector4.Transform(positionSS, invViewProjMatrix);
positionWS = positionWS / positionWS.W;
Vector3 rayWS = new Vector3(positionWS.X, positionWS.Y, positionWS.Z) - renderer.Camera.Position;
rayWS.Normalize();

float maxZ = 0;
GameObject pickedObject = null;

// Check with children first
foreach (GameObject levelNode in levelNodes)
{
foreach (GameObject gameObject in levelNode.Children)
{
CollisionBox box = new CollisionBox(gameObject.Position + gameObject.CollisionBox.min,
gameObject.Position + gameObject.CollisionBox.max);
float tnear, tfar;
if (box.RayIntersect(renderer.Camera.Position, rayWS, out tnear, out tfar) != -1)
{
Vector3 positionVS = Vector3.Transform(gameObject.Position, camera.ViewMatrix);
if ((positionVS.Z > minZ || pickedObject == null) && Math.Abs(positionVS.Z) < camera.FarClip)
{
minZ = positionVS.Z;
pickedObject = gameObject;
}
}
}
}

return pickedObject;
}



As you can see it's bounding box-based...I use Fabio Policarpo's BoxCollider library to handle the intersection of a ray with a box. The math for that is relatively simple though...if you need to see how that's done you can just download the library and have a peek at the source for the CollisionBox class.

Share this post


Link to post
Share on other sites
How exactly does this work? What will I have to plug in to the Unproject in order to do this? And do I want to convert the mouse to 3d cordinates og the 3d cordinates og 2d cordinates?

Edit: I figured it out with the picking tutorial :) thanks a lot everybody!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!