Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc238
1 files changed, 106 insertions, 132 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index d71cb09f1bd..bfcde288cfb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -14,8 +14,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "BLI_kdopbvh.h"
-#include "BLI_kdtree.h"
#include "BLI_task.hh"
#include "BLI_timeit.hh"
@@ -53,179 +51,155 @@ static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
sizeof(NodeGeometryAttributeProximity), __func__);
- node_storage->target_geometry_element =
- GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES;
+ node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
node->storage = node_storage;
}
namespace blender::nodes {
-static void proximity_calc(MutableSpan<float> distance_span,
- MutableSpan<float3> location_span,
- const VArray<float3> &positions,
- BVHTreeFromMesh &tree_data_mesh,
- BVHTreeFromPointCloud &tree_data_pointcloud,
- const bool bvh_mesh_success,
- const bool bvh_pointcloud_success,
- const bool store_distances,
- const bool store_locations)
+static void calculate_mesh_proximity(const VArray<float3> &positions,
+ const Mesh &mesh,
+ const GeometryNodeAttributeProximityTargetType type,
+ MutableSpan<float> r_distances,
+ MutableSpan<float3> r_locations)
{
- IndexRange range = positions.index_range();
- threading::parallel_for(range, 512, [&](IndexRange range) {
- BVHTreeNearest nearest_from_mesh;
- BVHTreeNearest nearest_from_pointcloud;
+ BVHTreeFromMesh bvh_data;
+ switch (type) {
+ case GEO_NODE_PROXIMITY_TARGET_POINTS:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_VERTS, 2);
+ break;
+ case GEO_NODE_PROXIMITY_TARGET_EDGES:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_EDGES, 2);
+ break;
+ case GEO_NODE_PROXIMITY_TARGET_FACES:
+ BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
+ break;
+ }
- copy_v3_fl(nearest_from_mesh.co, FLT_MAX);
- copy_v3_fl(nearest_from_pointcloud.co, FLT_MAX);
+ if (bvh_data.tree == nullptr) {
+ return;
+ }
- nearest_from_mesh.index = -1;
- nearest_from_pointcloud.index = -1;
+ threading::parallel_for(positions.index_range(), 512, [&](IndexRange range) {
+ BVHTreeNearest nearest;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.index = -1;
for (int i : range) {
/* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest_from_mesh.dist_sq = len_squared_v3v3(nearest_from_mesh.co, positions[i]);
-
- if (bvh_mesh_success) {
- BLI_bvhtree_find_nearest(tree_data_mesh.tree,
- positions[i],
- &nearest_from_mesh,
- tree_data_mesh.nearest_callback,
- &tree_data_mesh);
- }
+ nearest.dist_sq = float3::distance_squared(nearest.co, positions[i]);
- /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
- * This is ok because we only need to find the closest point in the pointcloud if it's closer
- * than the mesh. */
- nearest_from_pointcloud.dist_sq = nearest_from_mesh.dist_sq;
-
- if (bvh_pointcloud_success) {
- BLI_bvhtree_find_nearest(tree_data_pointcloud.tree,
- positions[i],
- &nearest_from_pointcloud,
- tree_data_pointcloud.nearest_callback,
- &tree_data_pointcloud);
- }
+ BLI_bvhtree_find_nearest(
+ bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
- if (nearest_from_pointcloud.dist_sq < nearest_from_mesh.dist_sq) {
- if (store_distances) {
- distance_span[i] = sqrtf(nearest_from_pointcloud.dist_sq);
- }
- if (store_locations) {
- location_span[i] = nearest_from_pointcloud.co;
- }
- }
- else {
- if (store_distances) {
- distance_span[i] = sqrtf(nearest_from_mesh.dist_sq);
- }
- if (store_locations) {
- location_span[i] = nearest_from_mesh.co;
+ if (nearest.dist_sq < r_distances[i]) {
+ r_distances[i] = nearest.dist_sq;
+ if (!r_locations.is_empty()) {
+ r_locations[i] = nearest.co;
}
}
}
});
+
+ free_bvhtree_from_mesh(&bvh_data);
}
-static bool bvh_from_mesh(const Mesh *target_mesh,
- int target_geometry_element,
- BVHTreeFromMesh &r_tree_data_mesh)
+static void calculate_pointcloud_proximity(const VArray<float3> &positions,
+ const PointCloud &pointcloud,
+ MutableSpan<float> r_distances,
+ MutableSpan<float3> r_locations)
{
- BVHCacheType bvh_type = BVHTREE_FROM_LOOPTRI;
- switch (target_geometry_element) {
- case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS:
- bvh_type = BVHTREE_FROM_VERTS;
- break;
- case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_EDGES:
- bvh_type = BVHTREE_FROM_EDGES;
- break;
- case GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES:
- bvh_type = BVHTREE_FROM_LOOPTRI;
- break;
+ BVHTreeFromPointCloud bvh_data;
+ BKE_bvhtree_from_pointcloud_get(&bvh_data, &pointcloud, 2);
+ if (bvh_data.tree == nullptr) {
+ return;
}
- BKE_bvhtree_from_mesh_get(&r_tree_data_mesh, target_mesh, bvh_type, 2);
- if (r_tree_data_mesh.tree == nullptr) {
- return false;
- }
- return true;
-}
+ threading::parallel_for(positions.index_range(), 512, [&](IndexRange range) {
+ BVHTreeNearest nearest;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.index = -1;
-static bool bvh_from_pointcloud(const PointCloud *target_pointcloud,
- BVHTreeFromPointCloud &r_tree_data_pointcloud)
-{
- BKE_bvhtree_from_pointcloud_get(&r_tree_data_pointcloud, target_pointcloud, 2);
- if (r_tree_data_pointcloud.tree == nullptr) {
- return false;
- }
- return true;
+ for (int i : range) {
+ /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
+ * This is ok because we only need to find the closest point in the pointcloud if it's
+ * closer than the mesh. */
+ nearest.dist_sq = r_distances[i];
+
+ BLI_bvhtree_find_nearest(
+ bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
+
+ if (nearest.dist_sq < r_distances[i]) {
+ r_distances[i] = nearest.dist_sq;
+ if (!r_locations.is_empty()) {
+ r_locations[i] = nearest.co;
+ }
+ }
+ }
+ });
+
+ free_bvhtree_from_pointcloud(&bvh_data);
}
static void attribute_calc_proximity(GeometryComponent &component,
- GeometrySet &geometry_set_target,
+ GeometrySet &target,
GeoNodeExecParams &params)
{
- /* This node works on the "point" domain, since that is where positions are stored. */
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
-
- const std::string distance_attribute_name = params.get_input<std::string>("Distance");
+ const std::string distance_name = params.get_input<std::string>("Distance");
OutputAttribute_Typed<float> distance_attribute =
- component.attribute_try_get_for_output_only<float>(distance_attribute_name, result_domain);
+ component.attribute_try_get_for_output_only<float>(distance_name, ATTR_DOMAIN_POINT);
- const std::string location_attribute_name = params.get_input<std::string>("Position");
+ const std::string location_name = params.get_input<std::string>("Position");
OutputAttribute_Typed<float3> location_attribute =
- component.attribute_try_get_for_output_only<float3>(location_attribute_name, result_domain);
+ component.attribute_try_get_for_output_only<float3>(location_name, ATTR_DOMAIN_POINT);
ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position");
if (!position_attribute || (!distance_attribute && !location_attribute)) {
return;
}
- BLI_assert(position_attribute.varray->type().is<float3>());
-
- const bNode &node = params.node();
- const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)
- node.storage;
-
- BVHTreeFromMesh tree_data_mesh;
- BVHTreeFromPointCloud tree_data_pointcloud;
- bool bvh_mesh_success = false;
- bool bvh_pointcloud_success = false;
+ GVArray_Typed<float3> positions{*position_attribute.varray};
+ const NodeGeometryAttributeProximity &storage =
+ *(const NodeGeometryAttributeProximity *)params.node().storage;
- if (geometry_set_target.has_mesh()) {
- bvh_mesh_success = bvh_from_mesh(
- geometry_set_target.get_mesh_for_read(), storage.target_geometry_element, tree_data_mesh);
+ Array<float> distances_internal;
+ MutableSpan<float> distances;
+ if (distance_attribute) {
+ distances = distance_attribute.as_span();
}
-
- if (geometry_set_target.has_pointcloud() &&
- storage.target_geometry_element ==
- GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS) {
- bvh_pointcloud_success = bvh_from_pointcloud(geometry_set_target.get_pointcloud_for_read(),
- tree_data_pointcloud);
+ else {
+ /* Theoretically it would be possible to avoid using the distance array when it's not required
+ * and there is only one component. However, this only adds an allocation and a single float
+ * comparison per vertex, so it's likely not worth it. */
+ distances_internal.reinitialize(positions.size());
+ distances = distances_internal;
}
-
- GVArray_Typed<float3> positions{*position_attribute.varray};
- MutableSpan<float> distance_span = distance_attribute ? distance_attribute.as_span() :
- MutableSpan<float>();
- MutableSpan<float3> location_span = location_attribute ? location_attribute.as_span() :
- MutableSpan<float3>();
-
- proximity_calc(distance_span,
- location_span,
- positions,
- tree_data_mesh,
- tree_data_pointcloud,
- bvh_mesh_success,
- bvh_pointcloud_success,
- distance_attribute, /* Boolean. */
- location_attribute); /* Boolean. */
-
- if (bvh_mesh_success) {
- free_bvhtree_from_mesh(&tree_data_mesh);
+ distances.fill(FLT_MAX);
+ MutableSpan<float3> locations = location_attribute ? location_attribute.as_span() :
+ MutableSpan<float3>();
+
+ if (target.has_mesh()) {
+ calculate_mesh_proximity(
+ positions,
+ *target.get_mesh_for_read(),
+ static_cast<GeometryNodeAttributeProximityTargetType>(storage.target_geometry_element),
+ distances,
+ locations);
}
- if (bvh_pointcloud_success) {
- free_bvhtree_from_pointcloud(&tree_data_pointcloud);
+
+ if (target.has_pointcloud() &&
+ storage.target_geometry_element == GEO_NODE_PROXIMITY_TARGET_POINTS) {
+ calculate_pointcloud_proximity(
+ positions, *target.get_pointcloud_for_read(), distances, locations);
}
if (distance_attribute) {
+ /* Squared distances are used above to speed up comparisons,
+ * so do the square roots now if necessary for the output attribute. */
+ threading::parallel_for(distances.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ distances[i] = std::sqrt(distances[i]);
+ }
+ });
distance_attribute.save();
}
if (location_attribute) {