diff --git a/source/blender/blenkernel/BKE_bvhutils.hh b/source/blender/blenkernel/BKE_bvhutils.hh index 75fd07fe33d..d58d92c2bf2 100644 --- a/source/blender/blenkernel/BKE_bvhutils.hh +++ b/source/blender/blenkernel/BKE_bvhutils.hh @@ -93,11 +93,13 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, const float v2[3]); struct BVHTreeFromPointCloud { - std::unique_ptr tree; + const BVHTree *tree = nullptr; BVHTree_NearestPointCallback nearest_callback; - const float (*coords)[3]; + Span positions; + + std::unique_ptr owned_tree; }; BVHTreeFromPointCloud bvhtree_from_pointcloud_get(const PointCloud &pointcloud, diff --git a/source/blender/blenkernel/BKE_pointcloud.hh b/source/blender/blenkernel/BKE_pointcloud.hh index 5535e87f02c..f026108a468 100644 --- a/source/blender/blenkernel/BKE_pointcloud.hh +++ b/source/blender/blenkernel/BKE_pointcloud.hh @@ -10,6 +10,7 @@ */ #include "BLI_bounds_types.hh" +#include "BLI_kdopbvh.hh" #include "BLI_math_vector_types.hh" #include "BLI_shared_cache.hh" #include "BLI_string_ref.hh" @@ -42,6 +43,8 @@ struct PointCloudRuntime { /** Stores weak references to material data blocks. */ std::unique_ptr bake_materials; + SharedCache> bvh_cache; + MEM_CXX_CLASS_ALLOC_FUNCS("PointCloudRuntime"); }; diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 09cbe9be6d2..3587dbf0e06 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -15,6 +15,7 @@ #include "BKE_bvhutils.hh" #include "BKE_editmesh.hh" #include "BKE_mesh.hh" +#include "BKE_pointcloud.hh" namespace blender::bke { @@ -811,21 +812,54 @@ BVHTreeFromMesh bvhtree_from_mesh_verts_init(const Mesh &mesh, const IndexMask & /** \name Point Cloud BVH Building * \{ */ -BVHTreeFromPointCloud bvhtree_from_pointcloud_get(const PointCloud &pointcloud, - const IndexMask &points_mask) +static BVHTreeFromPointCloud create_points_tree_data(const BVHTree *tree, + const Span positions) { - const Span positions = pointcloud.positions(); - std::unique_ptr tree = create_tree_from_verts(positions, points_mask); - if (!tree) { - return {}; - } BVHTreeFromPointCloud data{}; - data.tree = std::move(tree); + data.tree = tree; + data.positions = positions; data.nearest_callback = nullptr; - data.coords = (const float(*)[3])positions.data(); return data; } -/** \} */ +static BVHTreeFromPointCloud create_point_cloud_tree_data(const BVHTree *tree, + const Span positions) +{ + BVHTreeFromPointCloud data{}; + data.tree = tree; + data.positions = positions; + return data; +} + +static BVHTreeFromPointCloud create_point_cloud_tree_data( + std::unique_ptr tree, const Span positions) +{ + BVHTreeFromPointCloud data = create_points_tree_data(tree.get(), positions); + data.owned_tree = std::move(tree); + return data; +} + +BVHTreeFromPointCloud bvhtree_from_pointcloud_get(const PointCloud &pointcloud, + const IndexMask &points_mask) +{ + if (points_mask.size() == pointcloud.totpoint) { + return pointcloud.bvh_tree(); + } + const Span positions = pointcloud.positions(); + return create_point_cloud_tree_data(create_tree_from_verts(positions, points_mask), positions); +} } // namespace blender::bke + +blender::bke::BVHTreeFromPointCloud PointCloud::bvh_tree() const +{ + using namespace blender; + using namespace blender::bke; + const Span positions = this->positions(); + this->runtime->bvh_cache.ensure([&](std::unique_ptr &data) { + data = create_tree_from_verts(positions, positions.index_range()); + }); + return create_point_cloud_tree_data(this->runtime->bvh_cache.data().get(), positions); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 3cfdc9bc885..75b8ca10ee0 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -85,6 +85,7 @@ static void pointcloud_copy_data(Main * /*bmain*/, pointcloud_dst->runtime = new blender::bke::PointCloudRuntime(); pointcloud_dst->runtime->bounds_cache = pointcloud_src->runtime->bounds_cache; + pointcloud_dst->runtime->bvh_cache = pointcloud_src->runtime->bvh_cache; if (pointcloud_src->runtime->bake_materials) { pointcloud_dst->runtime->bake_materials = std::make_unique( @@ -457,6 +458,7 @@ void BKE_pointcloud_data_update(Depsgraph *depsgraph, Scene *scene, Object *obje void PointCloud::tag_positions_changed() { this->runtime->bounds_cache.tag_dirty(); + this->runtime->bvh_cache.tag_dirty(); } void PointCloud::tag_radii_changed() diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h index 2ac1b9e6be4..844bd27ea69 100644 --- a/source/blender/makesdna/DNA_pointcloud_types.h +++ b/source/blender/makesdna/DNA_pointcloud_types.h @@ -26,6 +26,7 @@ namespace blender { template class Span; namespace bke { class AttributeAccessor; +struct BVHTreeFromPointCloud; class MutableAttributeAccessor; struct PointCloudRuntime; } // namespace bke @@ -73,6 +74,8 @@ typedef struct PointCloud { /** Get the largest material index used by the point-cloud or `nullopt` if it is empty. */ std::optional material_index_max() const; + blender::bke::BVHTreeFromPointCloud bvh_tree() const; + void count_memory(blender::MemoryCounter &memory) const; #endif diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc index ca0bc6605a4..d61e8bb3746 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc @@ -228,7 +228,7 @@ class ProximityFunction : public mf::MultiFunction { const_cast(&trees.mesh_bvh)); } if (trees.pointcloud_bvh.tree != nullptr) { - BLI_bvhtree_find_nearest(trees.pointcloud_bvh.tree.get(), + BLI_bvhtree_find_nearest(trees.pointcloud_bvh.tree, sample_position, &nearest, trees.pointcloud_bvh.nearest_callback, diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc index 58f9d42baa5..074e9e37f29 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc @@ -91,7 +91,7 @@ static void get_closest_pointcloud_points(const bke::BVHTreeFromPointCloud &tree nearest.index = -1; nearest.dist_sq = FLT_MAX; const float3 position = positions[i]; - BLI_bvhtree_find_nearest(tree_data.tree.get(), + BLI_bvhtree_find_nearest(tree_data.tree, position, &nearest, tree_data.nearest_callback,