(地基工)Ogre动画拾取函数优化版本

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


拾取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;
}

你可能感兴趣的:((地基工)Ogre动画拾取函数优化版本)