Exemple #1
0
BVHBuildNode *BVH::recursiveBuild(int start, int end, int *numTotalNodes)
{
	AABoundingBox bbox;
	for(int i=start; i<end; i++){
		bbox.join(m_buildData[i].m_bbox);
	}
	BVHBuildNode *node = new BVHBuildNode();
    (*numTotalNodes)++;

	int numTriangles = end - start;

	if(numTriangles == 1){
		createLeafNode(start,end,bbox,node, numTotalNodes);
	}
	else{
		AABoundingBox bboxCentroids;
		for(int i=start; i<end; i++){
			bboxCentroids.join(m_buildData[i].m_centroid);
		}
		int dim = bboxCentroids.getMaximumExtent();
		if(bboxCentroids.min(dim) == bboxCentroids.max(dim)){
			createLeafNode(start,end,bbox,node,numTotalNodes);
		}
        else{
            float splitCost;
            int splitBucket;
            findSAHSplit(dim,start,end,bboxCentroids,bbox, &splitCost, &splitBucket);
            if(numTriangles > 6 || splitCost < numTriangles){
                BVHTriangleInfo *midPtr = std::partition(&m_buildData[start], &m_buildData[end], CompareToBucket(dim, splitBucket, 12, bboxCentroids));
                int mid = midPtr - &m_buildData[0];
                if(mid == start || mid == end){
                    mid = start+1;
                }
                node->initInterior(dim, recursiveBuild(start,mid,numTotalNodes), recursiveBuild(mid,end,numTotalNodes));
            }
            else{
                createLeafNode(start,end,bbox,node,numTotalNodes);
            }
        }
	}
	
	return node;
}
BVHBuildNode *CBVH_PBRT::recursiveBuild ( std::vector<BVHPrimitiveInfo> &primitiveInfo,
                                          int start,
                                          int end,
                                          int *totalNodes,
                                          CONST_VECTOR_OBJECT &orderedPrims )
{
    wxASSERT( totalNodes != NULL );
    wxASSERT( start >= 0 );
    wxASSERT( end   >= 0 );
    wxASSERT( start != end );
    wxASSERT( start < end );
    wxASSERT( start <= (int)primitiveInfo.size() );
    wxASSERT( end   <= (int)primitiveInfo.size() );

    (*totalNodes)++;

    // !TODO: implement an memory Arena
    BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ),
                                                                  L1_CACHE_LINE_SIZE ) );
    m_addresses_pointer_to_mm_free.push_back( node );

    node->bounds.Reset();
    node->firstPrimOffset = 0;
    node->nPrimitives = 0;
    node->splitAxis = 0;
    node->children[0] = NULL;
    node->children[1] = NULL;

    // Compute bounds of all primitives in BVH node
    CBBOX bounds;
    bounds.Reset();

    for( int i = start; i < end; ++i )
        bounds.Union( primitiveInfo[i].bounds );

    int nPrimitives = end - start;

    if( nPrimitives == 1 )
    {
        // Create leaf _BVHBuildNode_
        int firstPrimOffset = orderedPrims.size();

        for( int i = start; i < end; ++i )
        {
            int primitiveNr = primitiveInfo[i].primitiveNumber;
            wxASSERT( primitiveNr < (int)m_primitives.size() );
            orderedPrims.push_back( m_primitives[ primitiveNr ] );
        }

        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
    }
    else
    {
        // Compute bound of primitive centroids, choose split dimension _dim_
        CBBOX centroidBounds;
        centroidBounds.Reset();

        for( int i = start; i < end; ++i )
            centroidBounds.Union( primitiveInfo[i].centroid );

        const int dim = centroidBounds.MaxDimension();

        // Partition primitives into two sets and build children
        int mid = (start + end) / 2;

        if( fabs( centroidBounds.Max()[dim] -
                  centroidBounds.Min()[dim] ) < (FLT_EPSILON + FLT_EPSILON) )
        {
            // Create leaf _BVHBuildNode_
            const int firstPrimOffset = orderedPrims.size();

            for( int i = start; i < end; ++i )
            {
                int primitiveNr = primitiveInfo[i].primitiveNumber;

                wxASSERT( (primitiveNr >= 0) &&
                          (primitiveNr < (int)m_primitives.size()) );

                const COBJECT *obj = static_cast<const COBJECT *>( m_primitives[ primitiveNr ] );

                wxASSERT( obj != NULL );

                orderedPrims.push_back( obj );
            }

            node->InitLeaf( firstPrimOffset, nPrimitives, bounds );
        }
        else
        {
            // Partition primitives based on _splitMethod_
            switch( m_splitMethod )
            {
            case SPLIT_MIDDLE:
            {
                // Partition primitives through node's midpoint
                float pmid = centroidBounds.GetCenter( dim );

                BVHPrimitiveInfo *midPtr = std::partition( &primitiveInfo[start],
                                                           &primitiveInfo[end - 1] + 1,
                                                           CompareToMid( dim, pmid ) );
                mid = midPtr - &primitiveInfo[0];

                wxASSERT( (mid >= start) &&
                          (mid <= end) );

                if( (mid != start) && (mid != end) )
                    // for lots of prims with large overlapping bounding boxes, this
                    // may fail to partition; in that case don't break and fall through
                    // to SPLIT_EQUAL_COUNTS
                    break;
            }

            case SPLIT_EQUALCOUNTS:
            {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;

                std::nth_element( &primitiveInfo[start],
                                  &primitiveInfo[mid],
                                  &primitiveInfo[end - 1] + 1,
                                  ComparePoints( dim ) );

                break;
            }

            case SPLIT_SAH:
            default:
            {
                // Partition primitives using approximate SAH
                if( nPrimitives <= 2 )
                {
                    // Partition primitives into equally-sized subsets
                    mid = (start + end) / 2;

                    std::nth_element( &primitiveInfo[start],
                                      &primitiveInfo[mid],
                                      &primitiveInfo[end - 1] + 1,
                                      ComparePoints( dim ) );
                }
                else
                {
                    // Allocate _BucketInfo_ for SAH partition buckets
                    const int nBuckets = 12;

                    BucketInfo buckets[nBuckets];

                    for( int i = 0; i < nBuckets; ++i )
                    {
                        buckets[i].count = 0;
                        buckets[i].bounds.Reset();
                    }

                    // Initialize _BucketInfo_ for SAH partition buckets
                    for( int i = start; i < end; ++i )
                    {
                        int b = nBuckets *
                                centroidBounds.Offset( primitiveInfo[i].centroid )[dim];

                        if( b == nBuckets )
                            b = nBuckets - 1;

                        wxASSERT( b >= 0 && b < nBuckets );

                        buckets[b].count++;
                        buckets[b].bounds.Union( primitiveInfo[i].bounds );
                    }

                    // Compute costs for splitting after each bucket
                    float cost[nBuckets - 1];

                    for( int i = 0; i < (nBuckets - 1); ++i )
                    {
                        CBBOX b0, b1;

                        b0.Reset();
                        b1.Reset();

                        int count0 = 0;
                        int count1 = 0;

                        for( int j = 0; j <= i; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count0 += buckets[j].count;
                                b0.Union( buckets[j].bounds );
                            }
                        }

                        for( int j = i + 1; j < nBuckets; ++j )
                        {
                            if( buckets[j].count )
                            {
                                count1 += buckets[j].count;
                                b1.Union( buckets[j].bounds );
                            }
                        }

                        cost[i] = 1.0f +
                                  ( count0 * b0.SurfaceArea() +
                                    count1 * b1.SurfaceArea() ) /
                                  bounds.SurfaceArea();
                    }

                    // Find bucket to split at that minimizes SAH metric
                    float minCost = cost[0];
                    int minCostSplitBucket = 0;

                    for( int i = 1; i < (nBuckets - 1); ++i )
                    {
                        if( cost[i] < minCost )
                        {
                            minCost = cost[i];
                            minCostSplitBucket = i;
                        }
                    }

                    // Either create leaf or split primitives at selected SAH
                    // bucket
                    if( (nPrimitives > m_maxPrimsInNode) ||
                        (minCost < (float)nPrimitives) )
                    {
                        BVHPrimitiveInfo *pmid =
                            std::partition( &primitiveInfo[start],
                                            &primitiveInfo[end - 1] + 1,
                                            CompareToBucket( minCostSplitBucket,
                                                             nBuckets,
                                                             dim,
                                                             centroidBounds ) );
                        mid = pmid - &primitiveInfo[0];

                        wxASSERT( (mid >= start) &&
                                  (mid <= end) );
                    }
                    else
                    {
                        // Create leaf _BVHBuildNode_
                        const int firstPrimOffset = orderedPrims.size();

                        for( int i = start; i < end; ++i )
                        {
                            const int primitiveNr = primitiveInfo[i].primitiveNumber;

                            wxASSERT( primitiveNr < (int)m_primitives.size() );

                            orderedPrims.push_back( m_primitives[ primitiveNr ] );
                        }

                        node->InitLeaf( firstPrimOffset, nPrimitives, bounds );

                        return node;
                    }
                }
                break;
            }
            }

            node->InitInterior( dim,
                                recursiveBuild( primitiveInfo,
                                                start,
                                                mid,
                                                totalNodes,
                                                orderedPrims ),
                                recursiveBuild( primitiveInfo,
                                                mid,
                                                end,
                                                totalNodes,
                                                orderedPrims) );
        }
    }

    return node;
}
Exemple #3
0
BVHBuildNode *BVHAccel::recursiveBuild(MemoryArena &buildArena,
        vector<BVHPrimitiveInfo> &buildData, uint32_t start,
        uint32_t end, uint32_t *totalNodes,
        vector<Reference<Primitive> > &orderedPrims) {
    Assert(start != end);
    (*totalNodes)++;
    BVHBuildNode *node = buildArena.Alloc<BVHBuildNode>();
    // Compute bounds of all primitives in BVH node
    BBox bbox;
    for (uint32_t i = start; i < end; ++i)
        bbox = Union(bbox, buildData[i].bounds);
    uint32_t nPrimitives = end - start;
    if (nPrimitives == 1) {
        // Create leaf _BVHBuildNode_
        uint32_t firstPrimOffset = orderedPrims.size();
        for (uint32_t i = start; i < end; ++i) {
            uint32_t primNum = buildData[i].primitiveNumber;
            orderedPrims.push_back(primitives[primNum]);
        }
        node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
    }
    else {
        // Compute bound of primitive centroids, choose split dimension _dim_
        BBox centroidBounds;
        for (uint32_t i = start; i < end; ++i)
            centroidBounds = Union(centroidBounds, buildData[i].centroid);
        int dim = centroidBounds.MaximumExtent();

        // Partition primitives into two sets and build children
        uint32_t mid = (start + end) / 2;
        if (centroidBounds.pMax[dim] == centroidBounds.pMin[dim]) {
            // Create leaf _BVHBuildNode_
            uint32_t firstPrimOffset = orderedPrims.size();
            for (uint32_t i = start; i < end; ++i) {
                uint32_t primNum = buildData[i].primitiveNumber;
                orderedPrims.push_back(primitives[primNum]);
            }
            node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
            return node;
        }

        // Partition primitives based on _splitMethod_
        switch (splitMethod) {
        case SPLIT_MIDDLE: {
            // Partition primitives through node's midpoint
            float pmid = .5f * (centroidBounds.pMin[dim] + centroidBounds.pMax[dim]);
            BVHPrimitiveInfo *midPtr = std::partition(&buildData[start],
                                                      &buildData[end-1]+1,
                                                      CompareToMid(dim, pmid));
            mid = midPtr - &buildData[0];
            if (mid != start && mid != end)
                // for lots of prims with large overlapping bounding boxes, this
                // may fail to partition; in that case don't break and fall through
                // to SPLIT_EQUAL_COUNTS
                break;
        }
        case SPLIT_EQUAL_COUNTS: {
            // Partition primitives into equally-sized subsets
            mid = (start + end) / 2;
            std::nth_element(&buildData[start], &buildData[mid],
                             &buildData[end-1]+1, ComparePoints(dim));
            break;
        }
        case SPLIT_SAH: default: {
            // Partition primitives using approximate SAH
            if (nPrimitives <= 4) {
                // Partition primitives into equally-sized subsets
                mid = (start + end) / 2;
                std::nth_element(&buildData[start], &buildData[mid],
                                 &buildData[end-1]+1, ComparePoints(dim));
            }
            else {
                // Allocate _BucketInfo_ for SAH partition buckets
                const int nBuckets = 12;
                struct BucketInfo {
                    BucketInfo() { count = 0; }
                    int count;
                    BBox bounds;
                };
                BucketInfo buckets[nBuckets];

                // Initialize _BucketInfo_ for SAH partition buckets
                for (uint32_t i = start; i < end; ++i) {
                    int b = nBuckets *
                        ((buildData[i].centroid[dim] - centroidBounds.pMin[dim]) /
                         (centroidBounds.pMax[dim] - centroidBounds.pMin[dim]));
                    if (b == nBuckets) b = nBuckets-1;
                    Assert(b >= 0 && b < nBuckets);
                    buckets[b].count++;
                    buckets[b].bounds = Union(buckets[b].bounds, buildData[i].bounds);
                }

                // Compute costs for splitting after each bucket
                float cost[nBuckets-1];
                for (int i = 0; i < nBuckets-1; ++i) {
                    BBox b0, b1;
                    int count0 = 0, count1 = 0;
                    for (int j = 0; j <= i; ++j) {
                        b0 = Union(b0, buckets[j].bounds);
                        count0 += buckets[j].count;
                    }
                    for (int j = i+1; j < nBuckets; ++j) {
                        b1 = Union(b1, buckets[j].bounds);
                        count1 += buckets[j].count;
                    }
                    cost[i] = .125f + (count0*b0.SurfaceArea() + count1*b1.SurfaceArea()) /
                              bbox.SurfaceArea();
                }

                // Find bucket to split at that minimizes SAH metric
                float minCost = cost[0];
                uint32_t minCostSplit = 0;
                for (int i = 1; i < nBuckets-1; ++i) {
                    if (cost[i] < minCost) {
                        minCost = cost[i];
                        minCostSplit = i;
                    }
                }

                // Either create leaf or split primitives at selected SAH bucket
                if (nPrimitives > maxPrimsInNode ||
                    minCost < nPrimitives) {
                    BVHPrimitiveInfo *pmid = std::partition(&buildData[start],
                        &buildData[end-1]+1,
                        CompareToBucket(minCostSplit, nBuckets, dim, centroidBounds));
                    mid = pmid - &buildData[0];
                }
                
                else {
                    // Create leaf _BVHBuildNode_
                    uint32_t firstPrimOffset = orderedPrims.size();
                    for (uint32_t i = start; i < end; ++i) {
                        uint32_t primNum = buildData[i].primitiveNumber;
                        orderedPrims.push_back(primitives[primNum]);
                    }
                    node->InitLeaf(firstPrimOffset, nPrimitives, bbox);
                    return node;
                }
            }
            break;
        }
        }
        node->InitInterior(dim,
                           recursiveBuild(buildArena, buildData, start, mid,
                                          totalNodes, orderedPrims),
                           recursiveBuild(buildArena, buildData, mid, end,
                                          totalNodes, orderedPrims));
    }
    return node;
}