Sign in to follow this  
OppiXP

[SlimDX] Picking a point on a plane

Recommended Posts

OppiXP    105
Hello guys, I am stuck on picking a certain point on a plane which is located anywhere on the z axis of my coordinate system. The coordinate system can be zoomed and rotated by using my chase camera. Here is what it looks like: Coordinate system The problem is that my coordinates seem to be messed up and I cannot figure out why. The camera is rotated and zoomed by setting up the projection and view matrices in this way:

projectionMatrix = Matrix.PerspectiveFovLH(
             (float)Math.PI / 4,
             (float)ClientRect.Width / ClientRect.Height,
             0.001f,
             20f);

Matrix trans = Matrix.Translation(0.0f, 0.0f, camDistance);
Matrix rot = Matrix.Multiply(Matrix.RotationY(camAngleHorizontal), Matrix.Identity);
rot = Matrix.Multiply(Matrix.RotationX(camAngleVertical), rot);
viewMatrix = Matrix.Multiply(trans, rot);
viewMatrix = Matrix.Invert(viewMatrix);



Rotating the camera around my coordinate system works fine. I use this code to determine if a ray intersects a certain plane:

protected override void MouseMove(System.Windows.Forms.MouseEventArgs e)
{
  base.MouseMove(e);
  Plane plane = new Plane(new Vector3(1f, 0, 0), 0);
 
  DX.Instance.SetWorldMatrix(Matrix.Identity, Matrix.Identity);

  Vector3 nearPlane = Vector3.Unproject(new Vector3((float)e.X, (float)e.Y, currentCamDistance), DX.Instance.ViewPort, DX.Instance.CurrentProjectionMatrix, DX.Instance.CurrentViewMatrix, DX.Instance.CurrentWorldMatrix);

  Vector3 farPlane = Vector3.Unproject(new Vector3((float)e.X, (float)e.Y,  20f), DX.Instance.ViewPort, DX.Instance.CurrentProjectionMatrix, DX.Instance.CurrentViewMatrix, DX.Instance.CurrentWorldMatrix);

  Vector3 direction = farPlane - nearPlane;
  direction.Normalize();

  Ray ray = new Ray(nearPlane, direction);
  float distance;

  Console.WriteLine(Ray.Intersects(ray, plane, out distance));
}



Sometimes it seems that the plane is located flat in the upper right corner of the screen... Can please anybody have a look at this and tell me what is wrong? I also tried intersection using a BoundingBox: BoundingBox box = new BoundingBox(new Vector3(0), new Vector3(1)); It seems that the coordinates are not translated correctly. Any help is appreciated! Best Regards OppiXP

Share this post


Link to post
Share on other sites
OppiXP    105
Hello Buckeye,

thanks for your reply. I tried this but it was not successful. The bounding box still seems to be somewhere on the screen but not where I expect it to be.

Are BoundingBoxes located in Worldspace?

Regards

OppiXP

Share this post


Link to post
Share on other sites
Buckeye    10747
Quote:
I tried this but it was not successful..The bounding box still seems to be somewhere on the screen but not where I expect it to be.

That's not much info to help you with. You haven't posted any code for whatever you're doing with a bounding box, what you expect or what values you're getting.

It sounds like you need to take one step at a time. Pick one of your problems and work on it.

For instance, orient the camera such that your world origin is in the center of the screen (or close). If you unproject the coordinates for the center of the screen, is your camera position + camera-distance*ray-direction close to (0,0,0)?
Quote:
Are BoundingBoxes located in Worldspace?

A BoundingBox is just a structure. It can be used as you see fit.

Share this post


Link to post
Share on other sites
OppiXP    105
Hi,

maybe I tell you what I want to achieve. The problem is that I have no idea how to make this work correctly.

I am currently working on a 3D view of some measuring data. The user can rotate the camera around the signals and he can change the distance of the camera to the signals. The world's center remains at (0,0,0), only the camera is moved around using the code I posted above. So the camera always looks at (0,0,0) with varying distance. The signals are rendered as linestrips at certain z-positions. The world coordinates never exceed -1 and 1 in any direction. This part works perfectly already. Only one signal can be selected at any time.

The user should now be able to place some markers on the samples of this signal using the mouse as illustrated in the image below:



The code for picking mentioned earlier does not work correctly and I do not understand why. See the near vector: It always returns values between -0.5 and 0.5 regardless how far away the camera is located from the origin. If the camera was moved 5 units back from the center I would assume X coordinates ranging from -5 to 5 when moving the mouse to the left and right edge of the screen and the camera was not rotated around the signals.

If this worked the next idea would be to place a plane at the z position of the selected signal spanning the whole x and y axis and then cast a ray for intersection test with that plane. Is it possible to determine where exactly a ray hit a plane?

Any help is appreciated as I am really stuck on this.

Best regards






Share this post


Link to post
Share on other sites
Buckeye    10747
Quote:
See the near vector: It always returns values between -0.5 and 0.5 regardless .. of the camera position

Are you using (mouseX, mouseY, 0) and (mouseX, mouseY, 1) to unproject the mouse position and get the direction vector?

Also, are you trying to intersect the z-plane? Is so, shouldn't your plane be [(0,0,-1),0]? I'm assuming positive Z looking into the screen in your image. In any case, you can calculate the intersection without that.

Once you get that straightened out, then you can find the point in the plane (this is off the top of my head):

dir = far-near

You want: point(someX, someY, 0) = near+dir*D (a point in the vector under the mouse)

D is some unknown distance from the near plane. You know you want a point for which Z=0.

point = (nearX+dirX*D, nearY+dirY*D, nearZ+dirZ*D)

So nearZ + dirZ*D = 0, or D = -nearZ/dirZ

Substitute D back in nearX+dirX*D, etc. to get the point in the plane.

Share this post


Link to post
Share on other sites
Monza    140
Seems to me to pick a data point, you may be best running a function which finds the closest 3D data point to the 3D mouse ray line segment (line between back and front of screen) at the XY mouse point.

Anyway, if you want a plane intersection,

Define your Slimdx plane [VB.NET]

' define point on plane, and set the up direction
Dim cPlane As Plane = New Plane(New Vector3(X,Y,Z), New Vector3(0, 0, 1))

Unproject the mouse X Y point at the near V3Near and far plane V3Far on the screen. AS Buckeye quotes us "Try unprojecting (x,y,0) for the near plane and (x,y,1) for the far plane"

and then use the following slimdx function.

'find intersection of line and plane
Plane.Intersects(cPlane, v3Near, v3Far, intersectionPoint)

End Function

Share this post


Link to post
Share on other sites
OppiXP    105
Hey guys,

thanks for your help! I really appreciate it!

I tried Buckeyes hint but again no luck. This is what I have so far:



// The size of the coordinate system was doubled before so I set the world matrix accordingly. The coordinate sytem is now centered.

DX.Instance.SetWorldMatrix(Matrix.Scaling(2f, 2f, 2f), Matrix.Translation(-1, -1, -1));

// Unproject near plane
Vector3 nearPlane = Vector3.Unproject(new Vector3(e.X, e.Y, 0), DX.Instance.ViewPort, DX.Instance.CurrentProjectionMatrix, DX.Instance.CurrentViewMatrix, DX.Instance.CurrentWorldMatrix);

// Unproject far plane
Vector3 farPlane = Vector3.Unproject(new Vector3(e.X, e.Y, 1), DX.Instance.ViewPort, DX.Instance.CurrentProjectionMatrix, DX.Instance.CurrentViewMatrix, DX.Instance.CurrentWorldMatrix);

Vector3 direction = farPlane - nearPlane;
direction.Normalize();

position = new Vector3(
nearPlane.X + direction.X * (-nearPlane.Z / direction.Z),
nearPlane.Y + direction.Y * (-nearPlane.Z / direction.Z),
nearPlane.Z + direction.Z * (-nearPlane.Z / direction.Z));

Console.WriteLine(position);





It seems that the distance and angle of the camera is not taken into account.

If I understand this correctly the position vector should return values at z = 0 which is the center of the coordinate system. So if I move the mouse pointer left and right at this z position with camera angles all zero, position.X should return -1 if I hit the left boundary and 1 if I hit the right boundary but I get values ranging from 0.64 to 0.3.

I think we are getting close but there is still something I did wrong...

The other approach using the plane does not work either.

Regards

OppiXP

[Edited by - OppiXP on February 11, 2010 8:21:49 AM]

Share this post


Link to post
Share on other sites
Buckeye    10747
Quote:
It seems that the distance and angle of the camera is not taken into account.

Hmm. That should be taken care of in the Unproject call using the current matrices. Do you set those before you do the Unproject? And do you use the same world matrix to render the data?

You should have something like:

GetUserData (mouse-click)
SetProjection and World matrix.
CalcClickPosition.
Render data and click position

Share this post


Link to post
Share on other sites
OppiXP    105
Yes, the view and projection matrices are always stored in my DX singleton as you can see references to it in my code. The world matrix is set explicitely before unprojecting and has the same scale and translation factors used during rendering the axes. Funny thing though if I assign the identity matrix to the view and projection matrices the coordinates are correct, ranging from -1 to 1 in either x and y direction. Maybe there is something wrong in the unproject method in SlimDX?

I have no clue what is going wrong. As far as I understand the whole unproject thing should return coordinates from -1 to 1 as long as I stay inside the "cube" of my coordinate system.

This drives me nuts as I have tried at least 5 different tutorials I found and none of them worked.

Could it be a problem that the distance of the camera to the coordinate system is always negative? The range is from -19 to -1. Maybe the calculation of the view matrix is not correct. Could you please have a look at it?

Many thanks in advance!!!

Share this post


Link to post
Share on other sites
Buckeye    10747
Quote:
As far as I understand the whole unproject thing should return coordinates from -1 to 1 as long as I stay inside the "cube" of my coordinate system.

If you're looking for a range of -1 to 1, it sounds like you're talking about view-projection space. Unproject will return world-space coordinates.

WRT the viewmatrix, you might try using the standard D3DXMatrixLookAtLH (or the SlimDX equivalent).

Just for fun, to see if things make sense, when you calculate the intersect position, turn right around and Project that point using the same parameters and see if you get the mouse position.

Share this post


Link to post
Share on other sites
OppiXP    105
That's it!!! Man! If I use Matrix.LookAtLH the whole thing works perfectly.

The next question is how can I rotate the eye vector around (0,0,0) in x and y directions with varying distance?

Share this post


Link to post
Share on other sites
Buckeye    10747
Quote:
how can I rotate the eye vector around (0,0,0) in x and y directions with varying distance?

Are you trying to allow the camera to be translated and rotated?

Share this post


Link to post
Share on other sites
OppiXP    105
Quote:
Are you trying to allow the camera to be translated and rotated?


Basically I'd like the eye vector to be located on the hull of a sphere whilst looking to the center of the sphere. By using the mouse wheel the user can change the distance to the center and by moving the mouse up/down and left/right the horizontal and vertical position on the hull.

The calculation of the view matrix did that fine but obviously screwed up a few things. Could you please give me a hint how I can move the eye vector the way I explained?

Thank you very much!

Share this post


Link to post
Share on other sites
Buckeye    10747
A simple approach would be to initialize the cameraDistance, the sphere position, the camera up vector and the camera direction to the center of the sphere.

The mousewheel just changes the distance.

For left/right:

orthoVector = Normalize(CrossProduct(dir,up));
// you may have to swap right and left to make it move correctly
if(moves right) cameraDir += smallIncrement*orthoVector;
else cameraDir -= smallIncrement*orthoVector;
Normalize(cameraDir);
cameraPosition = spherePosition * cameraDistance*cameraDir;

For up/down

if( forward ) cameraUp += smallIncrement*cameraDir;
else cameraUp -= smallIncrement*cameraDir;
Normalize(cameraUp);

LookAtLH(cameraPosition, cameraPosition+cameraDir, cameraUp,...)

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