Picking Sample

This sample shows how to determine whether a player's cursor is over an object, and how to find out where on the screen an object is.

Sample Overview

There are several situations where it can be useful to know the 3D equivalent of a point on the screen, and vice versa: for example, checking to see whether a player has clicked on an object, or drawing text above a player's head. This can be accomplished by using the Project and Unproject methods on the Viewport class. This sample demonstrates the use of these methods.

In the sample, there is a table with several objects on it. If the user moves the cursor over an object, the object's name is drawn.

Sample Controls

This sample uses the following keyboard and gamepad controls.

Action Windows Phone Windows Windows/Xbox Gamepad
Move the cursor. TAP or DRAG screen Mouse Left thumbstick
Exit the game. BACK ESC or ALT+F4 BACK

 

How the Sample Works

This sample shows how to determine whether a user's cursor is over an object, and how to find out where on the screen an object is. To do this, the sample uses Viewport.Project and Unproject to go between screen space and world space. What are world and screen space?

World space is a simply the coordinate system that your 3D game objects live in. When you move a 3D object from (0,0,0) to (0,0,1), you are changing its position in world space.

Screen space is a coordinate space that closely relates to your game's window, and corresponds to pixels. For example, in this sample, the screen space goes from (0,0) at the upper left of the game window to (853,480) at the lower right of the window. Most 2D games use screen space coordinates.

The Viewport.Project function takes a world space point and tell you where that point will be drawn on the screen. Viewport.Unproject has the opposite effect. It takes a screen space point, and returns a point in world space.

So, now that you understand what world space and screen space are, and how the Project and Unproject functions can convert between them, how can you use that information to tell whether the user's cursor is over an object? If the cursor is in 2D screen space, how can that "intersect" a 3D world space object?

To perform that intersection check, the sample uses Viewport.Unproject to convert two screen space points into world space. The first point is the cursor's position, with a z-value of zero: as close as possible to the camera. The second point is the same thing but with a z-value of one: as far away from the camera as possible. Using those two points, you can create a ray, and then check to see whether world space objects intersect that ray.

 

The ray is checked against the models' bounding spheres, so the result will not be pixel perfect. However, in many cases, this approach will be "good enough."

Going Beyond

It is possible that the ray could intersect multiple models at once. Try to change the code so that only the closest intersection is reported as an intersection. To do this, you'll have to change the RayIntersectsModel function to keep track of the closest collision. You can determine the closest collision by using the result of BoundingSphere.Intersects(Ray) function.