Point2f Universe::ConstructCameraRay( Point2f click, Point3f *rayOriginOut, Point3f *rayDirectionOut )
{
XMFLOAT4X4 projectionLeft, inverseCamera;
Point3f direction;
assert( rayOriginOut != NULL );
assert( rayDirectionOut != NULL );
float px, py;
// Set mouse coordinates to range ( -1.0f to 1.0f, 1.0f to -1.0f )
px = (( 2.0f * click.x) / projection.ScreenPixelsWidth()) - 1.0f;
py = ((( 2.0f * click.y) / projection.ScreenPixelsHeight()) - 1.0f) * -1.0f;
Point3f mouseClickNear( px, py, 0.0f );
Point3f mouseClickFar( px, py, 1.0f );
XMVECTOR mouseClickVec, unprojected;
mouseClickVec = mouseClickNear;
unprojected = DirectX::XMVector3Unproject(
mouseClickVec,
0.0f, 0.0f, projection.ScreenPixelsWidth(), projection.ScreenPixelsHeight(),
0.0f, 1.0f,
projection[0], camera, XMMatrixIdentity()
);
Point3f unprojectedClickNear( unprojected );
mouseClickVec = mouseClickFar;
unprojected = DirectX::XMVector3Unproject(
mouseClickVec,
0.0f, 0.0f, projection.ScreenPixelsWidth(), projection.ScreenPixelsHeight(),
0.0f, 1.0f,
projection[0], camera, XMMatrixIdentity()
);
Point3f unprojectedClickFar( unprojected );
direction = Point3f( mouseClickNear ) - Point3f( mouseClickFar );
*rayOriginOut = mouseClickNear;
*rayDirectionOut = direction.Normalize();
return Point2f( px, py );
}
bool Universe::PickTest( Point3f rayOrigin, Point3f rayDirection, Point3f planeOrigin, Point2f planeSize, Point3f *intersectionPosition )
{
// Used http://www.rastertek.com/dx11tut47.html as reference
XMFLOAT4X4 inverseModel;
XMFLOAT3 origin, direction;
Point3f planeNormal, rayHit;
planeNormal = Point3f( 0.0f, 0.0f, -1.0f );
float halfWidth = (planeSize.x / 2.0f);
float halfHeight = (planeSize.y / 2.0f);
Point3f points[4] = { // Clockwise, start@top left
Point3f( planeOrigin.x - halfWidth, planeOrigin.y - halfHeight, planeOrigin.z ),
Point3f( planeOrigin.x + halfWidth, planeOrigin.y - halfHeight, planeOrigin.z ),
Point3f( planeOrigin.x + halfWidth, planeOrigin.y + halfHeight, planeOrigin.z ),
Point3f( planeOrigin.x - halfWidth, planeOrigin.y + halfHeight, planeOrigin.z )
};
unsigned int triangle[2][3] = {
{ 0, 1, 2 },
{ 0, 2, 3 }
};
int intersects = -1;
for( unsigned int t=0; t < 2; t++ )
{
if ( intersects != -1 ) break;
Point3f e1 = points[ triangle[t][1] ] - points[ triangle[t][0] ];
Point3f e2 = points[ triangle[t][2] ] - points[ triangle[t][0] ];
Point3f s1 = rayDirection.Cross( e2 );
float div = e1.Dot( s1 );
if ( (div > -0.00001f) && (div < 0.00001f) )
continue;
float invDiv = 1.0f / div;
Point3f d = rayOrigin - points[ triangle[t][0] ];
float b1 = invDiv * d.Dot( s1 );
if ( ( b1 < 0.0f ) || ( b1 > 1.0f ) )
continue;
Point3f s2 = d.Cross( e1 );
float b2 = invDiv * rayDirection.Dot( s2 );
if ( ( b2 < 0.0f ) || ( b1 + b2 > 1.0f ) )
continue;
float z = e2.Dot( s2 ) * invDiv;
rayHit = rayOrigin + (rayDirection * z );
intersects = t;
}
if ( intersects == -1 )
return false;
float ix = XMVectorGetX( rayHit ), iy = XMVectorGetY( rayHit );
if ( (ix >= XMVectorGetX( points[0] )) && (ix <= XMVectorGetX( points[1] )) )
{
if ( (iy >= XMVectorGetY( points[1] )) && (iy <= XMVectorGetY( points[3] )) )
{
if ( intersectionPosition != NULL )
{
// Convert to top-left (0,0)
intersectionPosition->x = ix;
intersectionPosition->y = iy;
intersectionPosition->z = XMVectorGetZ( rayHit );
}
return true;
}
}
return false;
}
The series of billboards are laid on top of each other, and here is a mini-ASCII visualization of what the scene looks like:[camera]< ||||||||
Where '|' are the billboards, each with transparent regions. The camera is at a fixed distance and angle (always looking directly at the billboards).
Bigger Edit/Clarifications: The code above does not work. I want to get the point of intersection of a ray to a plane, then test to see if the point of intersection is within a rectangle. Currently, my code does tell me that I am intersecting (however, I am unsure if it does so by accident, or if it's actually correct), but seems to consistently give me strange intersecting coordinates.
My testing planes are all 9600x1080, in between z 0.0f and -100.0f.
My camera pans from left to right of these giant planes, and when the mouse clicks, it should be calculating a ray based on that click, and I find the collision of the ray and each plane. Another section of my code take the intersection and finds whether or not the intersection took place within a given rectangular region, and if so, checks the texture to see if that point is transparent. If it's transparent, it proceeds to check then next furthest plane layer, and if it is not transparent, I check to see if the plane is clickable (only certain planes are) and then proceed with other tasks in the program.
Does anyone have a correction to my code, or a good tutorial on directx 11.1 picking?