Ejemplo n.º 1
0
//Performs a plane sweep across the triangles to find the best splitting plane using the SAH.
//From "On building fast kd-Trees for Ray Tracing, and on doing that in O(N log N)" by I. Wald and V. Havran
pair<pair<SplitPlane, SplitSide>, double> KDNode::findPlane(vector<Triangle*>& triangles, AABB boundingBox) {
	double bestCost = INFINITY;
	SplitPlane bestPlane(0, 0);
	SplitSide bestSide;

	for (int dim = 0; dim < 3; dim++) {
		vector<SweepEvent> events;

		for (auto t : triangles) {
			AABB b = t->getBoundingBox().intersection(boundingBox);

			if (b.getSize()[dim] == 0.0) {
				events.push_back(SweepEvent(t, b.getStartpoint()[dim], PLANAR));
			}
			else {
				events.push_back(SweepEvent(t, b.getStartpoint()[dim], START));
				events.push_back(SweepEvent(t, b.getEndpoint()[dim], END));
			}
		}
		sort(events.begin(), events.end());

		int left = 0;
		int planar = 0;
		int right = triangles.size();

		for (int i = 0; i < events.size(); i++) {
			double coordinate = events[i].coordinate;
			SplitPlane plane(coordinate, dim);

			int pAdd = 0; int pPlan = 0; int pRem = 0;

			while (i < events.size() && events[i].coordinate == coordinate && events[i].type == END) {
				pRem++; i++;
			}
			while (i < events.size() && events[i].coordinate == coordinate && events[i].type == PLANAR) {
				pPlan++; i++;
			}
			while (i < events.size() && events[i].coordinate == coordinate && events[i].type == START) {
				pAdd++; i++;
			}

			planar = pPlan; right -= pPlan; right -= pRem;

			pair<double, SplitSide> result = SAH(plane, boundingBox, left, right, planar);
			
			if (result.first < bestCost) {
				bestCost = result.first;
				bestPlane = plane;
				bestSide = result.second;
			}
			left += pAdd; left += pPlan; planar = 0;
		}
	}
	return make_pair(make_pair(bestPlane, bestSide), bestCost);
}
Ejemplo n.º 2
0
void AABBTree::findBestPlane(const vector<Triangle>& T, const AABB& V, SplittingPlane& p_est, float& C_est, PlaneSide& pside_est)
{
    C_est = numeric_limits<float>::max();

    for(int axis=0; axis<3; axis++) {
        vector<SplitEvent> events;
        events.reserve(T.size()*2);

        for(int i=0; i<T.size(); ++i) {
            auto ti = T[i];
            AABB tibb = V.clip(ti);

            if(tibb.isPlanar()) {
                events.push_back(SplitEvent(ti, axis, tibb.minPos(axis), SplitEvent::LyingOnPlane));
            }
            else {
                events.push_back(SplitEvent(ti, axis, tibb.minPos(axis), SplitEvent::StartingOnPlane));
                events.push_back(SplitEvent(ti, axis, tibb.maxPos(axis), SplitEvent::EndingOnPlane));
            }
        }

        // sort the events
        sort(events.begin(), events.end());

        // test every candidate plane
        int NL = 0, NP = 0, NR = T.size();
        for(int i=0; i<events.size(); ++i) {
            auto p = events[i].p;

            int tLyingOnPlane = 0, tEndingOnPlane=0, tStartingOnPlane=0;
            while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::EndingOnPlane ) {
                ++tEndingOnPlane;
                i++;
            }
            while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::LyingOnPlane ) {
                ++tLyingOnPlane;
                i++;
            }
            while( i<events.size() && events[i].p.pe == p.pe && events[i].type == SplitEvent::StartingOnPlane ) {
                ++tStartingOnPlane;
                i++;
            }

            NP = tLyingOnPlane;
            NR -= tLyingOnPlane;
            NR -= tEndingOnPlane;

            float C;
            PlaneSide ps;
            SAH(p, V, NL, NR, NP, C, ps);

            if(C < C_est) {
                C_est = C;
                p_est = p;
                pside_est = ps;
            }
            NL += tStartingOnPlane;
            NL += tLyingOnPlane;
            NP = 0;
        }
    }
}
Ejemplo n.º 3
0
/* BVH construction based on the algorithm presented in the paper:
 *
 *     "Ray Tracing Deformable Scenes Using Dynamic Bounding Volume Hierarchies".
 *     Ingo Wald, Solomon Boulos, and Peter Shirley
 *     ACM Transactions on Graphics.
 *     Volume 26 Issue 1, 2007.
 */
void BVH::splitNode( BVHNode **node,
                     std::deque< PrimitiveAABBArea > &s,
                     std::size_t first,
                     std::size_t last,
                     float s_area )
{
    (*node) = new BVHNode();
    (*node)->first_ = first;
    (*node)->last_ = last;
    (*node)->left_ = nullptr;
    (*node)->right_ = nullptr;

    std::deque< PrimitiveAABBArea > s_aux;

    float best_cost = cost_intersec_tri_ * ( last + 1 - first );
    int best_axis = -1;
    int best_event = -1;

    for ( int axis = 1; axis <= 3; axis++ )
    {
        switch( axis )
        {
        case 1:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInX );
            break;
        case 2:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInY );
            break;
        case 3:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInZ );
            break;
        }

        s_aux = std::deque< PrimitiveAABBArea >( s.begin() + first, s.begin() + last + 1 );

        for ( std::size_t i = first; i <= last; i++ )
        {
            if ( i == first )
            {
                s[i].left_area_ = std::numeric_limits< float >::infinity();
                s_aux[0].left_aabb_ = s_aux[0].aabb_;
            }
            else
            {
                s[i].left_area_ = s_aux[ i - first - 1 ].left_aabb_.getArea();
                s_aux[ i - first ].left_aabb_ = s_aux[ i - first ].aabb_ + s_aux[ i - first - 1 ].left_aabb_;
            }
        }

        for ( long int i = last; i >= static_cast< long int >( first ); i-- )
        {
            if ( i == static_cast< long int >( last ) )
            {
                s[i].right_area_ = std::numeric_limits< float >::infinity();
                s_aux[ last - first ].right_aabb_ = s_aux[ last - first ].aabb_;
            }
            else
            {
                s[i].right_area_ = s_aux[ i - first  + 1 ].right_aabb_.getArea();
                s_aux[ i - first ].right_aabb_ = s_aux[ i - first ].aabb_ + s_aux[ i - first + 1 ].right_aabb_;
            }

            float this_cost = SAH( i - first + 1,
                                    s[i].left_area_,
                                    last - i,
                                    s[i].right_area_,
                                    s_area );

            if ( this_cost < best_cost )
            {
                best_cost = this_cost;
                best_event = i;
                best_axis = axis;
            }
        }
    }

    if ( best_axis == -1 ) // This is a leaf node
    {
        primitives_inserted_ += last - first + 1;
        std::stringstream progress_stream;
        progress_stream << "\r  BVH building progress ............: "
                        << std::fixed << std::setw( 6 )
                        << std::setprecision( 2 )
                        << 100.0f * static_cast< float >( primitives_inserted_ ) / primitives_.size()
                        << "%";
        std::clog << progress_stream.str();

        //if ( last == first )
        //    std::clog << "One primitive node!\n";

        for ( long unsigned int i = first; i <= last; i++ )
        {
            primitive_id_[i] = s[i].primitive_id_;

            if ( i == first )
                (*node)->aabb_ = s[i].aabb_;
            else
                (*node)->aabb_ = (*node)->aabb_ + s[i].aabb_;
        }
    }
    else // This is an inner node
    {
        // Make inner node with best_axis / best_event
        switch( best_axis )
        {
        case 1:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInX );
            break;
        case 2:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInY );
            break;
        case 3:
            std::sort( s.begin() + first, s.begin() + last + 1, Comparator::sortInZ );
            break;
        }

        splitNode( &(*node)->left_, s, first, best_event, s_area );
        splitNode( &(*node)->right_, s, best_event + 1, last, s_area );

        (*node)->aabb_ = (*node)->left_->aabb_ + (*node)->right_->aabb_;
    }
}