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