//--
    void
    UniformGrid::VAddObjects(const std::vector<ISpatialObject*>& refObjects)
    {
        // [rad] We need to determine the size of the grid (size of each cell)
        int i32Hash;
        float f32Diameter;
        
        ISpatialObject* pObject;
        
        // [rad] Iterate through all objects, and find the biggest diameter
        std::vector<ISpatialObject*>::const_iterator iter_object;
        for(iter_object = refObjects.begin(); iter_object != refObjects.end(); iter_object++)
        {
            pObject = (*iter_object);
            
            f32Diameter = pObject->VGetRadius() * 2.0f;
            
            if(f32Diameter > m_f32GridSize)
            {
                // [rad] Found a bigger object, update
                m_f32GridSize = f32Diameter;
            }
            
            // [rad] We also locally store object pointers, so we could do a bulk update
            m_vecObjects.push_back(pObject);
        }
        
        
        // [rad] We'll make it so that cell's is 'x' times as big as the largest object
        m_f32GridSize *= s_f32ObjectCellRatio;

        
        // [rad] For each object, determine the cell and insert
        for(iter_object = refObjects.begin(); iter_object != refObjects.end(); iter_object++)
        {
            pObject = (*iter_object);
            
            // [rad] Compute hash for this object - we use object's center to
            // determine the proper cell, and then hash that value
            i32Hash = ComputeHashValue(m_i32HashBuckets, 
                        static_cast<int>(pObject->VGetPosition().x / m_f32GridSize),
                        static_cast<int>(pObject->VGetPosition().y / m_f32GridSize),
                        static_cast<int>(pObject->VGetPosition().z / m_f32GridSize));
                        
            
            // [rad] Insert at the end of this bucket
            (m_vecHashBuckets[i32Hash])->InsertObject(pObject);
        }
    }
Beispiel #2
0
    //--
    void
    KDTreeNode::Construct(ISpatialObject* pObjectList, int i32ObjectCount,
                                         const Vector3& refVectorMin, const Vector3& refVectorMax)
    {        
        
        // [rad] Store voxel info
        m_vec3Max = refVectorMax;
        m_vec3Min = refVectorMin;
        
        // [rad] Split plane position is already stored
        
        
        ISpatialObject* pIter = pObjectList;  
        ISpatialObject* pObjectTemp;
        ISpatialObject* pObject;
                       
        // [rad] If there are no children, or there's less objects than bins,
        // store everything in this node
        if(!m_pChildLeft || !m_pChildRight || i32ObjectCount < s_i32BinCount)
        {
            // [rad] There's no splitpane and position is not important
            m_f32SplitPosition = 0.0f;
            //m_i32SplitPane = -1;
            
            // [rad] Copy elements...
            m_pObjects = pObjectList;
            m_i32ObjectCount = i32ObjectCount;
            m_i32ObjectTotal = i32ObjectCount;
            
            
            // [rad] Iterate through all elements and set this node as a containing cell
            pIter = m_pObjects;   
            while(pIter)
            {
                pIter->VSetCell(this);
                pIter = pIter->VGetNext();
            }
            
            return;
        }
        


        // [rad] Compute sizes
        float f32Span = m_vec3Max[m_i32SplitPane] - m_vec3Min[m_i32SplitPane];
        float f32BucketSize = f32Span / static_cast<float>(s_i32BinCount);
        float f32Offset = -m_vec3Min[m_i32SplitPane];
                
        int i32BinIndex;        
        int i32Index;
      

        
        // [rad] Clean prefix sums and previous values
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            s_vecBins.at(i32Index).first = 0;
            s_vecBins.at(i32Index).second = 0;
            
            s_vecSums.at(i32Index).first = 0;
            s_vecSums.at(i32Index).second = 0;
        }
        
        
        
        
        // [rad] Go linearly through the list and do binning
        pIter = pObjectList;        
        Vector3 vec3Center;
        float f32Radius;
        
        while(pIter)
        {
            // [rad] Get center and radius of this object
            vec3Center = pIter->VGetPosition();
            f32Radius = pIter->VGetRadius();
            
            // [rad] Increment proper bins
            i32BinIndex = static_cast<int>(floorf((f32Offset + vec3Center[m_i32SplitPane] - f32Radius) * s_i32BinCount / f32Span));
            s_vecBins[i32BinIndex].first++;
            
            i32BinIndex = static_cast<int>(floorf((f32Offset + vec3Center[m_i32SplitPane] + f32Radius) * s_i32BinCount / f32Span));
            s_vecBins[i32BinIndex].second++;
                        
           
            // [rad] iterate to next element in list
            pIter = pIter->VGetNext();
        }
        
        
        
        
        // [rad] Compute prefix sums
        int i32SumMin = 0;
        int i32SumMax = 0;

        
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            i32SumMin += s_vecBins.at(i32Index).first;
            i32SumMax += s_vecBins.at(i32Index).second;
            
            s_vecSums.at(i32Index).first = i32SumMin;
            s_vecSums.at(i32Index).second = i32SumMax;
        }
        
        
        
        // [rad] Compute split candidate
        int i32MinDiff = std::numeric_limits<int>::max();
        int i32BinDiff;
        int i32SplitPosition = 0;
        
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            i32BinDiff = abs(s_vecSums.at(i32Index).first - s_vecSums.at(s_i32BinCount - i32Index - 1).second);
            
            if(i32BinDiff < i32MinDiff)
            {
                // [rad] This is a good candidate
                i32MinDiff = i32BinDiff;
                i32SplitPosition = i32Index;
            }
        }
    
    
        
        // [rad] Find real split position
        //m_f32SplitPosition = ((i32SplitPosition * f32Span) / f32BucketSize) - f32Offset;
        m_f32SplitPosition = m_vec3Min[m_i32SplitPane] + i32SplitPosition * f32BucketSize;
        
        
        // [rad] Now go insert objects into child nodes
        ISpatialObject* pObjectListLeft = NULL;
        ISpatialObject* pObjectListRight = NULL;
        
        int i32CountLeft = 0;
        int i32CountRight = 0;
        
        pIter = pObjectList;        
        while(pIter)
        {
            pObject = pIter->VGetNext();
            
            // [rad] Get center and radius of this object
            vec3Center = pIter->VGetPosition();
            f32Radius = pIter->VGetRadius();
            
            
            // [rad] Check where this object belongs
            if(vec3Center[m_i32SplitPane] + f32Radius <= m_f32SplitPosition)
            {
                // [rad] Left child

                pIter->VSetNext(pObjectListLeft);
                pObjectListLeft = pIter;
                
                i32CountLeft++;
            }
            else if(vec3Center[m_i32SplitPane] - f32Radius >= m_f32SplitPosition)
            {
                // [rad] Right child
                
                pIter->VSetNext(pObjectListRight);
                pObjectListRight = pIter;
                
                i32CountRight++;
            }
            else
            {
                
                pIter->VSetCell(this);
                pIter->VSetNext(m_pObjects);
                m_pObjects = pIter;
                
                m_i32ObjectCount++;
            }
            
            pIter = pObject;
        }
        
        
        // [rad] We'll keep track of how many objects we have in this node 
        // and in children
        m_i32ObjectTotal += i32ObjectCount;
        
        
        Vector3 vec3Min = refVectorMin;
        vec3Min[m_i32SplitPane] = m_f32SplitPosition;
        
        Vector3 vec3Max = refVectorMax;
        vec3Max[m_i32SplitPane] = m_f32SplitPosition;
        
        // [rad] Recurse into left child
        m_pChildLeft->Construct(pObjectListLeft, i32CountLeft,
                                            refVectorMin, vec3Max);
                                            
                                            
        // [rad] Recurse into right child
        m_pChildRight->Construct(pObjectListRight, i32CountRight,
                                            vec3Min, refVectorMax);
    }
 //--
 void
 OctreeNode::AddObjects(ISpatialObject* pObjectList, int i32ObjectCount)
 {
     ISpatialObject* pIter;
     ISpatialObject* pObject;
     
     // [rad] Check if we can stop splitting
     if(i32ObjectCount < s_i32MinSplitCount)
     {
         m_pObjects = pObjectList;
         
         pIter = m_pObjects;   
         while(pIter)
         {
             pIter->VSetCell(this);
             pIter = pIter->VGetNext();
         }
         
         
         m_i32ObjectCount = i32ObjectCount;
         
         return;
     }
     
     
     
     int i32Index = 0;
     ISpatialObject* apChildObjects[8];
     int aiChildCounts[8];
     
     for(i32Index = 0; i32Index < 8; i32Index++)
     {
         apChildObjects[i32Index] = NULL;
         aiChildCounts[i32Index] = 0;
     }
     
     
     pIter = pObjectList;
     while(pIter)
     {
         pObject = pIter->VGetNext();
         
         int i32Position = 0;
         int i32Straddle = 0;
 
         float f32Radius = pIter->VGetRadius();
         Vector3 vec3Center = pIter->VGetPosition();
         
         
         for(i32Index = 0; i32Index < 3; i32Index++)
         {
             if(m_vec3Center[i32Index] < vec3Center[i32Index])
             {
                 if(m_vec3Center[i32Index] > vec3Center[i32Index] - f32Radius)
                 {
                     // [rad] Straddle occurs
                     i32Straddle = 1;
                     break;
                 }
                 else
                 {
                     i32Position |= (1 << i32Index);
                 }
             }
             else
             {
                 if(m_vec3Center[i32Index] < vec3Center[i32Index] + f32Radius)
                 {
                     // [rad] Straddle occurs
                     i32Straddle = 1;
                     break;
                 }
             }
         }
     
     
         if(!i32Straddle && m_pChildren[i32Position])
         {
             // [rad] Contained in existing child node
             //m_pChildren[i32Position]->AddObject(pObject);
             
             pIter->VSetNext(apChildObjects[i32Position]);
             apChildObjects[i32Position] = pIter;
         
             aiChildCounts[i32Position]++;
             
         }
         else
         {
             // [rad] Store this node for fast back-link
             pIter->VSetCell(this);
     
             // [rad] Straddling or no child node available
             pIter->VSetNext(m_pObjects);
             m_pObjects = pIter;
             
             m_i32ObjectCount++;
         }
         
         
         pIter = pObject;
     }
     
     
     // [rad] At this point
     for(i32Index = 0; i32Index < 8; i32Index++)
     {            
         // [rad] Delegate to children
         if(m_pChildren[i32Index] && aiChildCounts[i32Index])
         {
             m_pChildren[i32Index]->AddObjects(apChildObjects[i32Index], aiChildCounts[i32Index]);
         }
     }    
 }
 //--
 void
 UniformGrid::VUpdate()
 {
     int i32X1, i32X2;
     int i32Y1, i32Y2;
     int i32Z1, i32Z2;
     
     int i32Hash;
     
     float f32Delta;
     
     UniformGridHashBucket* pBucket;        
             
     std::vector<ISpatialObject*>::iterator iter_object;
     for(iter_object = m_vecObjects.begin(); iter_object != m_vecObjects.end(); iter_object++)
     {
         ISpatialObject* pObject = (*iter_object);
         
         // [rad] Retrieve the bucket in which this object is stored
         pBucket = static_cast<UniformGridHashBucket*>(pObject->VGetCell());
         
         
         
         // [rad] Retrieve new object position
         const Vector3& vec3Position = pObject->VGetPosition();
                 
         // [rad] Check if we need bucket update (compute hash)
         i32Hash = ComputeHashValue(m_i32HashBuckets, 
                     static_cast<int>(vec3Position.x / m_f32GridSize),
                     static_cast<int>(vec3Position.y / m_f32GridSize),
                     static_cast<int>(vec3Position.z / m_f32GridSize));
                     
         
         // [rad] Check if we need to switch buckets
         if(m_vecHashBuckets[i32Hash] != pBucket)
         {
             // [rad] Remove from old bucket
             pBucket->RemoveObject(pObject);
             
             // [rad] Add to new (other) bucket
             (m_vecHashBuckets[i32Hash])->InsertObject(pObject);
         } 
         
         
         // [rad] Update frame
         ++m_i32FrameCount;
     
 
         // [rad] Check collisions within the current bucket
         pBucket->CheckCollisions(m_i32FrameCount, pObject);
         
                     
         // [rad] Now we need to check adjacent buckets:
         // compute all cells which this object might overlap.
         // Because initially we picked size for our cells big enough to
         // encompass any object, we have to check at most 8 cells (3D).
         
         f32Delta = pObject->VGetRadius() + m_f32GridSize / s_f32ObjectCellRatio + s_f32Epsilon;
         
         i32X1 = static_cast<int>(floorf((vec3Position.x - f32Delta) / m_f32GridSize));
         i32X2 = static_cast<int>(ceilf((vec3Position.x + f32Delta) / m_f32GridSize));
         i32Y1 = static_cast<int>(floorf((vec3Position.y - f32Delta) / m_f32GridSize));
         i32Y2 = static_cast<int>(ceilf((vec3Position.y + f32Delta) / m_f32GridSize));
         i32Z1 = static_cast<int>(floorf((vec3Position.z - f32Delta) / m_f32GridSize));
         i32Z2 = static_cast<int>(ceilf((vec3Position.z + f32Delta) / m_f32GridSize));
         
         // [rad] Check all grid cells
         for(int i32XIndex = i32X1; i32XIndex <= i32X2; i32XIndex++)
         {
             for(int i32YIndex = i32Y1; i32YIndex <= i32Y2; i32YIndex++)
             {
                 for(int i32ZIndex = i32Z1; i32ZIndex <= i32Z2; i32ZIndex++)
                 {
                     i32Hash = ComputeHashValue(m_i32HashBuckets, i32XIndex, i32YIndex, i32ZIndex);
                     
                     // [rad] Check if we have checked this bucket already
                     if(m_vecHashBuckets[i32Hash]->GetLastFrame() == m_i32FrameCount)
                     {
                         continue;
                     }
                     
                     // [rad] Otherwise check collisions
                     (m_vecHashBuckets[i32Hash])->CheckCollisions(m_i32FrameCount, pObject);
                 }
             }
         }
     }
 }