60 const int object_index)
68 for (
uint j = 0; j < num_triangles; j++) {
71 if (attr_mP ==
nullptr) {
80 else if (
params.num_motion_triangle_steps == 0 ||
params.use_spatial_split) {
86 const size_t num_verts = mesh->verts.size();
87 const size_t num_steps = mesh->motion_steps;
105 const int num_bvh_steps =
params.num_motion_triangle_steps * 2 + 1;
106 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
107 const size_t num_verts = mesh->verts.size();
108 const size_t num_steps = mesh->motion_steps;
117 prev_bounds.
grow(prev_verts[0]);
118 prev_bounds.
grow(prev_verts[1]);
119 prev_bounds.
grow(prev_verts[2]);
121 for (
int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
122 const float curr_time = (
float)(bvh_step)*num_bvh_steps_inv_1;
126 curr_bounds.
grow(curr_verts[0]);
127 curr_bounds.
grow(curr_verts[1]);
128 curr_bounds.
grow(curr_verts[2]);
132 const float prev_time = (
float)(bvh_step - 1) * num_bvh_steps_inv_1;
141 prev_bounds = curr_bounds;
150 const int object_index)
152 const Attribute *curve_attr_mP =
nullptr;
160 for (
uint j = 0; j < num_curves; j++) {
162 const float *curve_radius = hair->get_curve_radius().data();
163 for (
int k = 0; k < curve.
num_keys - 1; k++) {
164 if (curve_attr_mP ==
nullptr) {
175 else if (
params.num_motion_curve_steps == 0 ||
params.use_spatial_split) {
183 const size_t num_keys = hair->get_curve_keys().size();
184 const size_t num_steps = hair->get_motion_steps();
201 const int num_bvh_steps =
params.num_motion_curve_steps * 2 + 1;
202 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
203 const size_t num_steps = hair->get_motion_steps();
204 const float3 *curve_keys = hair->get_curve_keys().data();
206 const size_t num_keys = hair->get_curve_keys().size();
226 for (
int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
227 const float curr_time = (
float)(bvh_step)*num_bvh_steps_inv_1;
245 const float prev_time = (
float)(bvh_step - 1) * num_bvh_steps_inv_1;
255 prev_bounds = curr_bounds;
267 const Attribute *point_attr_mP =
nullptr;
272 const float3 *points_data = pointcloud->points.data();
273 const float *radius_data = pointcloud->radius.data();
274 const size_t num_points = pointcloud->
num_points();
275 const float4 *motion_data = (point_attr_mP) ? point_attr_mP->
data_float4() :
nullptr;
276 const size_t num_steps = pointcloud->get_motion_steps();
278 if (point_attr_mP ==
nullptr) {
280 for (
uint j = 0; j < num_points; j++) {
291 else if (
params.num_motion_point_steps == 0 ||
params.use_spatial_split) {
297 for (
uint j = 0; j < num_points; j++) {
316 const int num_bvh_steps =
params.num_motion_point_steps * 2 + 1;
317 const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1);
319 for (
uint j = 0; j < num_points; j++) {
321 const size_t num_steps = pointcloud->get_motion_steps();
329 points_data, radius_data, point_steps, num_points, num_steps, 0.0f, j);
333 for (
int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) {
334 const float curr_time = (
float)(bvh_step)*num_bvh_steps_inv_1;
336 points_data, radius_data, point_steps, num_points, num_steps, curr_time, j);
342 const float prev_time = (
float)(bvh_step - 1) * num_bvh_steps_inv_1;
351 prev_bounds = curr_bounds;
360 const int object_index)
363 Mesh *mesh =
static_cast<Mesh *
>(geom);
367 Hair *hair =
static_cast<Hair *
>(geom);
388 for (
size_t i = 0;
i < num_curves;
i++) {
398 Mesh *mesh =
static_cast<Mesh *
>(geom);
402 Hair *hair =
static_cast<Hair *
>(geom);
416 size_t num_alloc_references = 0;
420 if (!ob->is_traceable()) {
423 if (!ob->get_geometry()->is_instanced()) {
427 num_alloc_references++;
444 if (!ob->is_traceable()) {
448 if (!ob->get_geometry()->is_instanced()) {
494 params.use_spatial_split =
false;
510 params.use_spatial_split =
false;
520 double build_start_time;
539 if (
params.use_spatial_split) {
563 rootnode->update_visibility();
564 rootnode->update_time();
566 if (rootnode !=
nullptr) {
568 <<
" Build time: " <<
time_dt() - build_start_time <<
"\n"
569 <<
" Total number of nodes: "
572 <<
" Number of inner nodes: "
575 <<
" Number of leaf nodes: "
578 <<
" Number of unaligned nodes: "
581 <<
" Allocation slop factor: "
585 <<
" Maximum depth: "
604 "Building BVH %.0f%%, duplicates %.0f%%", progress_start * 100.0, duplicates * 100.0);
623 inner->
children[child] = std::move(node);
653 inner->
children[child] = std::move(node);
660 const size_t max_leaf_size =
max(
max(
params.max_triangle_leaf_size,
params.max_curve_leaf_size),
661 params.max_point_leaf_size);
663 if (
size > max_leaf_size) {
667 size_t num_triangles = 0;
668 size_t num_motion_triangles = 0;
669 size_t num_curves = 0;
670 size_t num_motion_curves = 0;
671 size_t num_points = 0;
672 size_t num_motion_points = 0;
674 for (
int i = 0;
i <
size;
i++) {
687 num_motion_triangles++;
703 return (num_triangles <=
params.max_triangle_leaf_size) &&
704 (num_motion_triangles <=
params.max_motion_triangle_leaf_size) &&
705 (num_curves <=
params.max_curve_leaf_size) &&
706 (num_motion_curves <=
params.max_motion_curve_leaf_size) &&
707 (num_points <=
params.max_point_leaf_size) &&
708 (num_motion_points <=
params.max_motion_point_leaf_size);
715 const float leafSAH =
params.sah_primitive_cost * range.
leafSAH;
722 if (!(range.
size() > 0 &&
params.top_level && level == 0)) {
724 if ((
params.small_enough_for_leaf(
size, level)) ||
732 float unalignedSplitSAH =
FLT_MAX;
733 float unalignedLeafSAH =
FLT_MAX;
735 bool do_unalinged_split =
false;
736 if (
params.use_unaligned_nodes && splitSAH >
params.unaligned_split_threshold * leafSAH) {
742 unalignedLeafSAH =
params.sah_primitive_cost * unaligned_range.
leafSAH;
743 if (!(range.
size() > 0 &&
params.top_level && level == 0)) {
744 if (unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH &&
751 if (unalignedSplitSAH < splitSAH) {
752 do_unalinged_split =
true;
759 if (do_unalinged_split) {
767 if (do_unalinged_split) {
781 inner = make_unique<InnerNode>(
bounds, std::move(leftnode), std::move(rightnode));
785 inner = make_unique<InnerNode>(
bounds);
791 [
this, inner_ptr, right, level] {
thread_build_node(inner_ptr, 1, right, level + 1); });
794 if (do_unalinged_split) {
795 inner->set_aligned_space(aligned_space);
819 if (!(range.
size() > 0 &&
params.top_level && level == 0)) {
820 if (
params.small_enough_for_leaf(range.
size(), level)) {
829 if (!(range.
size() > 0 &&
params.top_level && level == 0)) {
830 if (
split.no_split) {
835 const float leafSAH =
params.sah_primitive_cost *
split.leafSAH;
840 float unalignedSplitSAH =
FLT_MAX;
843 bool do_unalinged_split =
false;
844 if (
params.use_unaligned_nodes && splitSAH >
params.unaligned_split_threshold * leafSAH) {
853 if (unalignedSplitSAH < splitSAH) {
854 do_unalinged_split =
true;
861 if (do_unalinged_split) {
862 unaligned_split.
split(
this,
left, right, range);
871 if (do_unalinged_split) {
893 inner = make_unique<InnerNode>(
bounds, std::move(leftnode), std::move(rightnode));
897 inner = make_unique<InnerNode>(
bounds);
909 task_pool.push([
this, inner_ptr,
left, level, refs = std::move(left_references)]()
mutable {
912 task_pool.push([
this, inner_ptr, right, level, refs = std::move(right_references)]()
mutable {
917 if (do_unalinged_split) {
918 inner->set_aligned_space(aligned_space);
932 return make_unique<LeafNode>(
bounds, 0, 0, 0);
945 ref->
bounds(), visibility, start, start + 1);
947 leaf_node->time_to = ref->
time_to();
951 const int mid =
num / 2;
956 bounds.grow(leaf0->bounds);
957 bounds.grow(leaf1->bounds);
959 const float time_from =
min(leaf0->time_from, leaf1->time_from);
960 const float time_to =
max(leaf0->time_to, leaf1->time_to);
963 bounds, std::move(leaf0), std::move(leaf1));
964 inner_node->time_from = time_from;
965 inner_node->time_to = time_to;
987 using LeafStackAllocator = StackAllocator<256, int>;
988 using LeafTimeStackAllocator = StackAllocator<256, float2>;
989 using LeafReferenceStackAllocator = StackAllocator<256, BVHReference>;
1005 int num_new_prims = 0;
1007 for (
int i = 0;
i < range.
size();
i++) {
1011 p_ref[type_index].push_back(ref);
1012 p_type[type_index].push_back(ref.
prim_type());
1013 p_index[type_index].push_back(ref.
prim_index());
1014 p_object[type_index].push_back(ref.
prim_object());
1022 object_references.push_back(ref);
1038 size_t start_index = 0;
1043 local_prim_type.resize(num_new_prims);
1044 local_prim_index.resize(num_new_prims);
1045 local_prim_object.resize(num_new_prims);
1047 local_prim_time.resize(num_new_prims);
1050 const int num = (int)p_type[
i].
size();
1055 bool alignment_found =
false;
1056 for (
int j = 0; j <
num; ++j) {
1057 const int index = start_index + j;
1058 local_prim_type[index] = p_type[
i][j];
1059 local_prim_index[index] = p_index[
i][j];
1060 local_prim_object[index] = p_object[
i][j];
1062 local_prim_time[index] = p_time[
i][j];
1064 if (
params.use_unaligned_nodes && !alignment_found) {
1069 bounds[
i], visibility[
i], start_index, start_index +
num);
1071 float time_from = 1.0f;
1072 float time_to = 0.0f;
1073 for (
int j = 0; j <
num; ++j) {
1078 leaf_node->time_from = time_from;
1079 leaf_node->time_to = time_to;
1081 if (alignment_found) {
1084 for (
int j = 0; j <
num; ++j) {
1087 ref, aligned_space);
1088 leaf_node->bounds.grow(ref_bounds);
1091 leaf_node->set_aligned_space(aligned_space);
1093 leaves[num_leaves++] = std::move(leaf_node);
1098 const int num_new_leaf_data = start_index;
1099 const size_t new_leaf_data_size =
sizeof(int) * num_new_leaf_data;
1101 if (
params.use_spatial_split) {
1112 const size_t range_end = start_index + range.
size();
1117 if (range_end >=
prim_type.capacity()) {
1119 const float factor = (1.0f -
progress);
1120 const size_t reserve = (size_t)(range_end + (
float)range_end * factor);
1137 if (new_leaf_data_size > 0) {
1138 memcpy(&
prim_type[start_index], local_prim_type.data(), new_leaf_data_size);
1139 memcpy(&
prim_index[start_index], local_prim_index.data(), new_leaf_data_size);
1140 memcpy(&
prim_object[start_index], local_prim_object.data(), new_leaf_data_size);
1143 &
prim_time[start_index], local_prim_time.data(),
sizeof(
float2) * num_new_leaf_data);
1153 start_index = range.
start();
1154 if (new_leaf_data_size > 0) {
1155 memcpy(&
prim_type[start_index], local_prim_type.data(), new_leaf_data_size);
1156 memcpy(&
prim_index[start_index], local_prim_index.data(), new_leaf_data_size);
1157 memcpy(&
prim_object[start_index], local_prim_object.data(), new_leaf_data_size);
1160 &
prim_time[start_index], local_prim_time.data(),
sizeof(
float2) * num_new_leaf_data);
1169 for (
int i = 0;
i < num_leaves; ++
i) {
1171 leaf->
lo += start_index;
1172 leaf->
hi += start_index;
1176 if (num_leaves == 0 || ob_num) {
1180 const BVHReference *ref = (ob_num) ? object_references.data() :
nullptr;
1188 if (num_leaves == 1) {
1193 return std::move(leaves[0]);
1195 if (num_leaves == 2) {
1196 return make_unique<InnerNode>(range.
bounds(), std::move(leaves[0]), std::move(leaves[1]));
1198 if (num_leaves == 3) {
1201 inner_bounds, std::move(leaves[1]), std::move(leaves[2]));
1202 return make_unique<InnerNode>(range.
bounds(), std::move(leaves[0]), std::move(inner));
1210 inner_bounds_a, std::move(leaves[0]), std::move(leaves[1]));
1212 inner_bounds_b, std::move(leaves[2]), std::move(leaves[3]));
1213 const BoundBox inner_bounds_c =
merge(inner_a->bounds, inner_b->bounds);
1215 inner_bounds_c, std::move(inner_a), std::move(inner_b));
1216 if (num_leaves == 5) {
1217 return make_unique<InnerNode>(range.
bounds(), std::move(inner_c), std::move(leaves[4]));
1221#undef MAX_ITEMS_PER_LEAF
1231 for (
int i = 0;
i < iterations;
i++) {
1240 if (node->
is_leaf() || max_depth < 0) {
1247 for (
size_t c = 0; c < 2; c++) {
1255 const float area0 = bounds0.
half_area();
1256 const float area1 = bounds1.
half_area();
1262 int best_child = -1;
1263 int best_target = -1;
1264 int best_other = -1;
1266 for (
size_t c = 0; c < 2; c++) {
1268 if (parent->
children[c]->is_leaf()) {
1273 const BoundBox &other = (c == 0) ? bounds1 : bounds0;
1280 const float cost0 =
merge(other, target1).half_area() - child_area[c];
1281 const float cost1 =
merge(target0, other).half_area() - child_area[c];
1283 if (
min(cost0, cost1) < best_cost) {
1284 best_child = (int)c;
1285 best_other = (int)(1 - c);
1287 if (cost0 < cost1) {
1299 if (best_cost >= 0) {
1303 assert(best_child == 0 || best_child == 1);
1304 assert(best_target != -1);
ATTR_WARN_UNUSED_RESULT const size_t num
static void split(const char *text, const char *seps, char ***str, int *count)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
static size_t count_primitives(Geometry *geom)
static size_t count_curve_segments(Hair *hair)
@ BVH_STAT_UNALIGNED_COUNT
Attribute * find(ustring name) const
void add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *mesh, const int object_index)
BVHBuild(const vector< Object * > &objects, array< int > &prim_type, array< int > &prim_index, array< int > &prim_object, array< float2 > &prim_time, const BVHParams ¶ms, Progress &progress)
void thread_build_spatial_split_node(InnerNode *inner, const int child, const BVHRange &range, vector< BVHReference > &references, int level)
unique_ptr< BVHNode > run()
void rotate(BVHNode *node, const int max_depth)
bool range_within_max_leaf_size(const BVHRange &range, const vector< BVHReference > &references) const
thread_spin_lock spatial_spin_lock
void add_references(BVHRange &root)
void add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, const int i)
unique_ptr< BVHNode > create_leaf_node(const BVHRange &range, const vector< BVHReference > &references)
size_t spatial_free_index
void add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair, const int object_index)
BVHUnaligned unaligned_heuristic
friend class BVHObjectBinning
unique_ptr< BVHNode > create_object_leaf_nodes(const BVHReference *ref, const int start, const int num)
array< float2 > & prim_time
vector< Object * > objects
unique_ptr< BVHNode > build_node(const BVHRange &range, vector< BVHReference > &references, const int level, BVHSpatialStorage *storage)
array< int > & prim_index
enumerable_thread_specific< BVHSpatialStorage > spatial_storage
size_t progress_original_total
float spatial_min_overlap
void thread_build_node(InnerNode *inner, const int child, const BVHObjectBinning &range, const int level)
double progress_start_time
array< int > & prim_object
friend class BVHMixedSplit
vector< BVHReference > references
void add_reference_points(BoundBox &root, BoundBox ¢er, PointCloud *pointcloud, const int i)
void add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, const int object_index)
__forceinline void split(BVHBuild *builder, BVHRange &left, BVHRange &right, const BVHRange &range)
void split(BVHReference *prims, BVHObjectBinning &left_o, BVHObjectBinning &right_o) const
__forceinline const BoundBox & unaligned_bounds()
__forceinline int size() const
__forceinline int start() const
__forceinline const BoundBox & bounds() const
__forceinline void set_start(const int start_)
__forceinline int end() const
__forceinline int prim_type() const
__forceinline int prim_object() const
__forceinline float time_from() const
__forceinline const BoundBox & bounds() const
__forceinline float time_to() const
__forceinline int prim_index() const
bool is_pointcloud() const
virtual bool has_motion_blur() const
Curve get_curve(const size_t i) const
size_t num_curves() const
PrimitiveType primitive_type() const override
unique_ptr< BVHNode > children[kNumMaxChildren]
#define PRIMITIVE_PACK_SEGMENT(type, segment)
#define PRIMITIVE_INDEX(type)
#define CCL_NAMESPACE_END
#define assert(assertion)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
@ ATTR_STD_MOTION_VERTEX_POSITION
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
string string_human_readable_number(size_t num)
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
virtual bool is_leaf() const =0
__forceinline float half_area() const
__forceinline float safe_area() const
__forceinline void grow(const float3 &pt)
__forceinline float3 center2() const
void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox &bounds) const
void cardinal_motion_keys(const float3 *curve_keys, const float *curve_radius, const float4 *key_steps, const size_t num_curve_keys, const size_t num_steps, const float time, size_t k0, size_t k1, size_t k2, size_t k3, float4 r_keys[4]) const
bool valid(const float3 *verts) const
void bounds_grow(const float3 *verts, BoundBox &bounds) const
void motion_verts(const float3 *verts, const float3 *vert_steps, const size_t num_verts, const size_t num_steps, const float time, float3 r_verts[3]) const
bool has_motion_blur() const override
size_t num_triangles() const
Triangle get_triangle(const size_t i) const
PrimitiveType primitive_type() const override
NODE_DECLARE BoundBox bounds
void bounds_grow(const float3 *points, const float *radius, BoundBox &bounds) const
float4 motion_key(const float3 *points, const float *radius, const float4 *point_steps, const size_t num_points, const size_t num_steps, const float time, size_t p) const
Point get_point(const int i) const
size_t num_points() const
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN double time_dt()