//------------------------------------------------------------------- void ICamera::PickRay(const vector2f& secen, Rayf& out) { //if( m_isChange ) //{ // Update(); //} //http://stackoverflow.com/questions/2093096/implementing-ray-picking //First you need to determine where on the nearplane the mouse click happened: // //rescale the window coordinates (0..640,0..480) to [-1,1], with (-1,-1) at the bottom-left corner and (1,1) at the top-right. //'undo' the projection by multiplying the scaled coordinates by what I call the 'unview' matrix: unview = (P * M).inverse() = M.inverse() * P.inverse(), where M is the ModelView matrix and P is the projection matrix. //Then determine where the camera is in worldspace, and draw a ray starting at the camera and passing through the point you found on the nearplane. // //The camera is at M.inverse().col(4), i.e. the final column of the inverse ModelView matrix. // //Final pseudocode: // //normalised_x = 2 * mouse_x / win_width - 1 //normalised_y = 1 - 2 * mouse_y / win_height //// note the y pos is inverted, so +y is at the top of the screen // //unviewMat = (projectionMat * modelViewMat).inverse() // //near_point = unviewMat * Vec(normalised_x, normalised_y, 0, 1) //camera_pos = ray_origin = modelViewMat.inverse().col(4) //ray_dir = near_point - camera_pos //vector4f ray(secen.m_x, secen.m_y , 1.0 , 1.0 ); ////ray *= (*m_pUnProject);//这两部等效于ray *= ( (*m_pUnProject) * (*m_pUnView) ); ////ray *= (*m_pUnView); //ray *= m_UnViewProject; //ray /= ray.m_w; ////vector4f camera(m_pUnView->a41,m_pUnView->a42,m_pUnView->a43,m_pUnView->a44); ////camera /= camera->m_w; ////ray -= camera; //ray -= vector4f( m_Position ); //vector3f reslut(ray.m_x, ray.m_y, ray.m_z); //reslut.NormalizeSelf(); //out.m_RayOrig = m_Position; //out.m_RayDir = reslut; vector4f rayb(secen.m_x, secen.m_y , 0.0 , 1.0 );//理论上z这个值应该是0,但是这样算出来的Y值偏小和aabb射线拾取不统一,故该做-1,只放大初始位置 vector4f raye(secen.m_x, secen.m_y , 1.0 , 1.0 ); vector4f ray2; rayb *= GetUnViewProj(); ASSERT( 0 != rayb.m_w ); rayb /= rayb.m_w; raye *= GetUnViewProj(); ASSERT( 0 != raye.m_w ); raye /= raye.m_w; ray2 = raye - rayb; vector3f reslut2(ray2.m_x, ray2.m_y, ray2.m_z); reslut2.NormalizeSelf(); out.SetRayOrigin( vector3f(rayb) ); out.SetRayDirection( reslut2 ); }
void Entity::pick(const Rayf& ray, PickResult& pickResults) { float dist = bounds().intersectWithRay(ray, NULL); if (Math<float>::isnan(dist)) return; Vec3f hitPoint = ray.pointAtDistance(dist); EntityHit* hit = new EntityHit(*this, hitPoint, dist); pickResults.add(hit); }
Vec3f Grid::moveDeltaForBounds(const Model::Face& face, const BBoxf& bounds, const BBoxf& worldBounds, const Rayf& ray, const Vec3f& position) const { const Planef dragPlane = Planef::alignedOrthogonalDragPlane(position, face.boundary().normal); const Vec3f halfSize = bounds.size() * 0.5f; float offsetLength = halfSize.dot(dragPlane.normal); if (offsetLength < 0.0f) offsetLength *= -1.0f; const Vec3f offset = dragPlane.normal * offsetLength; const float dist = dragPlane.intersectWithRay(ray); const Vec3f newPos = ray.pointAtDistance(dist); Vec3f delta = moveDeltaForPoint(bounds.center(), worldBounds, newPos - (bounds.center() - offset)); Axis::Type a = dragPlane.normal.firstComponent(); if (dragPlane.normal[a] > 0.0f) delta[a] = position[a] - bounds.min[a]; else delta[a] = position[a] - bounds.max[a]; return delta; }
void Brush::pick(const Rayf& ray, PickResult& pickResults) { float dist = bounds().intersectWithRay(ray, NULL); if (Math<float>::isnan(dist)) return; dist = Math<float>::nan(); Side* side = NULL; for (unsigned int i = 0; i < m_geometry->sides.size() && Math<float>::isnan(dist); i++) { side = m_geometry->sides[i]; dist = side->intersectWithRay(ray); } if (!Math<float>::isnan(dist)) { assert(side != NULL); Vec3f hitPoint = ray.pointAtDistance(dist); FaceHit* hit = new FaceHit(*(side->face), hitPoint, dist); pickResults.add(hit); } }
//------------------------------------------------------------------------------ //! bool BIH::trace( const Rayf& ray, Hit& hit, IntersectFunc intersect, void* data ) const { DBG_BLOCK( os_bih_trace, "BIH::trace(" << ray.origin() << ray.direction() << " hit: t=" << hit._t << " id=" << hit._id << ")" ); if( _nodes.empty() ) { return false; } Vec3f invDir = ray.direction().getInversed(); // Compute traversal order. uint order[3]; order[0] = invDir(0) >= 0.0f ? 0 : 1; order[1] = invDir(1) >= 0.0f ? 0 : 1; order[2] = invDir(2) >= 0.0f ? 0 : 1; float tmin = 0.0f; float tmax = hit._t; bool impact = false; // Traverse tree. Vector<TraversalStackNode> stack( _maxDepth ); uint stackID = 0; const Node* node = &_nodes[0]; while( 1 ) { DBG_MSG( os_bih_trace, "Visiting " << *node ); if( node->isInteriorNode() ) { uint axis = node->axis(); float tplane0 = ( node->_plane[order[axis]] - ray.origin()(axis)) * invDir(axis); float tplane1 = ( node->_plane[1-order[axis]] - ray.origin()(axis)) * invDir(axis); // Clip node. if( node->isClipNode() ) { // FIXME: we could probably do better (not traversing this node). node = &_nodes[node->index()]; tmin = CGM::max( tmin, tplane0 ); tmax = CGM::min( tmax, tplane1 ); continue; } bool traverse0 = tmin < tplane0; bool traverse1 = tmax > tplane1; if( traverse0 ) { if( traverse1 ) { stack[stackID++].set( &_nodes[node->index() + 1-order[axis]], CGM::max( tmin, tplane1 ), tmax ); } node = &_nodes[node->index() + order[axis]]; tmax = CGM::min( tmax, tplane0 ); } else { if( traverse1 ) { node = &_nodes[node->index() + 1-order[axis]]; tmin = CGM::max( tmin, tplane1 ); } else { // Unstack. do { if( stackID == 0 ) { return impact; } stack[--stackID].get( node, tmin, tmax ); tmax = CGM::min( tmax, hit._t ); } while( tmin > tmax ); } } } else { // We are in a leaf node. // Intersects all primitives in it. uint numElems = node->_numElements; uint id = node->index(); for( uint i = 0; i < numElems; ++i, ++id ) { if( intersect( ray, _ids[id], hit._t, data ) ) { impact = true; hit._id = _ids[id]; } } // Unstack. do { if( stackID == 0 ) { return impact; } stack[--stackID].get( node, tmin, tmax ); tmax = CGM::min( tmax, hit._t ); } while( tmin > tmax ); } } }
//------------------------------------------------------------------------------------------------------ SelectableRotatingRing::Selected SelectableRotatingRing::IsSelected( const Rayf& r ) { aabbox3df local = m_BindBox; local.SetCenter( GetWorldPosition() ); m_XBind.SetCenter( GetWorldPosition() ); m_YBind.SetCenter( GetWorldPosition() ); m_ZBind.SetCenter( GetWorldPosition() ); if ( ( local ).Intersection( r ) ) { std::map< float, SelectableRotatingRing::Selected > rm; vector3f point; if(( m_XBind ).IntersectPointWithRay( r, point ) ) rm.insert( std::make_pair( (point - r.GetRayOrigin()).LengthPow(), SR_BY_X_AXIS ) ); if(( m_YBind ).IntersectPointWithRay( r, point ) ) rm.insert( std::make_pair( (point - r.GetRayOrigin()).LengthPow(), SR_BY_Y_AXIS ) ); if(( m_ZBind ).IntersectPointWithRay( r, point ) ) rm.insert( std::make_pair( (point - r.GetRayOrigin()).LengthPow(), SR_BY_Z_AXIS ) ); if ( rm.empty() ) { return SR_NON; } return rm.begin()->second; } return SR_NON; }