bool
GraphicalWorld::pickPoint(
const
Ray
&
ray, Vector3
&
hitpoint,
const
WS::StringVector
&
excludeobjects, Real max_distance
/*
= 9999.0f
*/
, uint32 mask
/*
= 0xFFFFFFFF
*/
)
{
WS_ASSERT( msCore );
// const unsigned long mask = 0xFFFFFFFF;
Ogre::Vector3 pOrigin = VEC_WS2OGRE(ray.getOrigin());
Ogre::Vector3 pDirection = VEC_WS2OGRE(ray.getDirection());
Ogre::Ray ogreRay(pOrigin, pDirection);
if ( ! mpRaySceneQuery)
{
mpRaySceneQuery = msCore -> getSceneMgr() -> createRayQuery( ogreRay, mask );
}
else
{
mpRaySceneQuery -> setRay(ogreRay );
mpRaySceneQuery -> setQueryMask(mask);
}
mpRaySceneQuery -> setSortByDistance( true );
if (mpRaySceneQuery -> execute().size() <= 0 ) return ( false );
// at this point we have raycast to a series of different objects bounding boxes.
// we need to test these different objects to see which is the first polygon hit.
// there are some minor optimizations (distance based) that mean we wont have to
// check all of the objects most of the time, but the worst case scenario is that
// we need to test every triangle of every object.
Ogre::Real closest_distance = max_distance;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult & query_result = mpRaySceneQuery -> getLastResults();
Ogre::MovableObject * movable;
for (size_t qr_idx = 0 ; qr_idx < query_result.size(); qr_idx ++ )
{
// stop checking if we have found a raycast hit that is closer
// than all remaining entities
if ((closest_distance >= 0.0f ) && (closest_distance < query_result[qr_idx].distance))
{
break ;
}
movable = query_result[qr_idx].movable;
// only check this result if its a hit against an entity
if ((query_result[qr_idx].movable != NULL) && (query_result[qr_idx].movable -> getMovableType().compare( " Entity " ) == 0 ) && movable -> isVisible())
{
Ogre::Entity * pOgreEntity = static_cast < Ogre::Entity *> (movable);
EntityMap::const_iterator itFind = mEntityMap.find(pOgreEntity);
if (itFind == mEntityMap.end())
continue ;
// get the entity to check
graphics::IEntity * pEntity = itFind -> second;
const String & pname = pEntity -> getPoolableObjectID();
bool foundinlist = false ;
for (unsigned int lit = 0 ;lit < excludeobjects.size();lit ++ )
{
if (excludeobjects[lit] == pname)
{
foundinlist = true ;
break ;
}
}
if (foundinlist) continue ;
// parentOrientation * (parentScale * mPosition)
std::pair < bool , Ogre::Real > hit = HitMesh(ogreRay, pOgreEntity);
// if it was a hit check if its the closest
if ( ! hit.first) continue ;
bool new_closest_found = false ;
if ((closest_distance < 0.0f ) || (hit.second < closest_distance))
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true ;
}
// if we found a new closest raycast for this object, update the
// closest_result before moving on to the next object.
if (new_closest_found)
{
closest_result = ogreRay.getPoint(closest_distance);
}
}
}
// return the result
if (closest_distance != max_distance)
{
hitpoint = VEC_OGRE2WS(closest_result);
return true ;
}
else
{
return false ;
}
}
{
WS_ASSERT( msCore );
// const unsigned long mask = 0xFFFFFFFF;
Ogre::Vector3 pOrigin = VEC_WS2OGRE(ray.getOrigin());
Ogre::Vector3 pDirection = VEC_WS2OGRE(ray.getDirection());
Ogre::Ray ogreRay(pOrigin, pDirection);
if ( ! mpRaySceneQuery)
{
mpRaySceneQuery = msCore -> getSceneMgr() -> createRayQuery( ogreRay, mask );
}
else
{
mpRaySceneQuery -> setRay(ogreRay );
mpRaySceneQuery -> setQueryMask(mask);
}
mpRaySceneQuery -> setSortByDistance( true );
if (mpRaySceneQuery -> execute().size() <= 0 ) return ( false );
// at this point we have raycast to a series of different objects bounding boxes.
// we need to test these different objects to see which is the first polygon hit.
// there are some minor optimizations (distance based) that mean we wont have to
// check all of the objects most of the time, but the worst case scenario is that
// we need to test every triangle of every object.
Ogre::Real closest_distance = max_distance;
Ogre::Vector3 closest_result;
Ogre::RaySceneQueryResult & query_result = mpRaySceneQuery -> getLastResults();
Ogre::MovableObject * movable;
for (size_t qr_idx = 0 ; qr_idx < query_result.size(); qr_idx ++ )
{
// stop checking if we have found a raycast hit that is closer
// than all remaining entities
if ((closest_distance >= 0.0f ) && (closest_distance < query_result[qr_idx].distance))
{
break ;
}
movable = query_result[qr_idx].movable;
// only check this result if its a hit against an entity
if ((query_result[qr_idx].movable != NULL) && (query_result[qr_idx].movable -> getMovableType().compare( " Entity " ) == 0 ) && movable -> isVisible())
{
Ogre::Entity * pOgreEntity = static_cast < Ogre::Entity *> (movable);
EntityMap::const_iterator itFind = mEntityMap.find(pOgreEntity);
if (itFind == mEntityMap.end())
continue ;
// get the entity to check
graphics::IEntity * pEntity = itFind -> second;
const String & pname = pEntity -> getPoolableObjectID();
bool foundinlist = false ;
for (unsigned int lit = 0 ;lit < excludeobjects.size();lit ++ )
{
if (excludeobjects[lit] == pname)
{
foundinlist = true ;
break ;
}
}
if (foundinlist) continue ;
// parentOrientation * (parentScale * mPosition)
std::pair < bool , Ogre::Real > hit = HitMesh(ogreRay, pOgreEntity);
// if it was a hit check if its the closest
if ( ! hit.first) continue ;
bool new_closest_found = false ;
if ((closest_distance < 0.0f ) || (hit.second < closest_distance))
{
// this is the closest so far, save it off
closest_distance = hit.second;
new_closest_found = true ;
}
// if we found a new closest raycast for this object, update the
// closest_result before moving on to the next object.
if (new_closest_found)
{
closest_result = ogreRay.getPoint(closest_distance);
}
}
}
// return the result
if (closest_distance != max_distance)
{
hitpoint = VEC_OGRE2WS(closest_result);
return true ;
}
else
{
return false ;
}
}
拾取Mesh
std::pair
<
bool
, Real
>
GraphicalWorld::HitMesh(
const
Ogre::Ray
&
ray,Ogre::Entity
*
entity)
{
// parentOrientation * (parentScale * mPosition)
Ogre::Vector3 pPostion = entity -> getParentNode() -> _getDerivedPosition();
Ogre::Vector3 pScale = entity -> getParentNode() -> _getDerivedScale();
Ogre::Quaternion q = entity -> getParentNode() -> _getDerivedOrientation();
Ogre::Ray localRay(q.Inverse() * (ray.getOrigin() - pPostion) / pScale,(q.Inverse() * ray.getDirection() / pScale).normalisedCopy());
bool added_shared = false ;
size_t current_offset = 0 ;
size_t shared_offset = 0 ;
size_t next_offset = 0 ;
size_t index_offset = 0 ;
std::pair < bool , Ogre::Real > hit( false , 0 );
Ogre::MeshPtr mesh = entity -> getMesh();
bool useSoftwareBlendingVertices = entity -> hasSkeleton();
if (useSoftwareBlendingVertices)
{
entity -> _updateAnimation();
}
added_shared = false ;
// Run through the submeshes again, adding the data into the arrays
for ( unsigned short i = 0 ; i < mesh -> getNumSubMeshes(); ++ i)
{
Ogre::SubMesh * submesh = mesh -> getSubMesh(i);
// ----------------------------------------------------------------
// GET VERTEXDATA
// ----------------------------------------------------------------
Ogre::VertexData * vertex_data;
if (useSoftwareBlendingVertices)
vertex_data = submesh -> useSharedVertices ? entity -> _getSkelAnimVertexData() : entity -> getSubEntity(i) -> _getSkelAnimVertexData();
else
vertex_data = submesh -> useSharedVertices ? mesh -> sharedVertexData : submesh -> vertexData;
if (( ! submesh -> useSharedVertices) || (submesh -> useSharedVertices && ! added_shared))
{
if (submesh -> useSharedVertices)
{
added_shared = true ;
}
}
//////////////////////////////////////////////////////////////////////// //Vertex
const Ogre::VertexElement * posElem =
vertex_data -> vertexDeclaration -> findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf =
vertex_data -> vertexBufferBinding -> getBuffer(posElem -> getSource());
unsigned char * vertex =
static_cast < unsigned char *> (vbuf -> lock (Ogre::HardwareBuffer::HBL_READ_ONLY));
//////////////////////////////////////////////////////////////////////// //Index
Ogre::IndexData * index_data = submesh -> indexData;
size_t numTris = index_data -> indexCount / 3 ;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data -> indexBuffer;
bool use32bitindexes = (ibuf -> getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
unsigned long * pLong = static_cast < unsigned long *> (ibuf -> lock (Ogre::HardwareBuffer::HBL_READ_ONLY));
unsigned short * pShort = reinterpret_cast < unsigned short *> (pLong);
size_t offset = (submesh -> useSharedVertices) ? shared_offset : current_offset;
size_t index_start = index_data -> indexStart;
size_t last_index = numTris * 3 + index_start;
float * pReal0, * pReal1, * pReal2;
Ogre::Vector3 pVector30, pVector31,pVector32;
if (use32bitindexes)
{
for (size_t k = index_start; k < last_index;)
{
posElem -> baseVertexPointerToElement(vertex + (pLong[k] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal0);
pVector30.x = pReal0[ 0 ];
pVector30.y = pReal0[ 1 ];
pVector30.z = pReal0[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (pLong[k + 1 ] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal1);
pVector31.x = pReal1[ 0 ];
pVector31.y = pReal1[ 1 ];
pVector31.z = pReal1[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (pLong[k + 2 ] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal2);
pVector32.x = pReal2[ 0 ];
pVector32.y = pReal2[ 1 ];
pVector32.z = pReal2[ 2 ];
hit = Ogre::Math::intersects(localRay, pVector30,pVector31,pVector32, true , false );
if (hit.first)
{
// parentOrientation * (parentScale * mPosition);
hit = Ogre::Math::intersects(ray, q * (pVector30 * pScale) + pPostion ,q * (pVector31 * pScale) + pPostion, q * (pVector32 * pScale) + pPostion, true , false );
if (hit.first) break ;
}
//
k += 3 ;
}
}
else
{
for (size_t k = index_start; k < last_index;)
{
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal0);
pVector30.x = pReal0[ 0 ];
pVector30.y = pReal0[ 1 ];
pVector30.z = pReal0[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k + 1 ] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal1);
pVector31.x = pReal1[ 0 ];
pVector31.y = pReal1[ 1 ];
pVector31.z = pReal1[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k + 2 ] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal2);
pVector32.x = pReal2[ 0 ];
pVector32.y = pReal2[ 1 ];
pVector32.z = pReal2[ 2 ];
hit = Ogre::Math::intersects(localRay, pVector30,pVector31,pVector32, true , false );
if (hit.first)
{
hit = Ogre::Math::intersects(ray, q * (pVector30 * pScale) + pPostion ,q * (pVector31 * pScale) + pPostion, q * (pVector32 * pScale) + pPostion, true , false );
if (hit.first) break ;
}
k += 3 ;
}
}
ibuf -> unlock();
vbuf -> unlock();
}
return hit;
}
{
// parentOrientation * (parentScale * mPosition)
Ogre::Vector3 pPostion = entity -> getParentNode() -> _getDerivedPosition();
Ogre::Vector3 pScale = entity -> getParentNode() -> _getDerivedScale();
Ogre::Quaternion q = entity -> getParentNode() -> _getDerivedOrientation();
Ogre::Ray localRay(q.Inverse() * (ray.getOrigin() - pPostion) / pScale,(q.Inverse() * ray.getDirection() / pScale).normalisedCopy());
bool added_shared = false ;
size_t current_offset = 0 ;
size_t shared_offset = 0 ;
size_t next_offset = 0 ;
size_t index_offset = 0 ;
std::pair < bool , Ogre::Real > hit( false , 0 );
Ogre::MeshPtr mesh = entity -> getMesh();
bool useSoftwareBlendingVertices = entity -> hasSkeleton();
if (useSoftwareBlendingVertices)
{
entity -> _updateAnimation();
}
added_shared = false ;
// Run through the submeshes again, adding the data into the arrays
for ( unsigned short i = 0 ; i < mesh -> getNumSubMeshes(); ++ i)
{
Ogre::SubMesh * submesh = mesh -> getSubMesh(i);
// ----------------------------------------------------------------
// GET VERTEXDATA
// ----------------------------------------------------------------
Ogre::VertexData * vertex_data;
if (useSoftwareBlendingVertices)
vertex_data = submesh -> useSharedVertices ? entity -> _getSkelAnimVertexData() : entity -> getSubEntity(i) -> _getSkelAnimVertexData();
else
vertex_data = submesh -> useSharedVertices ? mesh -> sharedVertexData : submesh -> vertexData;
if (( ! submesh -> useSharedVertices) || (submesh -> useSharedVertices && ! added_shared))
{
if (submesh -> useSharedVertices)
{
added_shared = true ;
}
}
//////////////////////////////////////////////////////////////////////// //Vertex
const Ogre::VertexElement * posElem =
vertex_data -> vertexDeclaration -> findElementBySemantic(Ogre::VES_POSITION);
Ogre::HardwareVertexBufferSharedPtr vbuf =
vertex_data -> vertexBufferBinding -> getBuffer(posElem -> getSource());
unsigned char * vertex =
static_cast < unsigned char *> (vbuf -> lock (Ogre::HardwareBuffer::HBL_READ_ONLY));
//////////////////////////////////////////////////////////////////////// //Index
Ogre::IndexData * index_data = submesh -> indexData;
size_t numTris = index_data -> indexCount / 3 ;
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data -> indexBuffer;
bool use32bitindexes = (ibuf -> getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
unsigned long * pLong = static_cast < unsigned long *> (ibuf -> lock (Ogre::HardwareBuffer::HBL_READ_ONLY));
unsigned short * pShort = reinterpret_cast < unsigned short *> (pLong);
size_t offset = (submesh -> useSharedVertices) ? shared_offset : current_offset;
size_t index_start = index_data -> indexStart;
size_t last_index = numTris * 3 + index_start;
float * pReal0, * pReal1, * pReal2;
Ogre::Vector3 pVector30, pVector31,pVector32;
if (use32bitindexes)
{
for (size_t k = index_start; k < last_index;)
{
posElem -> baseVertexPointerToElement(vertex + (pLong[k] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal0);
pVector30.x = pReal0[ 0 ];
pVector30.y = pReal0[ 1 ];
pVector30.z = pReal0[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (pLong[k + 1 ] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal1);
pVector31.x = pReal1[ 0 ];
pVector31.y = pReal1[ 1 ];
pVector31.z = pReal1[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (pLong[k + 2 ] + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal2);
pVector32.x = pReal2[ 0 ];
pVector32.y = pReal2[ 1 ];
pVector32.z = pReal2[ 2 ];
hit = Ogre::Math::intersects(localRay, pVector30,pVector31,pVector32, true , false );
if (hit.first)
{
// parentOrientation * (parentScale * mPosition);
hit = Ogre::Math::intersects(ray, q * (pVector30 * pScale) + pPostion ,q * (pVector31 * pScale) + pPostion, q * (pVector32 * pScale) + pPostion, true , false );
if (hit.first) break ;
}
//
k += 3 ;
}
}
else
{
for (size_t k = index_start; k < last_index;)
{
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal0);
pVector30.x = pReal0[ 0 ];
pVector30.y = pReal0[ 1 ];
pVector30.z = pReal0[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k + 1 ] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal1);
pVector31.x = pReal1[ 0 ];
pVector31.y = pReal1[ 1 ];
pVector31.z = pReal1[ 2 ];
posElem -> baseVertexPointerToElement(vertex + (static_cast < unsigned long > ( pShort[k + 2 ] ) + static_cast < unsigned long > ( offset )) * vbuf -> getVertexSize(), & pReal2);
pVector32.x = pReal2[ 0 ];
pVector32.y = pReal2[ 1 ];
pVector32.z = pReal2[ 2 ];
hit = Ogre::Math::intersects(localRay, pVector30,pVector31,pVector32, true , false );
if (hit.first)
{
hit = Ogre::Math::intersects(ray, q * (pVector30 * pScale) + pPostion ,q * (pVector31 * pScale) + pPostion, q * (pVector32 * pScale) + pPostion, true , false );
if (hit.first) break ;
}
k += 3 ;
}
}
ibuf -> unlock();
vbuf -> unlock();
}
return hit;
}