MovableObject* CMFCRenderView::pick3D( Real relX, Real relY )
{
// 首先获得从摄像机出发穿过视口上某点的射线
Ray pickRay = mCamera->getCameraToViewportRay( relX, relY );
// 基于刚才的射线创建一个查询
RaySceneQuery* query = mSceneMgr->createRayQuery( pickRay );
// 根据距离排序,只返回最近的一个MovableObject。设定查询掩码,
// 这里的查询掩码是客户程序自己指定的,使用MovableObject的setQueryFlags接口
query->setSortByDistance( true, 1 );
query->setQueryMask( OGRE_HEAD_ENTITY_FLAG );
// 执行查询
RaySceneQueryResult& result = query->execute();
// 因为指定返回最近的MovableObject,只需要判断是否有结果返回即可
MovableObject *closestObject = NULL;
RaySceneQueryResult::iterator rayIterator = result.begin();
if( rayIterator != result.end() )
closestObject = rayIterator->movable;
// 清除查询结果并释放查询对象
query->clearResults( );
mSceneMgr->destroyQuery( query );
// 返回结果
return closestObject;
}
需要注意的是上面代码中的屏幕坐标是normal之后的坐标,范围为[0,1]
RECT clientRect;
GetClientRect( &clientRect );
MovableObject *pickObject = pick3D(
( Real )point.x/( Real )clientRect.right,
( Real )point.y/( Real )clientRect.bottom );
还有个需要注意的是查询的时候指定的掩码,Entity对象(从MovableObject继承)掩码初始化为
0xffffffff, 只要使用任何非0的值去标识某组对象然后查询,都会错误的得到射线上的所有Entity对象!暂时还没有发现办法改变默认值,只能手工将不想查询的对象的queryflag设置为0.
以下演示的是查询与地面的交点增加模型:
代码:
//--------------------------------------------------------------------------------
void CMainView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//get mouse pos and translate
static POINT mousePos;
GetCursorPos(&mousePos);
ScreenToClient(&mousePos);
//get client rect
RECT rect;
GetClientRect(&rect);
Ray mouseRay = m_Camera->getCameraToViewportRay(
mousePos.x/float(rect.right),
mousePos.y/float(rect.bottom));
m_raySceneQuery->setRay(mouseRay);
m_raySceneQuery->setSortByDistance(true);
// Execute query
RaySceneQueryResult &result = m_raySceneQuery->execute();
RaySceneQueryResult::iterator itr;
// Get results, create a node/entity on the position
for ( itr = result.begin(); itr != result.end(); itr++ )
{
if (itr->movable && itr->movable->getName().substr(0, 5) != "tile[")
{
mCurrentObject = itr->movable->getParentSceneNode();
break;
} // if
else if (itr->worldFragment)
{
Entity *ent;
char name[16];
static int mCount=0;
sprintf(name, "Robot%d", mCount++);
ent = m_SceneManager->createEntity(name, "robot.mesh");
mCurrentObject = m_SceneManager->
getRootSceneNode()->createChildSceneNode(
String(name) + "Node", itr->worldFragment->singleIntersection);
mCurrentObject->attachObject(ent);
mCurrentObject->setScale(0.1f, 0.1f, 0.1f);
break;
} // else if
} // for
CView::OnLButtonDown(nFlags, point);
}