void ireon::kd_tree::KdTree<T>::subdivide( KdTreeNode<T>* node, const aabb& box, int depth, int a_Prims ) { // recycle used split list nodes //add sPool_ at end sList_ if (sList_) { SplitList* list = sList_; while (list->next) list = list->next; list->next = sPool_; sPool_ = sList_, sList_ = 0; } // determine split axis Vector3 s = box.getSize(); if ((s.x >= s.y) && (s.x >= s.z)) node->setAxis( 0 ); else if ((s.y >= s.x) && (s.y >= s.z)) node->setAxis( 1 ); int axis = node->getAxis(); // make a list of the split position candidates ObjectList<T>* l = node->getList(); real p1, p2; real pos1 = box.getPos().val[axis]; real pos2 = box.getPos().val[axis] + box.getSize().val[axis]; bool* pright = new bool[a_Prims]; float* eleft = new float[a_Prims], *eright = new float[a_Prims]; T** parray = new T*[a_Prims]; real etleft, etright; int aidx = 0; while (l) { T* p = parray[aidx] = l->getPrimitive(); pright[aidx] = true; etleft = eleft[aidx]; etright = eright[aidx]; p->calculateRange( etleft, etright, axis ); eleft[aidx] = (float)etleft; eright[aidx] = (float)etright; aidx++; for ( int i = 0; i < 3; i++ ) { p1 = (float)p->vertice( i )->cell[axis]; if ((p1 >= pos1) && (p1 <= pos2)) insertSplitPos( p1 ); } l = l->getNext(); } // determine n1count / n2count for each split position aabb b1, b2, b3 = box, b4 = box; SplitList* splist = sList_; float b3p1 = b3.getPos().val[axis]; float b4p2 = b4.getPos().val[axis] + b4.getSize().val[axis]; Vector3 foo; while (splist) { foo = b4.getPos(); foo.val[axis] = splist->splitpos; b4.setPos(foo); foo = b4.getSize(); foo.val[axis] = pos2 - splist->splitpos; b4.setSize(foo); foo = b3.getSize(); foo.val[axis] = splist->splitpos - pos1; b3.setSize(foo); float b3p2 = b3.getPos().val[axis] + b3.getSize().val[axis]; float b4p1 = b4.getPos().val[axis]; for ( int i = 0; i < a_Prims; i++ ) if (pright[i]) { T* p = parray[i]; if ((eleft[i] <= b3p2) && (eright[i] >= b3p1)) if (p->intersectBox( b3 )) splist->n1count++; if ((eleft[i] <= b4p2) && (eright[i] >= b4p1)) if (p->intersectBox( b4 )) splist->n2count++; else pright[i] = false; } else splist->n1count++; splist = splist->next; } delete[] pright; // calculate surface area for current node real SAV = 0.5f / (box.w() * box.d() + box.w() * box.h() + box.d() * box.h()); // calculate cost for not splitting real Cleaf = a_Prims * 1.0f; // determine optimal split plane position splist = sList_; real lowcost = 10000; real bestpos = 0; while (splist) { // calculate child node extends foo = b4.getPos(); foo.val[axis] = splist->splitpos; b4.setPos(foo); foo = b4.getSize(); foo.val[axis] = pos2 - splist->splitpos; b4.setSize(foo); foo = b3.getSize(); foo.val[axis] = splist->splitpos - pos1; b3.setSize(foo); // calculate child node cost real SA1 = 2 * (b3.w() * b3.d() + b3.w() * b3.h() + b3.d() * b3.h()); real SA2 = 2 * (b4.w() * b4.d() + b4.w() * b4.h() + b4.d() * b4.h()); real splitcost = 0.3f + 1.0f * (SA1 * SAV * splist->n1count + SA2 * SAV * splist->n2count); // update best cost tracking variables if (splitcost < lowcost) { lowcost = splitcost; bestpos = splist->splitpos; b1 = b3, b2 = b4; } splist = splist->next; } if (lowcost > Cleaf) { delete[] eleft; delete[] eright; delete[] parray; return; } node->setSplitPos( bestpos ); // construct child nodes KdTreeNode<T>* left = s_MManager->NewKdTreeNodePair(); int n1count = 0, n2count = 0, total = 0; // assign primitives to both sides float b1p1 = b1.getPos().val[axis]; float b2p2 = b2.getPos().val[axis] + b2.getSize().val[axis]; float b1p2 = b1.getPos().val[axis] + b1.getSize().val[axis]; float b2p1 = b2.getPos().val[axis]; for ( int i = 0; i < a_Prims; i++ ) { T* p = parray[i]; total++; if ((eleft[i] <= b1p2) && (eright[i] >= b1p1)) if (p->intersectBox( b1 )) { left->add( p ); n1count++; } if ((eleft[i] <= b2p2) && (eright[i] >= b2p1)) if (p->intersectBox( b2 )) { (left + 1)->add( p ); n2count++; } } delete[] eleft; delete[] eright; delete[] parray; s_MManager->FreeObjectList( node->getList() ); node->setLeft( left ); node->setLeaf( false ); if (depth < MAXTREEDEPTH) { if (n1count > 2) subdivide( left, b1, depth + 1, n1count ); if (n2count > 2) subdivide( left + 1, b2, depth + 1, n2count ); } }
void KdTree::subdivide( KdTreeNode *node, AABB aabb, int depth, int objCount ) { // recycle used split nodes if (m_splitList) { SplitNode* list = m_splitList; while (list->next) list = list->next; list->next = m_splitPool; m_splitPool = m_splitList; // Reset the split list m_splitList = 0; } // Find the split axis, we split the aixs of maximum size Vector3 s = aabb.getSize(); // Get the size int axis; if ( (s.x >= s.y) && (s.x >= s.z) ) // Split x axis = 0; else if ( (s.y >= s.x) && (s.y >= s.z) ) // Split y axis = 1; // y axis else // Split z axis = 2; // z axis node->setAxis( axis ); // make a list of the split position candidates ObjectNode* objNodes = node->getObjectList(); float posStart = aabb.getPos().xyz[axis]; float posEnd = aabb.getPos().xyz[axis] + aabb.getSize().xyz[axis]; float* eleft = new float[objCount]; float* eright = new float[objCount]; SceneObject** parray = new SceneObject*[objCount]; int id = 0; while (objNodes) { SceneObject* p = parray[id] = objNodes->getObject(); calculateAABBRange( p->m_boundingBox, eleft[id], eright[id], axis ); // Insert all of the split positions if( eleft[id] >= posStart && eleft[id] <= posEnd ) insertSplitPos( eleft[id] ); if( eright[id] >= posStart && eright[id] <= posEnd ) insertSplitPos( eright[id] ); id++; // Get next one objNodes = objNodes->getNext(); } // Calculate left count and right count for each split choice AABB leftAABB, rightAABB; // Need to do this to give the initial value of axis other than the axis we gonna split AABB leftAABBTmp = aabb, rightAABBTmp = aabb; SplitNode* splist = m_splitList; float leftAABBStartTmp = aabb.getPos().xyz[axis]; float rightAABBEndTmp = aabb.getPos().xyz[axis] + aabb.getSize().xyz[axis]; while ( splist ) { rightAABBTmp.getPos().xyz[axis] = splist->splitPos; rightAABBTmp.getSize().xyz[axis] = posEnd - splist->splitPos; leftAABBTmp.getSize().xyz[axis] = splist->splitPos - posStart; //SUB: float leftAABBEndTmp =splist->splitPos; float leftAABBEndTmp = leftAABBTmp.getPos().xyz[axis] + leftAABBTmp.getSize().xyz[axis]; //SUB:splist->splitPos; float rightAABBStartTmp = rightAABBTmp.getPos().xyz[axis]; /* *Intersect problematic */ for ( int i = 0; i < objCount; i++ ) { SceneObject* p = parray[i]; // SUB if ((eleft[i] <= leftAABBEndTmp) && (eright[i] >= leftAABBStartTmp)) { if (p->m_boundingBox.intersectAABB( leftAABBTmp )) splist->leftCount++; } // SUB if ((eleft[i] <= rightAABBEndTmp) && (eright[i] >= rightAABBStartTmp )) { if (p->m_boundingBox.intersectAABB( rightAABBTmp )) splist->rightCount++; } } splist = splist->next; } // calculate surface area for current node float SAV = 1.f / calculateSA( aabb ); // calculate cost for not splitting float costNoSplit = objCount; // determine optimal split plane position splist = m_splitList; float min = POS_INF; float bestpos = 0; leftAABBTmp = rightAABBTmp = aabb; while (splist) { // calculate child node extends rightAABBTmp.getPos().xyz[axis] = splist->splitPos; rightAABBTmp.getSize().xyz[axis] = posEnd - splist->splitPos; leftAABBTmp.getSize().xyz[axis] = splist->splitPos - posStart; // calculate child node cost float SA1 = calculateSA( leftAABBTmp ); float SA2 = calculateSA( rightAABBTmp ); float splitcost = 0.3f + 1.0f * (SA1 * SAV * splist->leftCount + SA2 * SAV * splist->rightCount ); // update best cost tracking variables if (splitcost < min) { min = splitcost; bestpos = splist->splitPos; // Record the best left AABB and right AABB leftAABB = leftAABBTmp; rightAABB = rightAABBTmp; } splist = splist->next; } if ( min > costNoSplit) { node->setLeaf( true ); return; } node->setSplitPos( bestpos ); // construct child nodes KdTreeNode* left = newKdTreeNodePair(); KdTreeNode* right = left + 1; // COF: total, useless? int leftCount, rightCount, totalCount; leftCount = rightCount = totalCount = 0; // assign primitives to both sides float leftAABBStart = leftAABB.getPos().xyz[axis]; float leftAABBEnd = leftAABB.getPos().xyz[axis] + leftAABB.getSize().xyz[axis]; float rightAABBStart = rightAABB.getPos().xyz[axis]; float rightAABBEnd = rightAABB.getPos().xyz[axis] + rightAABB.getSize().xyz[axis]; for ( int i = 0; i < objCount; i++ ) { SceneObject* p = parray[i]; totalCount++; // TIG if ((eleft[i] <= leftAABBEnd) && (eright[i] >= leftAABBStart)) { if (p->m_boundingBox.intersectAABB( leftAABB )) { left->add( p, this ); leftCount++; } } // TIG if ((eleft[i] <= rightAABBEnd) && (eright[i] >= rightAABBStart )) { if (p->m_boundingBox.intersectAABB( rightAABB )) { right->add( p, this ); rightCount++; } } } // Release if( eleft ) delete []eleft; if( eright ) delete []eright; if( parray ) delete []parray; left->setAABB( leftAABB ); right->setAABB( rightAABB ); node->setLeft( left ); node->setRight(right); node->setLeaf( false ); if (depth < MAX_TREE_DEPTH) { if (leftCount > 2) subdivide( left, leftAABB, depth + 1, leftCount); if (rightCount > 2) subdivide( right, rightAABB, depth + 1, rightCount ); } }