/* multithreaded binning builder */ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) { size_t size = range.size(); float leafSAH = params.sah_triangle_cost * range.leafSAH; float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_triangle_cost * range.splitSAH; /* make leaf node when threshold reached or SAH tells us */ if(params.small_enough_for_leaf(size, level) || (size <= params.max_leaf_size && leafSAH < splitSAH)) return create_leaf_node(range); /* perform split */ BVHObjectBinning left, right; range.split(&references[0], left, right); /* create inner node. */ InnerNode *inner; if(range.size() < THREAD_TASK_SIZE) { /* local build */ BVHNode *leftnode = build_node(left, level + 1); BVHNode *rightnode = build_node(right, level + 1); inner = new InnerNode(range.bounds(), leftnode, rightnode); } else { /* threaded build */ inner = new InnerNode(range.bounds()); task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true); task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true); } return inner; }
/* single threaded spatial split builder */ BVHNode* BVHBuild::build_node(const BVHRange& range, int level) { /* progress update */ progress_update(); if(progress.get_cancel()) return NULL; /* small enough or too deep => create leaf. */ if(!(range.size() > 0 && params.top_level && level == 0)) { if(params.small_enough_for_leaf(range.size(), level)) { progress_count += range.size(); return create_leaf_node(range); } } /* splitting test */ BVHMixedSplit split(this, range, level); if(!(range.size() > 0 && params.top_level && level == 0)) { if(split.no_split) { progress_count += range.size(); return create_leaf_node(range); } } /* do split */ BVHRange left, right; split.split(this, left, right, range); progress_total += left.size() + right.size() - range.size(); size_t total = progress_total; /* leaft node */ BVHNode *leftnode = build_node(left, level + 1); /* right node (modify start for splits) */ right.set_start(right.start() + progress_total - total); BVHNode *rightnode = build_node(right, level + 1); /* inner node */ return new InnerNode(range.bounds(), leftnode, rightnode); }
// Function to insert a new node in AVL Tree struct node* insert_node(struct node *tree, int num) { int balance_factor; if (tree == NULL) return(create_leaf_node(num)); if (tree->data > num) tree->left = insert_node(tree->left, num); else tree->right = insert_node(tree->right, num); // Update height tree->height = max(compute_height(tree->left), compute_height(tree->right)) + 1; // Check AVL tree is balanced or not balance_factor = get_balance_factor(tree); // If unbalanced, then 4 cases of rotation // 1. Left Left Case - Only 1 Right Rotate will solve unbalancy if (balance_factor > 1 && num < tree->left->data) return right_rotate(tree); // 2. Right Right Case - Only 1 Left Rotate will solve unbalancy if (balance_factor < -1 && num >= tree->right->data) return left_rotate(tree); // 3. Left Right Case - Left rotation on left child will make it left left case if (balance_factor > 1 && num >= tree->left->data) { tree->left = left_rotate(tree->left); return right_rotate(tree); } // 4. Right Left Case - Right rotation on right child will make it right right case if (balance_factor < -1 && num < tree->right->data) { tree->right = right_rotate(tree->right); return left_rotate(tree); } // If balanced then return unchanged node return tree; }
/* multithreaded binning builder */ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) { size_t size = range.size(); float leafSAH = params.sah_primitive_cost * range.leafSAH; float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH; /* have at least one inner node on top level, for performance and correct * visibility tests, since object instances do not check visibility flag */ if(!(range.size() > 0 && params.top_level && level == 0)) { /* make leaf node when threshold reached or SAH tells us */ if(params.small_enough_for_leaf(size, level) || (range_within_max_leaf_size(range) && leafSAH < splitSAH)) return create_leaf_node(range); } /* perform split */ BVHObjectBinning left, right; range.split(&references[0], left, right); /* create inner node. */ InnerNode *inner; if(range.size() < THREAD_TASK_SIZE) { /* local build */ BVHNode *leftnode = build_node(left, level + 1); BVHNode *rightnode = build_node(right, level + 1); inner = new InnerNode(range.bounds(), leftnode, rightnode); } else { /* threaded build */ inner = new InnerNode(range.bounds()); task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true); task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true); } return inner; }
// Recursively subdivide triangles into two groups, by determining // a split plane and sorting the triangles into "left-of" and "right-of". static bvh_node* bvh_build_recursive(int depth, boundingbox bbox, triangle* triangles, int num_triangles) { vec3 bbox_size, bbox_center; int i, j, t; int sorted_dimensions[3]; int split_axis; float split_value; int num_triangles_left, num_triangles_right; boundingbox left_bbox, right_bbox; bvh_node *left_child, *right_child; if (depth == max_depth || num_triangles <= acceptable_leaf_size) { // Create a leaf node #ifdef VERBOSE if (num_triangles > acceptable_leaf_size) printf("[%d] Maximum depth reached, forced to create a leaf of %d triangles\n", depth, num_triangles); else printf("[%d] Creating a leaf node of %d triangles\n", depth, num_triangles); #endif return create_leaf_node(bbox, triangles, num_triangles); } // // Split the triangles into two groups, using a split plane based // on largest bbox side // bbox_size = v3_subtract(bbox.max, bbox.min); bbox_center = v3_multiply(v3_add(bbox.min, bbox.max), 0.5); // Sort bbox sides by size in descending order sorted_dimensions[0] = 0; sorted_dimensions[1] = 1; sorted_dimensions[2] = 2; // Good old bubble sort :) for (i = 0; i < 2; i++) { for (j = i+1; j < 3; j++) { if (v3_component(bbox_size, sorted_dimensions[i]) < v3_component(bbox_size, sorted_dimensions[j])) { t = sorted_dimensions[i]; sorted_dimensions[i] = sorted_dimensions[j]; sorted_dimensions[j] = t; } } } // Iterate over the three split dimensions in descending order of // bbox size on that dimension. When the triangles are unsplitable // (or not very favorably) continue to the next dimension. Create a // leaf with all triangles in case none of dimensions is a good // split candidate. for (i = 0; i < 3; i++) { // Partition the triangles on the chosen split axis, with the // split plane at the center of the bbox split_axis = sorted_dimensions[i]; split_value = v3_component(bbox_center, split_axis); #ifdef VERBOSE printf("[%d] Splitting on axis %d, value %.3f\n", depth, split_axis, split_value); #endif partition_on_split_value(&num_triangles_left, &num_triangles_right, triangles, num_triangles, split_axis, split_value); #ifdef VERBOSE printf("[%d] %d left, %d right\n", depth, num_triangles_left, num_triangles_right); #endif if (num_triangles_left == 0 || num_triangles_right == 0) continue; // Determine bboxes for the two new groups of triangles left_bbox = bound_triangles(triangles, num_triangles_left); if (v3_component(v3_subtract(left_bbox.max, left_bbox.min), split_axis) > 0.9 * v3_component(bbox_size, split_axis)) { //printf("[%d] skipping dimension (left)\n", split_axis); continue; } #ifdef VERBOSE printf("[%d] left bbox: %.3f, %.3f, %.3f .. %.3f, %.3f, %.3f\n", depth, left_bbox.min.x, left_bbox.min.y, left_bbox.min.z, left_bbox.max.x, left_bbox.max.y, left_bbox.max.z); #endif right_bbox = bound_triangles(triangles+num_triangles_left, num_triangles_right); if (v3_component(v3_subtract(right_bbox.max, right_bbox.min), split_axis) > 0.9 * v3_component(bbox_size, split_axis)) { //printf("[%d] skipping dimension (right)\n", split_axis); continue; } #ifdef VERBOSE printf("[%d] right bbox: %.3f, %.3f, %.3f .. %.3f, %.3f, %.3f\n", depth, right_bbox.min.x, right_bbox.min.y, right_bbox.min.z, right_bbox.max.x, right_bbox.max.y, right_bbox.max.z); #endif // Recurse using the two new groups left_child = bvh_build_recursive(depth+1, left_bbox, triangles, num_triangles_left); right_child = bvh_build_recursive(depth+1, right_bbox, triangles+num_triangles_left, num_triangles_right); // Create an inner code with two children return create_inner_node(left_child, right_child); } // Split dimensions exhausted, forced to create a leaf #ifdef VERBOSE printf("Split dimensions exhausted, creating a leaf of %d triangles\n", num_triangles); #endif return create_leaf_node(bbox, triangles, num_triangles); }