Ray Picking::CalcPickingRay(int x, int y) { float px = 0.0f; float py = 0.0f; D3DVIEWPORT9 vp; d3ddev->GetViewport(&vp); D3DXMATRIX proj; d3ddev->GetTransform(D3DTS_PROJECTION, &proj); px = ((( 2.0f * x) / vp.Width) - 1.0f) / proj(0,0); py = (((-2.0f * y) / vp.Height) + 1.0f) / proj(1,1); Ray ray; ray.origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f); ray.direction = D3DXVECTOR3(px, py, 1.0f); //transform the ray to world space D3DXMATRIX view; d3ddev->GetTransform(D3DTS_VIEW, &view); D3DXMATRIX viewInverse; D3DXMatrixInverse(&viewInverse, 0,&view); TransformRay(&ray, &viewInverse); return ray; }
// // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; case WM_LBUTTONDOWN: // compute the ray in view space given the clicked screen point d3d::Ray ray = CalcPickingRay(LOWORD(lParam), HIWORD(lParam)); // transform the ray to world space D3DXMATRIX view; Device->GetTransform(D3DTS_VIEW, &view); D3DXMATRIX viewInverse; D3DXMatrixInverse(&viewInverse, 0, &view); TransformRay(&ray, &viewInverse); // test for a hit if( RaySphereIntTest(&ray, &BSphere) ) ::MessageBox(0, "Hit!", "HIT", 0); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); }
bool Picking::IsPicked(int x, int y, const BoundingSphere* sphere) { Ray ray; CalculatePickingRay(x, y, &ray); D3DXMATRIX view_matrix, inverse_matrix; m_pDevice->GetTransform(D3DTS_VIEW, &view_matrix); //求出View矩阵的逆矩阵 D3DXMatrixInverse(&inverse_matrix, NULL, &view_matrix); TransformRay(&ray, &inverse_matrix); return Ray_SphereIntersect(&ray, sphere); }
bool Rectangle::Intersect(const Ray &ray, const RayInterval &interval, SurfaceInteraction *const interaction) const { // Compute local ray Ray local_ray = TransformRay(world_to_local, ray); // Check intersection with plane if (std::abs(local_ray.Direction().y()) > 10e-6f) { // Compute intersection with plane float t = -local_ray.Origin().y() * local_ray.InvDirection().y(); // Check boundaries if (interval.Inside(t)) { // Compute intersection point Vector3f hit_p = local_ray(t); // Check hit point inside rectangle if (hit_p.x() > -x_size / 2.f && hit_p.x() < x_size / 2.f && hit_p.z() > -z_size / 2.f && hit_p.z() < z_size / 2.f) { // Fill interaction interaction->hit_point = hit_p; interaction->geom_frame = Frame(Vector3f(1.f, 0.f, 0.f), Vector3f(0.f, 1.f, 0.f), Vector3f(0.f, 0.f, 1.f)); interaction->sh_frame = Frame(Vector3f(1.f, 0.f, 0.f), Vector3f(0.f, 1.f, 0.f), Vector3f(0.f, 0.f, 1.f)); interaction->t = t; interaction->wo = Normalize(-local_ray.Direction()); interaction->uv = Vector2f((hit_p.x() + x_size / 2.f) / x_size, (hit_p.z() + z_size / 2.f) / z_size); interaction->surface = this; // Transform to global space *interaction = TransformInteraction(local_to_world, world_to_local, *interaction); return true; } } } return false; }
bool Rectangle::IntersectP(const Ray &ray, const RayInterval &interval) const { // Compute local ray Ray local_ray = TransformRay(world_to_local, ray); // Check intersection with plane if (std::abs(local_ray.Direction().y()) > EPS) { // Compute intersection with plane float t = -local_ray.Origin().y() * local_ray.InvDirection().y(); // Check boundaries if (interval.Inside(t)) { // Compute intersection point Vector3f hit_p = local_ray(t); // Check hit point inside rectangle if (hit_p.x() > -x_size / 2.f && hit_p.x() < x_size / 2.f && hit_p.z() > -z_size / 2.f && hit_p.z() < z_size / 2.f) { return true; } } } return false; }
LRESULT CALLBACK d3d9::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) DestroyWindow(hWnd); break; case WM_LBUTTONDOWN: { Ray ray; if (CalcPickingRay(LOWORD(lParam), HIWORD(lParam), g_pDevice, &ray)) { D3DXMATRIX view; g_pDevice->GetTransform(D3DTS_VIEW, &view); D3DXMATRIX inverse; float determinant = D3DXMatrixDeterminant(&view); D3DXMatrixInverse(&inverse, &determinant, &view); TransformRay(&ray, &inverse); if (RayHitSephere(&ray, &g_BSephere)) { MessageBox(0, "Hit!", "HIT", 0); } } break; } } return DefWindowProc(hWnd, msg, wParam, lParam); }