posts - 311, comments - 0, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

(搬运工)Ogre动画拾取函数

Posted on 2011-09-20 14:22 点点滴滴 阅读(714) 评论(0)  编辑 收藏 引用 所属分类: 08 游戏SDK
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]], truefalse);

                    
// 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;
    }
}