41 prim_type(prim_type_),
42 prim_index(prim_index_),
43 prim_object(prim_object_),
44 prim_time(prim_time_),
47 progress_start_time(0.0),
48 unaligned_heuristic(objects_)
60 const int object_index)
68 for (
uint j = 0; j < num_triangles; j++) {
71 if (attr_mP ==
nullptr) {
86 const size_t num_verts =
mesh->verts.size();
87 const size_t num_steps =
mesh->motion_steps;
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) {
167 curve.bounds_grow(k, hair->get_curve_keys().data(), curve_radius,
bounds);
182 curve.bounds_grow(k, hair->get_curve_keys().data(), curve_radius,
bounds);
183 const size_t num_keys = hair->get_curve_keys().size();
184 const size_t num_steps = hair->get_motion_steps();
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();
212 curve.cardinal_motion_keys(curve_keys,
224 curve.bounds_grow(prev_keys, prev_bounds);
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;
229 curve.cardinal_motion_keys(curve_keys,
241 curve.bounds_grow(curr_keys, curr_bounds);
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++) {
297 for (
uint j = 0; j < num_points; j++) {
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)
367 Hair *hair =
static_cast<Hair *
>(geom);
388 for (
size_t i = 0; i < num_curves; i++) {
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()) {
520 double build_start_time;
537 unique_ptr<BVHNode> rootnode;
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);
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++;
732 float unalignedSplitSAH =
FLT_MAX;
733 float unalignedLeafSAH =
FLT_MAX;
735 bool do_unalinged_split =
false;
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) {
775 unique_ptr<InnerNode> inner;
779 unique_ptr<BVHNode> rightnode =
build_node(right, level + 1);
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);
830 if (
split.no_split) {
840 float unalignedSplitSAH =
FLT_MAX;
843 bool do_unalinged_split =
false;
853 if (unalignedSplitSAH < splitSAH) {
854 do_unalinged_split =
true;
861 if (do_unalinged_split) {
871 if (do_unalinged_split) {
879 unique_ptr<InnerNode> inner;
891 unique_ptr<BVHNode> rightnode =
build_node(right, right_references, level + 1, storage);
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);
944 unique_ptr<BVHNode> leaf_node = make_unique<LeafNode>(
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);
962 unique_ptr<BVHNode> inner_node = make_unique<InnerNode>(
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];
1068 unique_ptr<LeafNode> leaf_node = make_unique<LeafNode>(
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;
1112 const size_t range_end = start_index +
range.size();
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) {
1200 unique_ptr<BVHNode> inner = make_unique<InnerNode>(
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));
1209 unique_ptr<BVHNode> inner_a = make_unique<InnerNode>(
1210 inner_bounds_a, std::move(leaves[0]), std::move(leaves[1]));
1211 unique_ptr<BVHNode> inner_b = make_unique<InnerNode>(
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);
1214 unique_ptr<BVHNode> inner_c = make_unique<InnerNode>(
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()
int max_triangle_leaf_size
int num_motion_triangle_steps
float spatial_split_alpha
int max_motion_curve_leaf_size
int max_motion_point_leaf_size
int max_motion_triangle_leaf_size
int num_motion_point_steps
float unaligned_split_threshold
__forceinline bool small_enough_for_leaf(const int size, const int level)
int num_motion_curve_steps
__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
Transform compute_aligned_space(const BVHObjectBinning &range, const BVHReference *references) const
BoundBox compute_aligned_prim_boundbox(const BVHReference &prim, const Transform &aligned_space) const
BoundBox compute_aligned_boundbox(const BVHObjectBinning &range, const BVHReference *references, const Transform &aligned_space, BoundBox *cent_bounds=nullptr) 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]
void set_substatus(const string &substatus_)
void reserve(const size_t newcapacity)
T * resize(const size_t newsize)
#define CCL_NAMESPACE_END
#define assert(assertion)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define PRIMITIVE_PACK_SEGMENT(type, segment)
@ ATTR_STD_MOTION_VERTEX_POSITION
#define PRIMITIVE_INDEX(type)
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,...)
__forceinline float half_area() const
__forceinline float safe_area() const
__forceinline void grow(const float3 &pt)
__forceinline float3 center2() 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
void push(TaskRunFunction &&task)
void wait_work(Summary *stats=nullptr)
std::unique_lock< std::mutex > thread_scoped_lock
CCL_NAMESPACE_BEGIN double time_dt()