DrGUI 402 Report post Posted November 27, 2006 Hey guys, this question is about ray-picking - I have it working as I have described below but I want an explanation of why Dunlop's method works and mine doesn't if you could... thanks! So at this stage I have converted the screen-space coordinate into a projection-space coordinate. My first approach was to set the ray origin as the camera position and unproject the ray direction from projection space to world-space by multiplying it with the inverse of the view-projection concatenation. The ray origin worked; however, I could not get the ray direction to be directly under the mouse (having drawn a debug line to see where the ray was being projected). I searched for ray picking using Google and found an article by Robert Dunlop, a Microsoft MVP (http://www.mvps.org/directx/articles/improved_ray_picking.htm); the sample code was creating a ray under the mouse position. The difference was in transforming from projection space to view space – I multiplied by the inverse projection while he just divided the point’s (x, y) coordinate by the (1,1) and (2,2) projection matrix elements respectively. He then multiplied the projected point by the inverse of the view matrix, as I did, to give the ray direction. So why does my method not work and how does Dunlop's work? Many thanks guys! 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted November 27, 2006 Personally, I'd recommend sticking with the matrix-based approach. It's more general and will handle different types of projections uniformly.I can't tell you why your implementation of this method isn't working, but concatenation of transforms in an incorrect order is a common error. Are you sure you're combining the view and projection transforms in the right order?Also, the typical 'unprojection' algorithm involves a division by w, so perhaps you're missing that step. 0 Share this post Link to post Share on other sites
mattdev 182 Report post Posted November 28, 2006 Could also be that the direction of your ray is not correct. In case it helps, my code for picking includes something like this:D3DXVECTOR3 inP1(mouseX, mouseY, viewport.MinZ);D3DXVec3Unproject(&outP1, &inP1, &viewport, &projMatrix, &viewMatrix, &worldMatrix);D3DXVECTOR3 inP2(mouseX, mouseY, viewport.MaxZ);D3DXVec3Unproject(&outP2, &inP2, &viewport, &projMatrix, &viewMatrix, &worldMatrix);The ray direction to intersect with geometry is then outP2-outP1. 0 Share this post Link to post Share on other sites
DrGUI 402 Report post Posted November 30, 2006 Thanks guys, I'll try the matrix method again when I can.Quote:...unproject the ray direction from projection space to world-space by multiplying it with the inverse of the view-projection concatenation...I know in normal maths matrices, (MN)^-1 = N^-1 M^-1, but with DX using left-hand matrices, do you think I took the inverse wrongly?Cheers 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted November 30, 2006 Quote:Original post by DrGUIThanks guys, I'll try the matrix method again when I can.Quote:...unproject the ray direction from projection space to world-space by multiplying it with the inverse of the view-projection concatenation...I know in normal maths matrices, (MN)^-1 = N^-1 M^-1, but with DX using left-hand matrices, do you think I took the inverse wrongly?Handedness has nothing to do with it; the issue is whether the matrices are intended for use with row vectors or column vectors.In DX it's the former, so the 'forward' transformation would be:v' = v*V*PTherefore the unprojection transformation would be:v' = v*(V*P)^-1 = v*P^-1*V^-1Where V is the view matrix and P is the projection matrix.Also, doesn't DX already have an 'unproject' function? (I can't remember for sure...) 0 Share this post Link to post Share on other sites
TheAdmiral 1122 Report post Posted November 30, 2006 Quote:Original post by jykAlso, doesn't DX already have an 'unproject' function? (I can't remember for sure...)It certainly does. D3DXVec3Unproject was already mentioned in this thread.RegardsAdmiral 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted November 30, 2006 Quote:Original post by TheAdmiralIt certainly does. D3DXVec3Unproject was already mentioned in this thread.So it was - my apologies. 0 Share this post Link to post Share on other sites
DrGUI 402 Report post Posted December 2, 2006 Thanks guysSo the following was the original code using Dunlop's algorithm:private Vector3 PickRayFromScreen(Vector2 screenCoordinate, Direct3D.Viewport wholeViewport, out Vector3 rayDirection){ //Convert the point's coords from screen space (0 to wholeViewport width/height) to proj space (-1 to 1) Vector3 projPoint = new Vector3((screenCoordinate.X - wholeViewport.X) / wholeViewport.Width * 2 - 1, -((screenCoordinate.Y - wholeViewport.Y) / wholeViewport.Height * 2 - 1), 1); projPoint.X /= m_RenderingCameraProxy.Projection.M11; projPoint.Y /= m_RenderingCameraProxy.Projection.M22; Matrix viewInverse = Matrix.Invert(m_RenderingCameraProxy.View); Vector3 rayOrigin; // Transform the screen space pick ray into 3D space rayDirection.X = projPoint.X * viewInverse.M11 + projPoint.Y * viewInverse.M21 + projPoint.Z * viewInverse.M31; rayDirection.Y = projPoint.X * viewInverse.M12 + projPoint.Y * viewInverse.M22 + projPoint.Z * viewInverse.M32; rayDirection.Z = projPoint.X * viewInverse.M13 + projPoint.Y * viewInverse.M23 + projPoint.Z * viewInverse.M33; rayDirection.Normalize(); rayOrigin.X = viewInverse.M41; rayOrigin.Y = viewInverse.M42; rayOrigin.Z = viewInverse.M43; rayOrigin += rayDirection * m_RenderingCameraProxy.Viewport.CameraProjection.ZNear; return rayOrigin;}but even leaving the ray origin unchanged and at the last minute sayingrayDirection = normalize( point in projection space * (V * P)^-1 )or in coderayDirection = Vector3.TransformNormal(projPoint, Matrix.Invert(Matrix.Multiply(m_RenderingCameraProxy.View, m_RenderingCameraProxy.Projection)));rayDirection.Normalize();seems to make the direction point from the ray origin to (0,0), whichever direction the camera is facing.I'll have a go at Unproject now, but I really wanted to do it myself.Cheers 0 Share this post Link to post Share on other sites
DrGUI 402 Report post Posted December 2, 2006 Unproject works:private Vector3 PickRayFromScreen(Vector2 screenCoordinate, Direct3D.Viewport wholeViewport, out Vector3 rayDirection){ Vector3 rayOrigin = Vector3.Unproject(new Vector3(screenCoordinate.X, screenCoordinate.Y, 0), wholeViewport, m_RenderingCameraProxy.Projection, m_RenderingCameraProxy.View, Matrix.Identity); Vector3 rayEnd = Vector3.Unproject(new Vector3(screenCoordinate.X, screenCoordinate.Y, 1), wholeViewport, m_RenderingCameraProxy.Projection, m_RenderingCameraProxy.View, Matrix.Identity); rayDirection = Vector3.Normalize(rayEnd - rayOrigin); return rayOrigin;}However I would still like to know how it works! 0 Share this post Link to post Share on other sites