Blender  V2.93
node_geo_attribute_proximity.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BLI_kdopbvh.h"
18 #include "BLI_kdtree.h"
19 #include "BLI_task.hh"
20 #include "BLI_timeit.hh"
21 
22 #include "DNA_mesh_types.h"
23 
24 #include "BKE_bvhutils.h"
25 
26 #include "UI_interface.h"
27 #include "UI_resources.h"
28 
29 #include "node_geometry_util.hh"
30 
32  {SOCK_GEOMETRY, N_("Geometry")},
33  {SOCK_GEOMETRY, N_("Target")},
34  {SOCK_STRING, N_("Distance")},
35  {SOCK_STRING, N_("Position")},
36  {-1, ""},
37 };
38 
40  {SOCK_GEOMETRY, N_("Geometry")},
41  {-1, ""},
42 };
43 
45  bContext *UNUSED(C),
46  PointerRNA *ptr)
47 {
48  uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE);
49 }
50 
52 {
54  sizeof(NodeGeometryAttributeProximity), __func__);
55 
56  node_storage->target_geometry_element =
58  node->storage = node_storage;
59 }
60 
61 namespace blender::nodes {
62 
63 static void proximity_calc(MutableSpan<float> distance_span,
64  MutableSpan<float3> location_span,
65  Span<float3> positions,
66  BVHTreeFromMesh &tree_data_mesh,
67  BVHTreeFromPointCloud &tree_data_pointcloud,
68  const bool bvh_mesh_success,
69  const bool bvh_pointcloud_success,
70  const bool store_distances,
71  const bool store_locations)
72 {
73  IndexRange range = positions.index_range();
74  parallel_for(range, 512, [&](IndexRange range) {
75  BVHTreeNearest nearest_from_mesh;
76  BVHTreeNearest nearest_from_pointcloud;
77 
78  copy_v3_fl(nearest_from_mesh.co, FLT_MAX);
79  copy_v3_fl(nearest_from_pointcloud.co, FLT_MAX);
80 
81  nearest_from_mesh.index = -1;
82  nearest_from_pointcloud.index = -1;
83 
84  for (int i : range) {
85  /* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
86  nearest_from_mesh.dist_sq = len_squared_v3v3(nearest_from_mesh.co, positions[i]);
87 
88  if (bvh_mesh_success) {
89  BLI_bvhtree_find_nearest(tree_data_mesh.tree,
90  positions[i],
91  &nearest_from_mesh,
92  tree_data_mesh.nearest_callback,
93  &tree_data_mesh);
94  }
95 
96  /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
97  * This is ok because we only need to find the closest point in the pointcloud if it's closer
98  * than the mesh. */
99  nearest_from_pointcloud.dist_sq = nearest_from_mesh.dist_sq;
100 
101  if (bvh_pointcloud_success) {
102  BLI_bvhtree_find_nearest(tree_data_pointcloud.tree,
103  positions[i],
104  &nearest_from_pointcloud,
105  tree_data_pointcloud.nearest_callback,
106  &tree_data_pointcloud);
107  }
108 
109  if (nearest_from_pointcloud.dist_sq < nearest_from_mesh.dist_sq) {
110  if (store_distances) {
111  distance_span[i] = sqrtf(nearest_from_pointcloud.dist_sq);
112  }
113  if (store_locations) {
114  location_span[i] = nearest_from_pointcloud.co;
115  }
116  }
117  else {
118  if (store_distances) {
119  distance_span[i] = sqrtf(nearest_from_mesh.dist_sq);
120  }
121  if (store_locations) {
122  location_span[i] = nearest_from_mesh.co;
123  }
124  }
125  }
126  });
127 }
128 
129 static bool bvh_from_mesh(const Mesh *target_mesh,
130  int target_geometry_element,
131  BVHTreeFromMesh &r_tree_data_mesh)
132 {
134  switch (target_geometry_element) {
136  bvh_type = BVHTREE_FROM_VERTS;
137  break;
139  bvh_type = BVHTREE_FROM_EDGES;
140  break;
142  bvh_type = BVHTREE_FROM_LOOPTRI;
143  break;
144  }
145 
146  /* This only updates a cache and can be considered to be logically const. */
147  BKE_bvhtree_from_mesh_get(&r_tree_data_mesh, const_cast<Mesh *>(target_mesh), bvh_type, 2);
148  if (r_tree_data_mesh.tree == nullptr) {
149  return false;
150  }
151  return true;
152 }
153 
154 static bool bvh_from_pointcloud(const PointCloud *target_pointcloud,
155  BVHTreeFromPointCloud &r_tree_data_pointcloud)
156 {
157  BKE_bvhtree_from_pointcloud_get(&r_tree_data_pointcloud, target_pointcloud, 2);
158  if (r_tree_data_pointcloud.tree == nullptr) {
159  return false;
160  }
161  return true;
162 }
163 
165  GeometrySet &geometry_set_target,
167 {
168  /* This node works on the "point" domain, since that is where positions are stored. */
169  const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
170 
171  const std::string distance_attribute_name = params.get_input<std::string>("Distance");
172  OutputAttributePtr distance_attribute = component.attribute_try_get_for_output(
173  distance_attribute_name, result_domain, CD_PROP_FLOAT);
174 
175  const std::string location_attribute_name = params.get_input<std::string>("Position");
176  OutputAttributePtr location_attribute = component.attribute_try_get_for_output(
177  location_attribute_name, result_domain, CD_PROP_FLOAT3);
178 
179  ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
180  BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3);
181 
182  if (!position_attribute || (!distance_attribute && !location_attribute)) {
183  return;
184  }
185 
186  const bNode &node = params.node();
188  node.storage;
189 
190  BVHTreeFromMesh tree_data_mesh;
191  BVHTreeFromPointCloud tree_data_pointcloud;
192  bool bvh_mesh_success = false;
193  bool bvh_pointcloud_success = false;
194 
195  if (geometry_set_target.has_mesh()) {
196  bvh_mesh_success = bvh_from_mesh(
197  geometry_set_target.get_mesh_for_read(), storage.target_geometry_element, tree_data_mesh);
198  }
199 
200  if (geometry_set_target.has_pointcloud() &&
201  storage.target_geometry_element ==
203  bvh_pointcloud_success = bvh_from_pointcloud(geometry_set_target.get_pointcloud_for_read(),
204  tree_data_pointcloud);
205  }
206 
207  Span<float3> position_span = position_attribute->get_span<float3>();
208 
209  MutableSpan<float> distance_span = distance_attribute ?
210  distance_attribute->get_span_for_write_only<float>() :
212  MutableSpan<float3> location_span = location_attribute ?
213  location_attribute->get_span_for_write_only<float3>() :
215 
216  proximity_calc(distance_span,
217  location_span,
218  position_span,
219  tree_data_mesh,
220  tree_data_pointcloud,
221  bvh_mesh_success,
222  bvh_pointcloud_success,
223  distance_attribute, /* Boolean. */
224  location_attribute); /* Boolean. */
225 
226  if (bvh_mesh_success) {
227  free_bvhtree_from_mesh(&tree_data_mesh);
228  }
229  if (bvh_pointcloud_success) {
230  free_bvhtree_from_pointcloud(&tree_data_pointcloud);
231  }
232 
233  if (distance_attribute) {
234  distance_attribute.apply_span_and_save();
235  }
236  if (location_attribute) {
237  location_attribute.apply_span_and_save();
238  }
239 }
240 
242 {
243  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
244  GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
245 
246  geometry_set = geometry_set_realize_instances(geometry_set);
247 
248  /* This isn't required. This node should be rewritten to handle instances
249  * for the target geometry set. However, the generic BVH API complicates this. */
250  geometry_set_target = geometry_set_realize_instances(geometry_set_target);
251 
252  if (geometry_set.has<MeshComponent>()) {
254  geometry_set.get_component_for_write<MeshComponent>(), geometry_set_target, params);
255  }
256  if (geometry_set.has<PointCloudComponent>()) {
258  geometry_set.get_component_for_write<PointCloudComponent>(), geometry_set_target, params);
259  }
260 
261  params.set_output("Geometry", geometry_set);
262 }
263 
264 } // namespace blender::nodes
265 
267 {
268  static bNodeType ntype;
269 
271  &ntype, GEO_NODE_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
275  node_type_storage(&ntype,
276  "NodeGeometryAttributeProximity",
281  nodeRegisterType(&ntype);
282 }
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, const BVHCacheType bvh_cache_type, const int tree_type)
Definition: bvhutils.c:1413
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.c:1701
BVHCacheType
Definition: BKE_bvhutils.h:89
@ BVHTREE_FROM_EDGES
Definition: BKE_bvhutils.h:91
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:93
@ BVHTREE_FROM_VERTS
Definition: BKE_bvhutils.h:90
BVHTree * BKE_bvhtree_from_pointcloud_get(struct BVHTreeFromPointCloud *data, const struct PointCloud *pointcloud, const int tree_type)
void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data)
Definition: bvhutils.c:1754
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4559
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:4599
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1654
A kd-tree for nearest neighbor search.
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
#define UNUSED(x)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_FACES
@ GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_POINTS
@ GEO_NODE_ATTRIBUTE_PROXIMITY_TARGET_GEOMETRY_ELEMENT_EDGES
@ SOCK_GEOMETRY
@ SOCK_STRING
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Separate Vector White RGB Map Separate Set Z Dilate Combine Combine Color Channel Split ID Combine Luminance Directional Alpha Distance Hue Movie Ellipse Bokeh View Corner Anti Mix RGB Hue Separate TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC Boolean Random Edge Subdivision Point Object Attribute Attribute Attribute Color Attribute Attribute Vector Point Attribute Sample Collection GEO_NODE_ATTRIBUTE_PROXIMITY
#define C
Definition: RandGen.cpp:39
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
OperationNode * node
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define sqrtf(x)
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
std::unique_ptr< ReadAttribute > ReadAttributePtr
static void proximity_calc(MutableSpan< float > distance_span, MutableSpan< float3 > location_span, Span< 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 geo_node_attribute_proximity_exec(GeoNodeExecParams params)
static bool bvh_from_pointcloud(const PointCloud *target_pointcloud, BVHTreeFromPointCloud &r_tree_data_pointcloud)
static void attribute_calc_proximity(GeometryComponent &component, GeometrySet &geometry_set_target, GeoNodeExecParams &params)
static bool bvh_from_mesh(const Mesh *target_mesh, int target_geometry_element, BVHTreeFromMesh &r_tree_data_mesh)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:62
static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
static bNodeSocketTemplate geo_node_attribute_proximity_out[]
void register_node_type_geo_attribute_proximity()
static void geo_node_attribute_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static bNodeSocketTemplate geo_node_attribute_proximity_in[]
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:67
void node_free_standard_storage(bNode *node)
Definition: node_util.c:55
struct BVHTree * tree
Definition: BKE_bvhutils.h:66
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:69
struct BVHTree * tree
Definition: BKE_bvhutils.h:254
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:256
float co[3]
Definition: BLI_kdopbvh.h:59
const PointCloud * get_pointcloud_for_read() const
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
bool has_mesh() const
bool has_pointcloud() const
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:253
PointerRNA * ptr
Definition: wm_files.c:3157