예제 #1
0
BVHNode* BVHBuild::run()
{
    BVHRange root;

    /* add references */
    add_references(root);

    if(progress.get_cancel())
        return NULL;

    /* init spatial splits */
    if(params.top_level) /* todo: get rid of this */
        params.use_spatial_split = false;

    spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
    spatial_right_bounds.clear();
    spatial_right_bounds.resize(max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1);

    /* init progress updates */
    progress_start_time = time_dt();
    progress_count = 0;
    progress_total = references.size();
    progress_original_total = progress_total;

    prim_type.resize(references.size());
    prim_index.resize(references.size());
    prim_object.resize(references.size());

    /* build recursively */
    BVHNode *rootnode;

    if(params.use_spatial_split) {
        /* singlethreaded spatial split build */
        rootnode = build_node(root, 0);
    }
    else {
        /* multithreaded binning build */
        BVHObjectBinning rootbin(root, (references.size())? &references[0]: NULL);
        rootnode = build_node(rootbin, 0);
        task_pool.wait_work();
    }

    /* delete if we canceled */
    if(rootnode) {
        if(progress.get_cancel()) {
            rootnode->deleteSubtree();
            rootnode = NULL;
        }
        else if(!params.use_spatial_split) {
            /*rotate(rootnode, 4, 5);*/
            rootnode->update_visibility();
        }
    }

    return rootnode;
}
예제 #2
0
BVHNode* BVHBuild::run()
{
	BVHRange root;

	/* add references */
	add_references(root);

	if(progress.get_cancel())
		return NULL;

	/* init spatial splits */
	if(params.top_level) {
		/* NOTE: Technically it is supported by the builder but it's not really
		 * optimized for speed yet and not really clear yet if it has measurable
		 * improvement on render time. Needs some extra investigation before
		 * enabling spatial split for top level BVH.
		 */
		params.use_spatial_split = false;
	}

	spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
	if(params.use_spatial_split) {
		/* NOTE: The API here tries to be as much ready for multi-threaded build
		 * as possible, but at the same time it tries not to introduce any
		 * changes in behavior for until all refactoring needed for threading is
		 * finished.
		 *
		 * So we currently allocate single storage for now, which is only used by
		 * the only thread working on the spatial BVH build.
		 */
		spatial_storage.resize(TaskScheduler::num_threads() + 1);
		size_t num_bins = max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1;
		foreach(BVHSpatialStorage &storage, spatial_storage) {
			storage.right_bounds.clear();
		}
		spatial_storage[0].right_bounds.resize(num_bins);
	}
예제 #3
0
BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
                                 BVHSpatialStorage *storage,
                                 const BVHRange& range,
                                 vector<BVHReference> *references,
                                 float nodeSAH)
: sah(FLT_MAX),
  dim(0),
  pos(0.0f),
  storage_(storage),
  references_(references)
{
	/* initialize bins. */
	float3 origin = range.bounds().min;
	float3 binSize = (range.bounds().max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
	float3 invBinSize = 1.0f / binSize;

	for(int dim = 0; dim < 3; dim++) {
		for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
			BVHSpatialBin& bin = storage_->bins[dim][i];

			bin.bounds = BoundBox::empty;
			bin.enter = 0;
			bin.exit = 0;
		}
	}

	/* chop references into bins. */
	for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
		const BVHReference& ref = references_->at(refIdx);
		float3 firstBinf = (ref.bounds().min - origin) * invBinSize;
		float3 lastBinf = (ref.bounds().max - origin) * invBinSize;
		int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
		int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z);

		firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
		lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);

		for(int dim = 0; dim < 3; dim++) {
			BVHReference currRef = ref;

			for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
				BVHReference leftRef, rightRef;

				split_reference(builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
				storage_->bins[dim][i].bounds.grow(leftRef.bounds());
				currRef = rightRef;
			}

			storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
			storage_->bins[dim][firstBin[dim]].enter++;
			storage_->bins[dim][lastBin[dim]].exit++;
		}
	}

	/* select best split plane. */
	for(int dim = 0; dim < 3; dim++) {
		/* sweep right to left and determine bounds. */
		BoundBox right_bounds = BoundBox::empty;

		storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
		for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
			right_bounds.grow(storage_->bins[dim][i].bounds);
			storage_->right_bounds[i - 1] = right_bounds;
		}

		/* sweep left to right and select lowest SAH. */
		BoundBox left_bounds = BoundBox::empty;
		int leftNum = 0;
		int rightNum = range.size();

		for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
			left_bounds.grow(storage_->bins[dim][i - 1].bounds);
			leftNum += storage_->bins[dim][i - 1].enter;
			rightNum -= storage_->bins[dim][i - 1].exit;

			float sah = nodeSAH +
				left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
				storage_->right_bounds[i - 1].safe_area() * builder.params.primitive_cost(rightNum);

			if(sah < this->sah) {
				this->sah = sah;
				this->dim = dim;
				this->pos = origin[dim] + binSize[dim] * (float)i;
			}
		}
	}
}