Exemple #1
0
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 );
	}
}
Exemple #2
0
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 );
    }
}