Sign in to follow this  
billconan

looking for ray pick samples in c# code

Recommended Posts

billconan    200
hi guys, any pick sample in c#? i don't know how to convert the mouse position according to the window form to the position in the directx scene?

Share this post


Link to post
Share on other sites
matthughson    588
Ray picking is pretty platform independent, so a standard DX one should work, you just need to find the equivilent functions in Managed DX.

There are some great tutorials on the subject out there, but I don't have any of the links on my work comp sorry.

Matt Hughson

Share this post


Link to post
Share on other sites
Armadon    1091
Hi billconan,
How are you doing buddy?

The Problem
Getting mouse coordinates in screen space and then converting them to other spaces.

The Solution
You are totally in luck as I have written a sample that will check mouse coordinates for a given form

Getting mouse coordinates in screen space and validating them

private void ValidateMouseCoordinates(Form window)
{
//Computes the screen space coordinates to client coordinates
cursor = window.PointToClient(Cursor.Position);
if(cursor.X < 0) //if the x position is less than 0. set it to the window width
cursor.X = window.Width;
if(cursor.Y < 0) //if the y position is less than 0. set it to the window height
cursor.Y = window.Height;
}



And then once you have the screen coordinates you can do a number of things with these coordinates.
You can project them to object space using Vector3.Unproject() method.
Or you can check if the mouse intersects with an object. Here is some source code that will help you with that.

Check if mouse ray intersects with object.

//The entity here is just an entity class that I created that stores an entities
//world matrix and mesh objects etc...
public bool Intersect(Microsoft.DirectX.Direct3D.Device device, Entity entity)
{
//intersection information
IntersectInformation closest;
//the near vector
Vector3 near;
//the far vector
Vector3 far;
near = new Vector3(cursor.X, cursor.Y, 0); //the mouse coordinates
far = new Vector3(cursor.X, cursor.Y, 1); //the mouse coordinates

near.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, entity.MatWorld);
far.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, entity.MatWorld);

far.Subtract(near);
if(entity.Mesh.Intersect(near, far, out closest))
return true;
return false;
}



I hope this helps a bit buddy.
Take care and if you have any other questions don't hesitate to ask ok?

Share this post


Link to post
Share on other sites
billconan    200
hi there, thanks a lot.

i've found some code too, in a german site. i cannot read german, but i guess the code works


private static Microsoft.DirectX.Direct3D.Device device;

private static Microsoft.DirectX.Vector3 mouseVector;

private static Microsoft.DirectX.Matrix projMatrix;
private static Microsoft.DirectX.Matrix viewMatrix;

private static Microsoft.DirectX.Vector3 rayDir;
private static Microsoft.DirectX.Vector3 rayOrigin;

private static int width;
private static int height;

private static int posX;
private static int posY;

Funktion:

public static void getRay(Device device, int xPos, int yPos)
{
CMousePicking.device = device;

projMatrix = device.GetTransform(TransformType.Projection);
viewMatrix = device.GetTransform(TransformType.View);
height = device.Viewport.Height;
width = device.Viewport.Width;

posX = xPos;
posY = yPos;

mouseVector.X = ( ( ( 2.0f * posX ) / width ) - 1 ) / projMatrix.M11;
mouseVector.Y = -( ( ( 2.0f * posY ) / height ) - 1 ) / projMatrix.M22;
mouseVector.Z = 1.0f;

Microsoft.DirectX.Matrix invertedViewMatrix = Microsoft.DirectX.Matrix.Invert(viewMatrix);

// Transform the screen space pick ray into 3D space
rayDir.X = mouseVector.X*invertedViewMatrix.M11 + mouseVector.Y*invertedViewMatrix.M21 + mouseVector.Z*invertedViewMatrix.M31;
rayDir.Y = mouseVector.X*invertedViewMatrix.M12 + mouseVector.Y*invertedViewMatrix.M22 + mouseVector.Z*invertedViewMatrix.M32;
rayDir.Z = mouseVector.X*invertedViewMatrix.M13 + mouseVector.Y*invertedViewMatrix.M23 + mouseVector.Z*invertedViewMatrix.M33;

rayOrigin.X = invertedViewMatrix.M41;
rayOrigin.Y = invertedViewMatrix.M42;
rayOrigin.Z = invertedViewMatrix.M43;
}


private static Microsoft.DirectX.Direct3D.Device device;

private static Microsoft.DirectX.Vector3 mouseVector;

private static Microsoft.DirectX.Matrix projMatrix;
private static Microsoft.DirectX.Matrix viewMatrix;

private static Microsoft.DirectX.Vector3 rayDir;
private static Microsoft.DirectX.Vector3 rayOrigin;

private static int width;
private static int height;

private static int posX;
private static int posY;

Funktion:

public static void getRay(Device device, int xPos, int yPos)
{
CMousePicking.device = device;

projMatrix = device.GetTransform(TransformType.Projection);
viewMatrix = device.GetTransform(TransformType.View);
height = device.Viewport.Height;
width = device.Viewport.Width;

posX = xPos;
posY = yPos;

mouseVector.X = ( ( ( 2.0f * posX ) / width ) - 1 ) / projMatrix.M11;
mouseVector.Y = -( ( ( 2.0f * posY ) / height ) - 1 ) / projMatrix.M22;
mouseVector.Z = 1.0f;

Microsoft.DirectX.Matrix invertedViewMatrix = Microsoft.DirectX.Matrix.Invert(viewMatrix);

// Transform the screen space pick ray into 3D space
rayDir.X = mouseVector.X*invertedViewMatrix.M11 + mouseVector.Y*invertedViewMatrix.M21 + mouseVector.Z*invertedViewMatrix.M31;
rayDir.Y = mouseVector.X*invertedViewMatrix.M12 + mouseVector.Y*invertedViewMatrix.M22 + mouseVector.Z*invertedViewMatrix.M32;
rayDir.Z = mouseVector.X*invertedViewMatrix.M13 + mouseVector.Y*invertedViewMatrix.M23 + mouseVector.Z*invertedViewMatrix.M33;

rayOrigin.X = invertedViewMatrix.M41;
rayOrigin.Y = invertedViewMatrix.M42;
rayOrigin.Z = invertedViewMatrix.M43;
}




thank u guys again, i will have a try

Share this post


Link to post
Share on other sites
billconan    200
hello Armadon, i know it may be a stupid question, but what is "entity" you used to test collision. i use my own datastructure, and i convert it to index buffer before rendering, so what should i do.

Share this post


Link to post
Share on other sites
remigius    1172
The entity Armadon is using is probably a class storing a scene object's Mesh and WorldMatrix for rendering and other tasks, like picking. In your case you should probably use the world transform matrix you set before rendering your custom object. For the intersection test, it probably pays off to put your custom data structure in a Mesh object. Check out the How do I create a Mesh paragraph on the Mesh class documentation page if you are unsure how to do this.

Just a quick question here. Armadon's example seems to be translated from a MVP sample, while the german code seems to be translated from Toymaker's article (good short read) on picking. Are they really equivalent, because Armadon's code looks so clean I can't believe that's all there is to it after my wrestling to translate the toymaker codesample :)

Share this post


Link to post
Share on other sites
NovaCaine    158
i agree and can say it does work, i first used toymaker's picking code but now use the directX project/unproject functions. Cant really say which is better but im lazy so i go for the directX ones. :P and i like clean code :D

Share this post


Link to post
Share on other sites
billconan    200
hey, thanks. but is that mean if i wanna adopt the directx's project/unproject function, i need to use the mesh? i think this could be annoying, 'cause my project is kinda like a 3d modeller, so i need to pick up everything in the 3d scene, i mean like, lines, vertices and faces. i just can't convert all this things into directx mesh. any suggestion? thanks!

Share this post


Link to post
Share on other sites
remigius    1172
Well, you only need the Mesh if you want to use the Mesh.Intersect function to do the test, obviously :)

DirectX has some other utility classes to perform intersection tests, like the Plane and most importantly the Geometry class. The latter supports intersection test on triangles, which is the way to go to accurately intersect arbitrary meshes.

That said, as long as you're not working with 'subobjects' (triangles, planes etc), you might do some quick and cheap intersection tests using bounding spheres. The Geometry class allows you to comute such a bounding sphere, but as far as I can tell it only works on non-indexed vertexbuffers... which is quite logical now that I think of it and shouldn't be a problem ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this