IEntity
*
GraphicalWorld::pickEntity(
const
Ray
&
ray, uint32 mask)
{
WS_ASSERT( msCore );
//
// const unsigned long mask = 0xFFFFFFFF;
Ogre::Ray ogreRay( VEC_WS2OGRE(ray.getOrigin()), VEC_WS2OGRE(ray.getDirection()) );
if ( ! mpRaySceneQuery)
{
mpRaySceneQuery = msCore -> getSceneMgr() -> createRayQuery( ogreRay, mask );
}
else
{
mpRaySceneQuery -> setRay(ogreRay );
mpRaySceneQuery -> setQueryMask(mask);
}
mpRaySceneQuery -> setSortByDistance( true );
Ogre::Real closest_distance = 99999.0f ;
Ogre::RaySceneQueryResult & query_result = mpRaySceneQuery -> execute();
Ogre::MovableObject * movable;
IEntity * pEntity = NULL;
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 ;
// only check this result if its a hit against an entity
movable = query_result[qr_idx].movable;
if (( movable != NULL) && (movable -> getMovableType().compare( " Entity " ) == 0 ) && movable -> isVisible())
{
EntityMap::const_iterator itFind = mEntityMap.find( static_cast < Ogre::Entity *> (movable));
if (itFind == mEntityMap.end())
continue ;
// get the entity to check
Ogre::Entity * pentity = static_cast < Ogre::Entity *> (movable);
// mesh data to retrieve
size_t vertex_count;
size_t index_count;
pentity -> _getSkelAnimVertexData();
// get the mesh information
GetMeshInformation(pentity, vertex_count, index_count,
pentity -> getParentNode() -> _getDerivedPosition(),
pentity -> getParentNode() -> _getDerivedOrientation(),
pentity -> getParentNode() -> _getDerivedScale());
// test for hitting individual triangles on the mesh
bool new_closest_found = false ;
for ( int i = 0 ; i < static_cast < int > (index_count); i += 3 )
{
assert(mIndexBuffer[i] < vertex_count);
assert(mIndexBuffer[i + 1 ] < vertex_count);
assert(mIndexBuffer[i + 2 ] < vertex_count);
// check for a hit against this triangle
std::pair < bool , Ogre::Real > hit = Ogre::Math::intersects(ogreRay, mVertexBuffer[mIndexBuffer[i]],
mVertexBuffer[mIndexBuffer[i + 1 ]], mVertexBuffer[mIndexBuffer[i + 2 ]], true , false );
// if it was a hit check if its the closest
if (hit.first)
{
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)
{
pEntity = itFind -> second;
}
}
}
// Ogre::RaySceneQueryResult &result = mpRaySceneQuery->execute();
// Ogre::RaySceneQueryResult::iterator it = result.begin();
// if (it != result.end())
// {
// // it->distance
// // if (it->worldFragment)
// if (it->movable)
// {
// // Ogre::UserDefinedObject* udo = Ogre::MovableObject::getUserObject();
// if (it->movable->getMovableType() == "Entity")
// {
// EntityMap::const_iterator itFind = mEntityMap.find( static_cast<Ogre::Entity*>( it->movable ) );
// if (itFind != mEntityMap.end())
// return itFind->second;
// }
// }
// }
return pEntity;
}
{
WS_ASSERT( msCore );
//
// const unsigned long mask = 0xFFFFFFFF;
Ogre::Ray ogreRay( VEC_WS2OGRE(ray.getOrigin()), VEC_WS2OGRE(ray.getDirection()) );
if ( ! mpRaySceneQuery)
{
mpRaySceneQuery = msCore -> getSceneMgr() -> createRayQuery( ogreRay, mask );
}
else
{
mpRaySceneQuery -> setRay(ogreRay );
mpRaySceneQuery -> setQueryMask(mask);
}
mpRaySceneQuery -> setSortByDistance( true );
Ogre::Real closest_distance = 99999.0f ;
Ogre::RaySceneQueryResult & query_result = mpRaySceneQuery -> execute();
Ogre::MovableObject * movable;
IEntity * pEntity = NULL;
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 ;
// only check this result if its a hit against an entity
movable = query_result[qr_idx].movable;
if (( movable != NULL) && (movable -> getMovableType().compare( " Entity " ) == 0 ) && movable -> isVisible())
{
EntityMap::const_iterator itFind = mEntityMap.find( static_cast < Ogre::Entity *> (movable));
if (itFind == mEntityMap.end())
continue ;
// get the entity to check
Ogre::Entity * pentity = static_cast < Ogre::Entity *> (movable);
// mesh data to retrieve
size_t vertex_count;
size_t index_count;
pentity -> _getSkelAnimVertexData();
// get the mesh information
GetMeshInformation(pentity, vertex_count, index_count,
pentity -> getParentNode() -> _getDerivedPosition(),
pentity -> getParentNode() -> _getDerivedOrientation(),
pentity -> getParentNode() -> _getDerivedScale());
// test for hitting individual triangles on the mesh
bool new_closest_found = false ;
for ( int i = 0 ; i < static_cast < int > (index_count); i += 3 )
{
assert(mIndexBuffer[i] < vertex_count);
assert(mIndexBuffer[i + 1 ] < vertex_count);
assert(mIndexBuffer[i + 2 ] < vertex_count);
// check for a hit against this triangle
std::pair < bool , Ogre::Real > hit = Ogre::Math::intersects(ogreRay, mVertexBuffer[mIndexBuffer[i]],
mVertexBuffer[mIndexBuffer[i + 1 ]], mVertexBuffer[mIndexBuffer[i + 2 ]], true , false );
// if it was a hit check if its the closest
if (hit.first)
{
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)
{
pEntity = itFind -> second;
}
}
}
// Ogre::RaySceneQueryResult &result = mpRaySceneQuery->execute();
// Ogre::RaySceneQueryResult::iterator it = result.begin();
// if (it != result.end())
// {
// // it->distance
// // if (it->worldFragment)
// if (it->movable)
// {
// // Ogre::UserDefinedObject* udo = Ogre::MovableObject::getUserObject();
// if (it->movable->getMovableType() == "Entity")
// {
// EntityMap::const_iterator itFind = mEntityMap.find( static_cast<Ogre::Entity*>( it->movable ) );
// if (itFind != mEntityMap.end())
// return itFind->second;
// }
// }
// }
return pEntity;
}
取得动画顶点数据
void
GetMeshInformation(
const
Entity
*
entity,
size_t & vertex_count,
Ogre::Vector3 * & vertices,
size_t & index_count,
unsigned long * & indices,
const Ogre::Vector3 & position,
const Ogre::Quaternion & orient,
const Ogre::Vector3 & scale)
{
bool added_shared = false ;
size_t current_offset = 0 ;
size_t shared_offset = 0 ;
size_t next_offset = 0 ;
size_t index_offset = 0 ;
vertex_count = index_count = 0 ;
Ogre::MeshPtr mesh = entity -> getMesh();
bool useSoftwareBlendingVertices = entity -> hasSkeleton();
if (useSoftwareBlendingVertices)
{
entity -> _updateAnimation();
}
// Calculate how many vertices and indices we're going to need
for (unsigned short i = 0 ; i < mesh -> getNumSubMeshes(); ++ i)
{
Ogre::SubMesh * submesh = mesh -> getSubMesh( i );
// We only need to add the shared vertices once
if (submesh -> useSharedVertices)
{
if ( ! added_shared )
{
vertex_count += mesh -> sharedVertexData -> vertexCount;
added_shared = true ;
}
}
else
{
vertex_count += submesh -> vertexData -> vertexCount;
}
// Add the indices
index_count += submesh -> indexData -> indexCount;
}
// Allocate space for the vertices and indices
vertices = new Ogre::Vector3[vertex_count];
indices = new unsigned long [index_count];
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 = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
Ogre::VertexData * vertex_data;
// When there is animation:
if (useSoftwareBlendingVertices)
#ifdef BUILD_AGAINST_AZATHOTH
vertex_data = submesh -> useSharedVertices ? entity -> _getSharedBlendedVertexData() : entity -> getSubEntity(i) -> _getBlendedVertexData();
#else
vertex_data = submesh -> useSharedVertices ? entity -> _getSkelAnimVertexData() : entity -> getSubEntity(i) -> _getSkelAnimVertexData();
#endif
else
vertex_data = submesh -> useSharedVertices ? mesh -> sharedVertexData : submesh -> vertexData;
if (( ! submesh -> useSharedVertices) || (submesh -> useSharedVertices && ! added_shared))
{
if (submesh -> useSharedVertices)
{
added_shared = true ;
shared_offset = current_offset;
}
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));
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float * pReal;
for ( size_t j = 0 ; j < vertex_data -> vertexCount; ++ j, vertex += vbuf -> getVertexSize())
{
posElem -> baseVertexPointerToElement(vertex, & pReal);
Ogre::Vector3 pt(pReal[ 0 ], pReal[ 1 ], pReal[ 2 ]);
vertices[current_offset + j] = (orient * (pt * scale)) + position;
}
vbuf -> unlock();
next_offset += vertex_data -> vertexCount;
}
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;
if (use32bitindexes)
for (size_t k = index_start; k < last_index; ++ k)
{
indices[index_offset ++ ] = pLong[k] + static_cast < unsigned long > ( offset );
}
else
for (size_t k = index_start; k < last_index; ++ k)
{
indices[ index_offset ++ ] = static_cast < unsigned long > ( pShort[k] ) +
static_cast < unsigned long > ( offset );
}
ibuf -> unlock();
current_offset = next_offset;
}
}
size_t & vertex_count,
Ogre::Vector3 * & vertices,
size_t & index_count,
unsigned long * & indices,
const Ogre::Vector3 & position,
const Ogre::Quaternion & orient,
const Ogre::Vector3 & scale)
{
bool added_shared = false ;
size_t current_offset = 0 ;
size_t shared_offset = 0 ;
size_t next_offset = 0 ;
size_t index_offset = 0 ;
vertex_count = index_count = 0 ;
Ogre::MeshPtr mesh = entity -> getMesh();
bool useSoftwareBlendingVertices = entity -> hasSkeleton();
if (useSoftwareBlendingVertices)
{
entity -> _updateAnimation();
}
// Calculate how many vertices and indices we're going to need
for (unsigned short i = 0 ; i < mesh -> getNumSubMeshes(); ++ i)
{
Ogre::SubMesh * submesh = mesh -> getSubMesh( i );
// We only need to add the shared vertices once
if (submesh -> useSharedVertices)
{
if ( ! added_shared )
{
vertex_count += mesh -> sharedVertexData -> vertexCount;
added_shared = true ;
}
}
else
{
vertex_count += submesh -> vertexData -> vertexCount;
}
// Add the indices
index_count += submesh -> indexData -> indexCount;
}
// Allocate space for the vertices and indices
vertices = new Ogre::Vector3[vertex_count];
indices = new unsigned long [index_count];
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 = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
Ogre::VertexData * vertex_data;
// When there is animation:
if (useSoftwareBlendingVertices)
#ifdef BUILD_AGAINST_AZATHOTH
vertex_data = submesh -> useSharedVertices ? entity -> _getSharedBlendedVertexData() : entity -> getSubEntity(i) -> _getBlendedVertexData();
#else
vertex_data = submesh -> useSharedVertices ? entity -> _getSkelAnimVertexData() : entity -> getSubEntity(i) -> _getSkelAnimVertexData();
#endif
else
vertex_data = submesh -> useSharedVertices ? mesh -> sharedVertexData : submesh -> vertexData;
if (( ! submesh -> useSharedVertices) || (submesh -> useSharedVertices && ! added_shared))
{
if (submesh -> useSharedVertices)
{
added_shared = true ;
shared_offset = current_offset;
}
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));
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float * pReal;
for ( size_t j = 0 ; j < vertex_data -> vertexCount; ++ j, vertex += vbuf -> getVertexSize())
{
posElem -> baseVertexPointerToElement(vertex, & pReal);
Ogre::Vector3 pt(pReal[ 0 ], pReal[ 1 ], pReal[ 2 ]);
vertices[current_offset + j] = (orient * (pt * scale)) + position;
}
vbuf -> unlock();
next_offset += vertex_data -> vertexCount;
}
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;
if (use32bitindexes)
for (size_t k = index_start; k < last_index; ++ k)
{
indices[index_offset ++ ] = pLong[k] + static_cast < unsigned long > ( offset );
}
else
for (size_t k = index_start; k < last_index; ++ k)
{
indices[ index_offset ++ ] = static_cast < unsigned long > ( pShort[k] ) +
static_cast < unsigned long > ( offset );
}
ibuf -> unlock();
current_offset = next_offset;
}
}