Blender  V3.3
node_geo_proximity.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 #include "BLI_timeit.hh"
5 
6 #include "DNA_mesh_types.h"
7 
8 #include "BKE_bvhutils.h"
9 #include "BKE_geometry_set.hh"
10 
11 #include "UI_interface.h"
12 #include "UI_resources.h"
13 
14 #include "node_geometry_util.hh"
15 
17 
19 
21 {
22  b.add_input<decl::Geometry>(N_("Target"))
23  .only_realized_data()
25  b.add_input<decl::Vector>(N_("Source Position")).implicit_field();
26  b.add_output<decl::Vector>(N_("Position")).dependent_field();
27  b.add_output<decl::Float>(N_("Distance")).dependent_field();
28 }
29 
30 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
31 {
32  uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE);
33 }
34 
36 {
37  NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__);
39  node->storage = node_storage;
40 }
41 
43  const IndexMask mask,
44  const Mesh &mesh,
46  const MutableSpan<float> r_distances,
47  const MutableSpan<float3> r_locations)
48 {
49  BVHTreeFromMesh bvh_data;
50  switch (type) {
53  break;
56  break;
59  break;
60  }
61 
62  if (bvh_data.tree == nullptr) {
63  return false;
64  }
65 
66  threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
67  BVHTreeNearest nearest;
68  copy_v3_fl(nearest.co, FLT_MAX);
69  nearest.index = -1;
70 
71  for (int i : range) {
72  const int index = mask[i];
73  /* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
74  nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[index]);
75 
76  BLI_bvhtree_find_nearest(
77  bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
78 
79  if (nearest.dist_sq < r_distances[index]) {
80  r_distances[index] = nearest.dist_sq;
81  if (!r_locations.is_empty()) {
82  r_locations[index] = nearest.co;
83  }
84  }
85  }
86  });
87 
88  free_bvhtree_from_mesh(&bvh_data);
89  return true;
90 }
91 
93  const IndexMask mask,
94  const PointCloud &pointcloud,
95  MutableSpan<float> r_distances,
96  MutableSpan<float3> r_locations)
97 {
98  BVHTreeFromPointCloud bvh_data;
99  BKE_bvhtree_from_pointcloud_get(&bvh_data, &pointcloud, 2);
100  if (bvh_data.tree == nullptr) {
101  return false;
102  }
103 
104  threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
105  BVHTreeNearest nearest;
106  copy_v3_fl(nearest.co, FLT_MAX);
107  nearest.index = -1;
108 
109  for (int i : range) {
110  const int index = mask[i];
111  /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
112  * This is ok because we only need to find the closest point in the pointcloud if it's
113  * closer than the mesh. */
114  nearest.dist_sq = r_distances[index];
115 
116  BLI_bvhtree_find_nearest(
117  bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
118 
119  if (nearest.dist_sq < r_distances[index]) {
120  r_distances[index] = nearest.dist_sq;
121  if (!r_locations.is_empty()) {
122  r_locations[index] = nearest.co;
123  }
124  }
125  }
126  });
127 
128  free_bvhtree_from_pointcloud(&bvh_data);
129  return true;
130 }
131 
133  private:
134  GeometrySet target_;
136 
137  public:
139  : target_(std::move(target)), type_(type)
140  {
141  static fn::MFSignature signature = create_signature();
142  this->set_signature(&signature);
143  }
144 
146  {
147  blender::fn::MFSignatureBuilder signature{"Geometry Proximity"};
148  signature.single_input<float3>("Source Position");
149  signature.single_output<float3>("Position");
150  signature.single_output<float>("Distance");
151  return signature.build();
152  }
153 
155  {
156  const VArray<float3> &src_positions = params.readonly_single_input<float3>(0,
157  "Source Position");
158  MutableSpan<float3> positions = params.uninitialized_single_output_if_required<float3>(
159  1, "Position");
160  /* Make sure there is a distance array, used for finding the smaller distance when there are
161  * multiple components. Theoretically it would be possible to avoid using the distance array
162  * when there is only one component. However, this only adds an allocation and a single float
163  * comparison per vertex, so it's likely not worth it. */
164  MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
165 
166  distances.fill_indices(mask, FLT_MAX);
167 
168  bool success = false;
169  if (target_.has_mesh()) {
170  success |= calculate_mesh_proximity(
171  src_positions, mask, *target_.get_mesh_for_read(), type_, distances, positions);
172  }
173 
174  if (target_.has_pointcloud() && type_ == GEO_NODE_PROX_TARGET_POINTS) {
176  src_positions, mask, *target_.get_pointcloud_for_read(), distances, positions);
177  }
178 
179  if (!success) {
180  if (!positions.is_empty()) {
181  positions.fill_indices(mask, float3(0));
182  }
183  if (!distances.is_empty()) {
184  distances.fill_indices(mask, 0.0f);
185  }
186  return;
187  }
188 
189  if (params.single_output_is_required(2, "Distance")) {
190  threading::parallel_for(mask.index_range(), 2048, [&](IndexRange range) {
191  for (const int i : range) {
192  const int j = mask[i];
193  distances[j] = std::sqrt(distances[j]);
194  }
195  });
196  }
197  }
198 };
199 
201 {
202  GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
203  geometry_set_target.ensure_owns_direct_data();
204 
205  if (!geometry_set_target.has_mesh() && !geometry_set_target.has_pointcloud()) {
206  params.set_default_remaining_outputs();
207  return;
208  }
209 
210  const NodeGeometryProximity &storage = node_storage(params.node());
211  Field<float3> position_field = params.extract_input<Field<float3>>("Source Position");
212 
213  auto proximity_fn = std::make_unique<ProximityFunction>(
214  std::move(geometry_set_target),
215  static_cast<GeometryNodeProximityTargetType>(storage.target_element));
216  auto proximity_op = std::make_shared<FieldOperation>(
217  FieldOperation(std::move(proximity_fn), {std::move(position_field)}));
218 
219  params.set_output("Position", Field<float3>(proximity_op, 0));
220  params.set_output("Distance", Field<float>(proximity_op, 1));
221 }
222 
223 } // namespace blender::nodes::node_geo_proximity_cc
224 
226 {
227  namespace file_ns = blender::nodes::node_geo_proximity_cc;
228 
229  static bNodeType ntype;
230 
231  geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY);
234  &ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
238  nodeRegisterType(&ntype);
239 }
BVHTree * BKE_bvhtree_from_pointcloud_get(struct BVHTreeFromPointCloud *data, const struct PointCloud *pointcloud, int tree_type)
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_EDGES
Definition: BKE_bvhutils.h:71
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
@ BVHTREE_FROM_VERTS
Definition: BKE_bvhutils.h:70
void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data)
Definition: bvhutils.cc:1451
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define GEO_NODE_PROXIMITY
Definition: BKE_node.h:1438
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define UNUSED(x)
GeometryNodeProximityTargetType
@ GEO_NODE_PROX_TARGET_EDGES
@ GEO_NODE_PROX_TARGET_POINTS
@ GEO_NODE_PROX_TARGET_FACES
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
float float3[3]
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
ProximityFunction(GeometrySet target, GeometryNodeProximityTargetType type)
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
OperationNode * node
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static bool calculate_mesh_proximity(const VArray< float3 > &positions, const IndexMask mask, const Mesh &mesh, const GeometryNodeProximityTargetType type, const MutableSpan< float > r_distances, const MutableSpan< float3 > r_locations)
static void node_geo_exec(GeoNodeExecParams params)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_declare(NodeDeclarationBuilder &b)
static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
static bool calculate_pointcloud_proximity(const VArray< float3 > &positions, const IndexMask mask, const PointCloud &pointcloud, MutableSpan< float > r_distances, MutableSpan< float3 > r_locations)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
MutableSpan< float3 > positions
void register_node_type_geo_proximity()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
struct BVHTree * tree
Definition: BKE_bvhutils.h:231
const PointCloud * get_pointcloud_for_read() const
void ensure_owns_direct_data()
const Mesh * get_mesh_for_read() const
bool has_mesh() const
bool has_pointcloud() const
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480