Blender  V3.3
node_geo_distribute_points_on_faces.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_kdtree.h"
4 #include "BLI_noise.hh"
5 #include "BLI_rand.hh"
6 #include "BLI_task.hh"
7 #include "BLI_timeit.hh"
8 
9 #include "DNA_mesh_types.h"
10 #include "DNA_meshdata_types.h"
11 #include "DNA_pointcloud_types.h"
12 
13 #include "BKE_attribute_math.hh"
14 #include "BKE_bvhutils.h"
15 #include "BKE_mesh.h"
16 #include "BKE_mesh_runtime.h"
17 #include "BKE_mesh_sample.hh"
18 #include "BKE_pointcloud.h"
19 
20 #include "UI_interface.h"
21 #include "UI_resources.h"
22 
23 #include "node_geometry_util.hh"
24 
26 
28 {
29  auto enable_random = [](bNode &node) {
31  };
32  auto enable_poisson = [](bNode &node) {
34  };
35 
36  b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
37  b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
38  b.add_input<decl::Float>(N_("Distance Min"))
39  .min(0.0f)
40  .subtype(PROP_DISTANCE)
41  .make_available(enable_poisson);
42  b.add_input<decl::Float>(N_("Density Max"))
43  .default_value(10.0f)
44  .min(0.0f)
45  .make_available(enable_poisson);
46  b.add_input<decl::Float>(N_("Density"))
47  .default_value(10.0f)
48  .min(0.0f)
49  .supports_field()
50  .make_available(enable_random);
51  b.add_input<decl::Float>(N_("Density Factor"))
52  .default_value(1.0f)
53  .min(0.0f)
54  .max(1.0f)
55  .subtype(PROP_FACTOR)
56  .supports_field()
57  .make_available(enable_poisson);
58  b.add_input<decl::Int>(N_("Seed"));
59 
60  b.add_output<decl::Geometry>(N_("Points"));
61  b.add_output<decl::Vector>(N_("Normal")).field_source();
62  b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source();
63 }
64 
65 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
66 {
67  uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
68 }
69 
71 {
72  bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
73  bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next;
74  bNodeSocket *sock_density = sock_density_max->next;
75  bNodeSocket *sock_density_factor = sock_density->next;
77  sock_distance_min,
80  ntree, sock_density_max, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON);
84  sock_density_factor,
86 }
87 
92 {
93  float quat[4];
95  float3 rotation;
96  quat_to_eul(rotation, quat);
97  return rotation;
98 }
99 
100 static void sample_mesh_surface(const Mesh &mesh,
101  const float base_density,
102  const Span<float> density_factors,
103  const int seed,
104  Vector<float3> &r_positions,
105  Vector<float3> &r_bary_coords,
106  Vector<int> &r_looptri_indices)
107 {
110 
111  for (const int looptri_index : looptris.index_range()) {
112  const MLoopTri &looptri = looptris[looptri_index];
113  const int v0_loop = looptri.tri[0];
114  const int v1_loop = looptri.tri[1];
115  const int v2_loop = looptri.tri[2];
116  const int v0_index = mesh.mloop[v0_loop].v;
117  const int v1_index = mesh.mloop[v1_loop].v;
118  const int v2_index = mesh.mloop[v2_loop].v;
119  const float3 v0_pos = float3(mesh.mvert[v0_index].co);
120  const float3 v1_pos = float3(mesh.mvert[v1_index].co);
121  const float3 v2_pos = float3(mesh.mvert[v2_index].co);
122 
123  float looptri_density_factor = 1.0f;
124  if (!density_factors.is_empty()) {
125  const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
126  const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
127  const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
128  looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
129  }
130  const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
131 
132  const int looptri_seed = noise::hash(looptri_index, seed);
133  RandomNumberGenerator looptri_rng(looptri_seed);
134 
135  const int point_amount = looptri_rng.round_probabilistic(area * base_density *
136  looptri_density_factor);
137 
138  for (int i = 0; i < point_amount; i++) {
139  const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
140  float3 point_pos;
141  interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord);
142  r_positions.append(point_pos);
143  r_bary_coords.append(bary_coord);
144  r_looptri_indices.append(looptri_index);
145  }
146  }
147 }
148 
150 {
151  KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
152 
153  int i_point = 0;
154  for (const float3 position : positions) {
155  BLI_kdtree_3d_insert(kdtree, i_point, position);
156  i_point++;
157  }
158 
159  BLI_kdtree_3d_balance(kdtree);
160  return kdtree;
161 }
162 
164  Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask)
165 {
166  if (minimum_distance <= 0.0f) {
167  return;
168  }
169 
170  KDTree_3d *kdtree = build_kdtree(positions);
171  BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
172 
173  for (const int i : positions.index_range()) {
174  if (elimination_mask[i]) {
175  continue;
176  }
177 
178  struct CallbackData {
179  int index;
180  MutableSpan<bool> elimination_mask;
181  } callback_data = {i, elimination_mask};
182 
183  BLI_kdtree_3d_range_search_cb(
184  kdtree,
185  positions[i],
186  minimum_distance,
187  [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
188  CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
189  if (index != callback_data.index) {
190  callback_data.elimination_mask[index] = true;
191  }
192  return true;
193  },
194  &callback_data);
195  }
196 }
197 
199  const Mesh &mesh,
200  const Span<float> density_factors,
201  const Span<float3> bary_coords,
202  const Span<int> looptri_indices,
203  const MutableSpan<bool> elimination_mask)
204 {
207  for (const int i : bary_coords.index_range()) {
208  if (elimination_mask[i]) {
209  continue;
210  }
211 
212  const MLoopTri &looptri = looptris[looptri_indices[i]];
213  const float3 bary_coord = bary_coords[i];
214 
215  const int v0_loop = looptri.tri[0];
216  const int v1_loop = looptri.tri[1];
217  const int v2_loop = looptri.tri[2];
218 
219  const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
220  const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
221  const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
222 
223  const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
224  v2_density_factor * bary_coord.z;
225 
226  const float hash = noise::hash_float_to_float(bary_coord);
227  if (hash > probablity) {
228  elimination_mask[i] = true;
229  }
230  }
231 }
232 
233 BLI_NOINLINE static void eliminate_points_based_on_mask(const Span<bool> elimination_mask,
235  Vector<float3> &bary_coords,
236  Vector<int> &looptri_indices)
237 {
238  for (int i = positions.size() - 1; i >= 0; i--) {
239  if (elimination_mask[i]) {
240  positions.remove_and_reorder(i);
241  bary_coords.remove_and_reorder(i);
242  looptri_indices.remove_and_reorder(i);
243  }
244  }
245 }
246 
248  const Span<float3> bary_coords,
249  const Span<int> looptri_indices,
250  const eAttrDomain source_domain,
251  const GVArray &source_data,
252  GMutableSpan output_data)
253 {
254  switch (source_domain) {
255  case ATTR_DOMAIN_POINT: {
257  looptri_indices,
258  bary_coords,
259  source_data,
260  IndexMask(output_data.size()),
261  output_data);
262  break;
263  }
264  case ATTR_DOMAIN_CORNER: {
266  looptri_indices,
267  bary_coords,
268  source_data,
269  IndexMask(output_data.size()),
270  output_data);
271  break;
272  }
273  case ATTR_DOMAIN_FACE: {
275  mesh, looptri_indices, source_data, IndexMask(output_data.size()), output_data);
276  break;
277  }
278  default: {
279  /* Not supported currently. */
280  return;
281  }
282  }
283 }
284 
286  const MeshComponent &mesh_component,
287  const Map<AttributeIDRef, AttributeKind> &attributes,
288  GeometryComponent &point_component,
289  const Span<float3> bary_coords,
290  const Span<int> looptri_indices)
291 {
292  const Mesh &mesh = *mesh_component.get_for_read();
293  const AttributeAccessor mesh_attributes = *mesh_component.attributes();
295 
296  for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
297  const AttributeIDRef attribute_id = entry.key;
298  const eCustomDataType output_data_type = entry.value.data_type;
299 
300  GAttributeReader source_attribute = mesh_attributes.lookup(attribute_id);
301  if (!source_attribute) {
302  continue;
303  }
304 
305  /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
306  GSpanAttributeWriter attribute_out = point_attributes.lookup_or_add_for_write_only_span(
307  attribute_id, ATTR_DOMAIN_POINT, output_data_type);
308  if (!attribute_out) {
309  continue;
310  }
311 
313  bary_coords,
314  looptri_indices,
315  source_attribute.domain,
316  source_attribute.varray,
317  attribute_out.span);
318  attribute_out.finish();
319  }
320 }
321 
322 namespace {
323 struct AttributeOutputs {
326 };
327 } // namespace
328 
329 BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_component,
330  PointCloudComponent &point_component,
331  const Span<float3> bary_coords,
332  const Span<int> looptri_indices,
333  const AttributeOutputs &attribute_outputs)
334 {
336 
337  SpanAttributeWriter<int> ids = pointcloud_attributes.lookup_or_add_for_write_only_span<int>(
338  "id", ATTR_DOMAIN_POINT);
339 
342 
343  if (attribute_outputs.normal_id) {
344  normals = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
345  attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
346  }
347  if (attribute_outputs.rotation_id) {
348  rotations = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
349  attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
350  }
351 
352  const Mesh &mesh = *mesh_component.get_for_read();
355 
356  for (const int i : bary_coords.index_range()) {
357  const int looptri_index = looptri_indices[i];
358  const MLoopTri &looptri = looptris[looptri_index];
359  const float3 &bary_coord = bary_coords[i];
360 
361  const int v0_index = mesh.mloop[looptri.tri[0]].v;
362  const int v1_index = mesh.mloop[looptri.tri[1]].v;
363  const int v2_index = mesh.mloop[looptri.tri[2]].v;
364  const float3 v0_pos = float3(mesh.mvert[v0_index].co);
365  const float3 v1_pos = float3(mesh.mvert[v1_index].co);
366  const float3 v2_pos = float3(mesh.mvert[v2_index].co);
367 
368  ids.span[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
369 
370  float3 normal;
371  if (!normals.span.is_empty() || !rotations.span.is_empty()) {
372  normal_tri_v3(normal, v0_pos, v1_pos, v2_pos);
373  }
374  if (!normals.span.is_empty()) {
375  normals.span[i] = normal;
376  }
377  if (!rotations.span.is_empty()) {
379  }
380  }
381 
382  ids.finish();
383 
384  if (normals) {
385  normals.finish();
386  }
387  if (rotations) {
388  rotations.finish();
389  }
390 }
391 
393  const Field<float> &density_field,
394  const Field<bool> &selection_field)
395 {
396  const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
397  GeometryComponentFieldContext field_context{component, attribute_domain};
398  const int domain_size = component.attribute_domain_size(attribute_domain);
399 
400  Array<float> densities(domain_size, 0.0f);
401 
402  fn::FieldEvaluator evaluator{field_context, domain_size};
403  evaluator.set_selection(selection_field);
404  evaluator.add_with_destination(density_field, densities.as_mutable_span());
405  evaluator.evaluate();
406  return densities;
407 }
408 
410  const Field<float> &density_field,
411  const Field<bool> &selection_field,
412  const int seed,
414  Vector<float3> &bary_coords,
415  Vector<int> &looptri_indices)
416 {
418  component, density_field, selection_field);
419  const Mesh &mesh = *component.get_for_read();
420  sample_mesh_surface(mesh, 1.0f, densities, seed, positions, bary_coords, looptri_indices);
421 }
422 
423 static void distribute_points_poisson_disk(const MeshComponent &mesh_component,
424  const float minimum_distance,
425  const float max_density,
426  const Field<float> &density_factor_field,
427  const Field<bool> &selection_field,
428  const int seed,
430  Vector<float3> &bary_coords,
431  Vector<int> &looptri_indices)
432 {
433  const Mesh &mesh = *mesh_component.get_for_read();
434  sample_mesh_surface(mesh, max_density, {}, seed, positions, bary_coords, looptri_indices);
435 
436  Array<bool> elimination_mask(positions.size(), false);
437  update_elimination_mask_for_close_points(positions, minimum_distance, elimination_mask);
438 
440  mesh_component, density_factor_field, selection_field);
441 
443  mesh, density_factors, bary_coords, looptri_indices, elimination_mask.as_mutable_span());
444 
446  elimination_mask.as_span(), positions, bary_coords, looptri_indices);
447 }
448 
449 static void point_distribution_calculate(GeometrySet &geometry_set,
450  const Field<bool> selection_field,
452  const int seed,
453  const AttributeOutputs &attribute_outputs,
454  const GeoNodeExecParams &params)
455 {
456  if (!geometry_set.has_mesh()) {
457  return;
458  }
459 
460  const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
461 
463  Vector<float3> bary_coords;
464  Vector<int> looptri_indices;
465 
466  switch (method) {
468  const Field<float> density_field = params.get_input<Field<float>>("Density");
469  distribute_points_random(mesh_component,
470  density_field,
471  selection_field,
472  seed,
473  positions,
474  bary_coords,
475  looptri_indices);
476  break;
477  }
479  const float minimum_distance = params.get_input<float>("Distance Min");
480  const float density_max = params.get_input<float>("Density Max");
481  const Field<float> density_factors_field = params.get_input<Field<float>>("Density Factor");
482  distribute_points_poisson_disk(mesh_component,
483  minimum_distance,
484  density_max,
485  density_factors_field,
486  selection_field,
487  seed,
488  positions,
489  bary_coords,
490  looptri_indices);
491  break;
492  }
493  }
494 
495  if (positions.is_empty()) {
496  return;
497  }
498 
499  PointCloud *pointcloud = BKE_pointcloud_new_nomain(positions.size());
501  *pointcloud);
502  bke::SpanAttributeWriter<float3> point_positions =
503  point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
504  bke::SpanAttributeWriter<float> point_radii =
505  point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
506  point_positions.span.copy_from(positions);
507  point_radii.span.fill(0.05f);
508  point_positions.finish();
509  point_radii.finish();
510 
511  geometry_set.replace_pointcloud(pointcloud);
512 
513  PointCloudComponent &point_component =
515 
519 
520  /* Position is set separately. */
521  attributes.remove("position");
522 
524  mesh_component, attributes, point_component, bary_coords, looptri_indices);
525 
527  mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs);
528 }
529 
531 {
532  GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
533 
535  static_cast<GeometryNodeDistributePointsOnFacesMode>(params.node().custom1);
536 
537  const int seed = params.get_input<int>("Seed") * 5383843;
538  const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
539 
540  AttributeOutputs attribute_outputs;
541  if (params.output_is_required("Normal")) {
542  attribute_outputs.normal_id = StrongAnonymousAttributeID("Normal");
543  }
544  if (params.output_is_required("Rotation")) {
545  attribute_outputs.rotation_id = StrongAnonymousAttributeID("Rotation");
546  }
547 
548  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
550  geometry_set, selection_field, method, seed, attribute_outputs, params);
551  /* Keep instances because the original geometry set may contain instances that are processed as
552  * well. */
554  });
555 
556  params.set_output("Points", std::move(geometry_set));
557 
558  if (attribute_outputs.normal_id) {
559  params.set_output(
560  "Normal",
561  AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.normal_id),
562  params.attribute_producer_name()));
563  }
564  if (attribute_outputs.rotation_id) {
565  params.set_output(
566  "Rotation",
567  AnonymousAttributeFieldInput::Create<float3>(std::move(attribute_outputs.rotation_id),
568  params.attribute_producer_name()));
569  }
570 }
571 
572 } // namespace blender::nodes::node_geo_distribute_points_on_faces_cc
573 
575 {
577 
578  static bNodeType ntype;
579 
580  geo_node_type_base(&ntype,
582  "Distribute Points on Faces",
585  node_type_size(&ntype, 170, 100, 320);
589  nodeRegisterType(&ntype);
590 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:29
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition: node.cc:4396
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4443
#define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES
Definition: BKE_node.h:1432
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
General operations for point clouds.
struct PointCloud * BKE_pointcloud_new_nomain(int totpoint)
Definition: pointcloud.cc:243
#define BLI_NOINLINE
A KD-tree for nearest neighbor search.
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:92
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag)
void quat_to_eul(float eul[3], const float quat[4])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
Definition: math_vector.c:160
#define BLI_SCOPED_DEFER(function_to_defer)
#define UNUSED(x)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
eCustomDataType
GeometryNodeDistributePointsOnFacesMode
@ GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM
@ GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON
@ OB_NEGZ
@ OB_POSY
@ PROP_DISTANCE
Definition: RNA_types.h:149
@ PROP_EULER
Definition: RNA_types.h:159
@ PROP_FACTOR
Definition: RNA_types.h:144
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
static unsigned long seed
Definition: btSoftBody.h:39
virtual std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write()
Definition: geometry_set.cc:79
const Mesh * get_for_read() const
std::optional< blender::bke::AttributeAccessor > attributes() const final
std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write() final
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:236
ItemIterator items() const
Definition: BLI_map.hh:859
int round_probabilistic(float x)
Definition: rand.cc:377
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr bool is_empty() const
Definition: BLI_span.hh:248
void remove_and_reorder(const int64_t index)
Definition: BLI_vector.hh:743
MutableSpan< T > as_mutable_span()
Definition: BLI_vector.hh:330
void append(const T &value)
Definition: BLI_vector.hh:433
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
void set_selection(Field< bool > selection)
Definition: FN_field.hh:366
OperationNode * node
void * user_data
bNodeTree * ntree
IconTextureDrawCall normal
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void sample_face_attribute(const Mesh &mesh, Span< int > looptri_indices, const GVArray &data_in, const IndexMask mask, GMutableSpan data_out)
Definition: mesh_sample.cc:127
void sample_point_attribute(const Mesh &mesh, Span< int > looptri_indices, Span< float3 > bary_coords, const GVArray &data_in, const IndexMask mask, GMutableSpan data_out)
Definition: mesh_sample.cc:44
void sample_corner_attribute(const Mesh &mesh, Span< int > looptri_indices, Span< float3 > bary_coords, const GVArray &data_in, const IndexMask mask, GMutableSpan data_out)
Definition: mesh_sample.cc:91
AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
AttributeAccessor mesh_attributes(const Mesh &mesh)
OwnedAnonymousAttributeID< true > StrongAnonymousAttributeID
static void area(int d1, int d2, int e1, int e2, float weights[2])
static BLI_NOINLINE void update_elimination_mask_for_close_points(Span< float3 > positions, const float minimum_distance, MutableSpan< bool > elimination_mask)
static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node)
static BLI_NOINLINE void update_elimination_mask_based_on_density_factors(const Mesh &mesh, const Span< float > density_factors, const Span< float3 > bary_coords, const Span< int > looptri_indices, const MutableSpan< bool > elimination_mask)
static void sample_mesh_surface(const Mesh &mesh, const float base_density, const Span< float > density_factors, const int seed, Vector< float3 > &r_positions, Vector< float3 > &r_bary_coords, Vector< int > &r_looptri_indices)
static BLI_NOINLINE void compute_attribute_outputs(const MeshComponent &mesh_component, PointCloudComponent &point_component, const Span< float3 > bary_coords, const Span< int > looptri_indices, const AttributeOutputs &attribute_outputs)
static BLI_NOINLINE KDTree_3d * build_kdtree(Span< float3 > positions)
static void distribute_points_random(const MeshComponent &component, const Field< float > &density_field, const Field< bool > &selection_field, const int seed, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &looptri_indices)
static BLI_NOINLINE void propagate_existing_attributes(const MeshComponent &mesh_component, const Map< AttributeIDRef, AttributeKind > &attributes, GeometryComponent &point_component, const Span< float3 > bary_coords, const Span< int > looptri_indices)
static BLI_NOINLINE void eliminate_points_based_on_mask(const Span< bool > elimination_mask, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &looptri_indices)
static BLI_NOINLINE void interpolate_attribute(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > looptri_indices, const eAttrDomain source_domain, const GVArray &source_data, GMutableSpan output_data)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static Array< float > calc_full_density_factors_with_selection(const MeshComponent &component, const Field< float > &density_field, const Field< bool > &selection_field)
static void distribute_points_poisson_disk(const MeshComponent &mesh_component, const float minimum_distance, const float max_density, const Field< float > &density_factor_field, const Field< bool > &selection_field, const int seed, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &looptri_indices)
static void point_distribution_calculate(GeometrySet &geometry_set, const Field< bool > selection_field, const GeometryNodeDistributePointsOnFacesMode method, const int seed, const AttributeOutputs &attribute_outputs, const GeoNodeExecParams &params)
uint32_t hash_float(float kx)
Definition: noise.cc:129
float hash_float_to_float(float k)
Definition: noise.cc:178
uint32_t hash(uint32_t kx)
Definition: noise.cc:67
vec_base< float, 3 > float3
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
MutableSpan< float3 > positions
Map< AttributeIDRef, GMutableSpan > point_attributes
MutableSpan< float3 > rotations
MutableSpan< float3 > normals
StrongAnonymousAttributeID normal_id
void register_node_type_geo_distribute_points_on_faces()
StrongAnonymousAttributeID rotation_id
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
#define hash
Definition: noise.c:153
#define min(a, b)
Definition: sort.c:35
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
void keep_only_during_modify(const blender::Span< GeometryComponentType > component_types)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
void gather_attributes_for_propagation(blender::Span< GeometryComponentType > component_types, GeometryComponentType dst_component_type, bool include_instances, blender::Map< blender::bke::AttributeIDRef, blender::bke::AttributeKind > &r_attributes) const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
bool has_mesh() const
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
unsigned int tri[3]
unsigned int v
float co[3]
struct MVert * mvert
struct MLoop * mloop
struct bNodeSocket * next
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
float max
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480