Blender  V2.93
node_geo_point_distribute.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_hash.h"
18 #include "BLI_kdtree.h"
19 #include "BLI_rand.hh"
20 #include "BLI_timeit.hh"
21 
22 #include "DNA_mesh_types.h"
23 #include "DNA_meshdata_types.h"
24 #include "DNA_pointcloud_types.h"
25 
26 #include "BKE_attribute_math.hh"
27 #include "BKE_bvhutils.h"
29 #include "BKE_mesh.h"
30 #include "BKE_mesh_runtime.h"
31 #include "BKE_pointcloud.h"
32 
33 #include "UI_interface.h"
34 #include "UI_resources.h"
35 
36 #include "node_geometry_util.hh"
37 
40 
42  {SOCK_GEOMETRY, N_("Geometry")},
43  {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_DISTANCE},
44  {SOCK_FLOAT, N_("Density Max"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE},
45  {SOCK_STRING, N_("Density Attribute")},
46  {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
47  {-1, ""},
48 };
49 
51  {SOCK_GEOMETRY, N_("Geometry")},
52  {-1, ""},
53 };
54 
56  bContext *UNUSED(C),
57  PointerRNA *ptr)
58 {
59  uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
60 }
61 
63 {
64  bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
65 
67 }
68 
69 namespace blender::nodes {
70 
75 {
76  float quat[4];
78  float3 rotation;
79  quat_to_eul(rotation, quat);
80  return rotation;
81 }
82 
84 {
85  /* This only updates a cache and can be considered to be logically const. */
86  const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
87  const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
88  return {looptris, looptris_len};
89 }
90 
91 static void sample_mesh_surface(const Mesh &mesh,
92  const float4x4 &transform,
93  const float base_density,
94  const FloatReadAttribute *density_factors,
95  const int seed,
96  Vector<float3> &r_positions,
97  Vector<float3> &r_bary_coords,
98  Vector<int> &r_looptri_indices)
99 {
101 
102  for (const int looptri_index : looptris.index_range()) {
103  const MLoopTri &looptri = looptris[looptri_index];
104  const int v0_loop = looptri.tri[0];
105  const int v1_loop = looptri.tri[1];
106  const int v2_loop = looptri.tri[2];
107  const int v0_index = mesh.mloop[v0_loop].v;
108  const int v1_index = mesh.mloop[v1_loop].v;
109  const int v2_index = mesh.mloop[v2_loop].v;
110  const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
111  const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
112  const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
113 
114  float looptri_density_factor = 1.0f;
115  if (density_factors != nullptr) {
116  const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
117  const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
118  const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
119  looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
120  }
121  const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
122 
123  const int looptri_seed = BLI_hash_int(looptri_index + seed);
124  RandomNumberGenerator looptri_rng(looptri_seed);
125 
126  const float points_amount_fl = area * base_density * looptri_density_factor;
127  const float add_point_probability = fractf(points_amount_fl);
128  const bool add_point = add_point_probability > looptri_rng.get_float();
129  const int point_amount = (int)points_amount_fl + (int)add_point;
130 
131  for (int i = 0; i < point_amount; i++) {
132  const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
133  float3 point_pos;
134  interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord);
135  r_positions.append(point_pos);
136  r_bary_coords.append(bary_coord);
137  r_looptri_indices.append(looptri_index);
138  }
139  }
140 }
141 
142 BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all,
143  const int initial_points_len)
144 {
145  KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len);
146 
147  int i_point = 0;
148  for (const Vector<float3> &positions : positions_all) {
149  for (const float3 position : positions) {
150  BLI_kdtree_3d_insert(kdtree, i_point, position);
151  i_point++;
152  }
153  }
154  BLI_kdtree_3d_balance(kdtree);
155  return kdtree;
156 }
157 
159  Span<Vector<float3>> positions_all,
160  Span<int> instance_start_offsets,
161  const float minimum_distance,
162  MutableSpan<bool> elimination_mask,
163  const int initial_points_len)
164 {
165  if (minimum_distance <= 0.0f) {
166  return;
167  }
168 
169  KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len);
170 
171  /* The elimination mask is a flattened array for every point,
172  * so keep track of the index to it separately. */
173  for (const int i_instance : positions_all.index_range()) {
174  Span<float3> positions = positions_all[i_instance];
175  const int offset = instance_start_offsets[i_instance];
176 
177  for (const int i : positions.index_range()) {
178  if (elimination_mask[offset + i]) {
179  continue;
180  }
181 
182  struct CallbackData {
183  int index;
184  MutableSpan<bool> elimination_mask;
185  } callback_data = {offset + i, elimination_mask};
186 
187  BLI_kdtree_3d_range_search_cb(
188  kdtree,
189  positions[i],
190  minimum_distance,
191  [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
192  CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
193  if (index != callback_data.index) {
194  callback_data.elimination_mask[index] = true;
195  }
196  return true;
197  },
198  &callback_data);
199  }
200  }
201  BLI_kdtree_3d_free(kdtree);
202 }
203 
205  const Mesh &mesh,
206  const FloatReadAttribute &density_factors,
207  Span<float3> bary_coords,
208  Span<int> looptri_indices,
209  MutableSpan<bool> elimination_mask)
210 {
212  for (const int i : bary_coords.index_range()) {
213  if (elimination_mask[i]) {
214  continue;
215  }
216 
217  const MLoopTri &looptri = looptris[looptri_indices[i]];
218  const float3 bary_coord = bary_coords[i];
219 
220  const int v0_loop = looptri.tri[0];
221  const int v1_loop = looptri.tri[1];
222  const int v2_loop = looptri.tri[2];
223 
224  const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
225  const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
226  const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
227 
228  const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
229  v2_density_factor * bary_coord.z;
230 
231  const float hash = BLI_hash_int_01(bary_coord.hash());
232  if (hash > probablity) {
233  elimination_mask[i] = true;
234  }
235  }
236 }
237 
239  Vector<float3> &positions,
240  Vector<float3> &bary_coords,
241  Vector<int> &looptri_indices)
242 {
243  for (int i = positions.size() - 1; i >= 0; i--) {
244  if (elimination_mask[i]) {
245  positions.remove_and_reorder(i);
246  bary_coords.remove_and_reorder(i);
247  looptri_indices.remove_and_reorder(i);
248  }
249  }
250 }
251 
252 template<typename T>
254  const Span<float3> bary_coords,
255  const Span<int> looptri_indices,
256  const Span<T> data_in,
257  MutableSpan<T> data_out)
258 {
259  BLI_assert(data_in.size() == mesh.totvert);
261 
262  for (const int i : bary_coords.index_range()) {
263  const int looptri_index = looptri_indices[i];
264  const MLoopTri &looptri = looptris[looptri_index];
265  const float3 &bary_coord = bary_coords[i];
266 
267  const int v0_index = mesh.mloop[looptri.tri[0]].v;
268  const int v1_index = mesh.mloop[looptri.tri[1]].v;
269  const int v2_index = mesh.mloop[looptri.tri[2]].v;
270 
271  const T &v0 = data_in[v0_index];
272  const T &v1 = data_in[v1_index];
273  const T &v2 = data_in[v2_index];
274 
275  const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
276  data_out[i] = interpolated_value;
277  }
278 }
279 
280 template<typename T>
282  const Span<float3> bary_coords,
283  const Span<int> looptri_indices,
284  const Span<T> data_in,
285  MutableSpan<T> data_out)
286 {
287  BLI_assert(data_in.size() == mesh.totloop);
289 
290  for (const int i : bary_coords.index_range()) {
291  const int looptri_index = looptri_indices[i];
292  const MLoopTri &looptri = looptris[looptri_index];
293  const float3 &bary_coord = bary_coords[i];
294 
295  const int loop_index_0 = looptri.tri[0];
296  const int loop_index_1 = looptri.tri[1];
297  const int loop_index_2 = looptri.tri[2];
298 
299  const T &v0 = data_in[loop_index_0];
300  const T &v1 = data_in[loop_index_1];
301  const T &v2 = data_in[loop_index_2];
302 
303  const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
304  data_out[i] = interpolated_value;
305  }
306 }
307 
308 template<typename T>
310  const Span<int> looptri_indices,
311  const Span<T> data_in,
312  MutableSpan<T> data_out)
313 {
314  BLI_assert(data_in.size() == mesh.totpoly);
316 
317  for (const int i : data_out.index_range()) {
318  const int looptri_index = looptri_indices[i];
319  const MLoopTri &looptri = looptris[looptri_index];
320  const int poly_index = looptri.poly;
321  data_out[i] = data_in[poly_index];
322  }
323 }
324 
325 template<typename T>
327  Span<float3> bary_coords,
328  Span<int> looptri_indices,
329  const AttributeDomain source_domain,
330  Span<T> source_span,
331  MutableSpan<T> output_span)
332 {
333  switch (source_domain) {
334  case ATTR_DOMAIN_POINT: {
335  interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span);
336  break;
337  }
338  case ATTR_DOMAIN_CORNER: {
339  interpolate_attribute_corner<T>(
340  mesh, bary_coords, looptri_indices, source_span, output_span);
341  break;
342  }
343  case ATTR_DOMAIN_FACE: {
344  interpolate_attribute_face<T>(mesh, looptri_indices, source_span, output_span);
345  break;
346  }
347  default: {
348  /* Not supported currently. */
349  return;
350  }
351  }
352 }
353 
355  Span<GeometryInstanceGroup> set_groups,
356  Span<int> instance_start_offsets,
357  const Map<std::string, AttributeKind> &attributes,
359  Span<Vector<float3>> bary_coords_array,
360  Span<Vector<int>> looptri_indices_array)
361 {
362  for (Map<std::string, AttributeKind>::Item entry : attributes.items()) {
363  StringRef attribute_name = entry.key;
364  const CustomDataType output_data_type = entry.value.data_type;
365  /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
366  OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
367  attribute_name, ATTR_DOMAIN_POINT, output_data_type);
368  if (!attribute_out) {
369  continue;
370  }
371 
372  fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
373 
374  int i_instance = 0;
375  for (const GeometryInstanceGroup &set_group : set_groups) {
376  const GeometrySet &set = set_group.geometry_set;
377  const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
378  const Mesh &mesh = *source_component.get_for_read();
379 
380  /* Use a dummy read without specifying a domain or data type in order to
381  * get the existing attribute's domain. Interpolation is done manually based
382  * on the bary coords in #interpolate_attribute. */
383  ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
384  attribute_name);
385  if (!dummy_attribute) {
386  i_instance += set_group.transforms.size();
387  continue;
388  }
389 
390  const AttributeDomain source_domain = dummy_attribute->domain();
391  ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
392  attribute_name, source_domain, output_data_type, nullptr);
393  if (!source_attribute) {
394  i_instance += set_group.transforms.size();
395  continue;
396  }
397  fn::GSpan source_span = source_attribute->get_span();
398 
399  attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
400  using T = decltype(dummy);
401 
402  for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
403  const int offset = instance_start_offsets[i_instance];
404  Span<float3> bary_coords = bary_coords_array[i_instance];
405  Span<int> looptri_indices = looptri_indices_array[i_instance];
406 
407  MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
408  interpolate_attribute<T>(mesh,
409  bary_coords,
410  looptri_indices,
411  source_domain,
412  source_span.typed<T>(),
413  instance_span);
414 
415  i_instance++;
416  }
417  });
418  }
419 
420  attribute_out.apply_span_and_save();
421  }
422 }
423 
425  Span<int> instance_start_offsets,
427  Span<Vector<float3>> bary_coords_array,
428  Span<Vector<int>> looptri_indices_array)
429 {
430  OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
432  OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
433  "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
434  OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
435  "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
436 
437  MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
438  MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
439  MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
440 
441  int i_instance = 0;
442  for (const GeometryInstanceGroup &set_group : sets) {
443  const GeometrySet &set = set_group.geometry_set;
445  const Mesh &mesh = *component.get_for_read();
447 
448  for (const float4x4 &transform : set_group.transforms) {
449  const int offset = instance_start_offsets[i_instance];
450 
451  Span<float3> bary_coords = bary_coords_array[i_instance];
452  Span<int> looptri_indices = looptri_indices_array[i_instance];
453  MutableSpan<int> ids = result_ids.slice(offset, bary_coords.size());
454  MutableSpan<float3> normals = result_normals.slice(offset, bary_coords.size());
455  MutableSpan<float3> rotations = result_rotations.slice(offset, bary_coords.size());
456 
457  /* Use one matrix multiplication per point instead of three (for each triangle corner). */
458  float rotation_matrix[3][3];
459  mat4_to_rot(rotation_matrix, transform.values);
460 
461  for (const int i : bary_coords.index_range()) {
462  const int looptri_index = looptri_indices[i];
463  const MLoopTri &looptri = looptris[looptri_index];
464  const float3 &bary_coord = bary_coords[i];
465 
466  const int v0_index = mesh.mloop[looptri.tri[0]].v;
467  const int v1_index = mesh.mloop[looptri.tri[1]].v;
468  const int v2_index = mesh.mloop[looptri.tri[2]].v;
469  const float3 v0_pos = float3(mesh.mvert[v0_index].co);
470  const float3 v1_pos = float3(mesh.mvert[v1_index].co);
471  const float3 v2_pos = float3(mesh.mvert[v2_index].co);
472 
473  ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index);
474  normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
475  mul_m3_v3(rotation_matrix, normals[i]);
476  rotations[i] = normal_to_euler_rotation(normals[i]);
477  }
478 
479  i_instance++;
480  }
481  }
482 
483  id_attribute.apply_span_and_save();
484  normal_attribute.apply_span_and_save();
485  rotation_attribute.apply_span_and_save();
486 }
487 
489  Span<GeometryInstanceGroup> set_groups,
490  Span<int> instance_start_offsets,
491  const Map<std::string, AttributeKind> &attributes,
493  Span<Vector<float3>> bary_coords_array,
494  Span<Vector<int>> looptri_indices_array)
495 {
497  instance_start_offsets,
498  attributes,
499  component,
500  bary_coords_array,
501  looptri_indices_array);
503  set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array);
504 }
505 
507  const StringRef density_attribute_name,
508  const float density,
509  const int seed,
510  MutableSpan<Vector<float3>> positions_all,
511  MutableSpan<Vector<float3>> bary_coords_all,
512  MutableSpan<Vector<int>> looptri_indices_all)
513 {
514  /* If there is an attribute name, the default value for the densities should be zero so that
515  * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
516  * factors. */
517  const bool use_one_default = density_attribute_name.is_empty();
518 
519  int i_instance = 0;
520  for (const GeometryInstanceGroup &set_group : set_groups) {
521  const GeometrySet &set = set_group.geometry_set;
523  const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
524  density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
525  const Mesh &mesh = *component.get_for_read();
526  for (const float4x4 &transform : set_group.transforms) {
527  Vector<float3> &positions = positions_all[i_instance];
528  Vector<float3> &bary_coords = bary_coords_all[i_instance];
529  Vector<int> &looptri_indices = looptri_indices_all[i_instance];
531  transform,
532  density,
533  &density_factors,
534  seed,
535  positions,
536  bary_coords,
537  looptri_indices);
538  i_instance++;
539  }
540  }
541 }
542 
544  const StringRef density_attribute_name,
545  const float density,
546  const int seed,
547  const float minimum_distance,
548  MutableSpan<Vector<float3>> positions_all,
549  MutableSpan<Vector<float3>> bary_coords_all,
550  MutableSpan<Vector<int>> looptri_indices_all)
551 {
552  Array<int> instance_start_offsets(positions_all.size());
553  int initial_points_len = 0;
554  int i_instance = 0;
555  for (const GeometryInstanceGroup &set_group : set_groups) {
556  const GeometrySet &set = set_group.geometry_set;
558  const Mesh &mesh = *component.get_for_read();
559  for (const float4x4 &transform : set_group.transforms) {
560  Vector<float3> &positions = positions_all[i_instance];
561  Vector<float3> &bary_coords = bary_coords_all[i_instance];
562  Vector<int> &looptri_indices = looptri_indices_all[i_instance];
564  mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
565 
566  instance_start_offsets[i_instance] = initial_points_len;
567  initial_points_len += positions.size();
568  i_instance++;
569  }
570  }
571 
572  /* If there is an attribute name, the default value for the densities should be zero so that
573  * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
574  * factors. */
575  const bool use_one_default = density_attribute_name.is_empty();
576 
577  /* Unlike the other result arrays, the elimination mask in stored as a flat array for every
578  * point, in order to simplify culling points from the KDTree (which needs to know about all
579  * points at once). */
580  Array<bool> elimination_mask(initial_points_len, false);
582  instance_start_offsets,
583  minimum_distance,
584  elimination_mask,
585  initial_points_len);
586 
587  i_instance = 0;
588  for (const GeometryInstanceGroup &set_group : set_groups) {
589  const GeometrySet &set = set_group.geometry_set;
591  const Mesh &mesh = *component.get_for_read();
592  const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
593  density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
594 
595  for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
596  Vector<float3> &positions = positions_all[i_instance];
597  Vector<float3> &bary_coords = bary_coords_all[i_instance];
598  Vector<int> &looptri_indices = looptri_indices_all[i_instance];
599 
600  const int offset = instance_start_offsets[i_instance];
602  mesh,
603  density_factors,
604  bary_coords,
605  looptri_indices,
606  elimination_mask.as_mutable_span().slice(offset, positions.size()));
607 
608  eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()),
609  positions,
610  bary_coords,
611  looptri_indices);
612 
613  i_instance++;
614  }
615  }
616 }
617 
619 {
620  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
621 
622  const GeometryNodePointDistributeMode distribute_method =
623  static_cast<GeometryNodePointDistributeMode>(params.node().custom1);
624 
625  const int seed = params.get_input<int>("Seed") * 5383843;
626  const float density = params.extract_input<float>("Density Max");
627  const std::string density_attribute_name = params.extract_input<std::string>(
628  "Density Attribute");
629 
630  if (density <= 0.0f) {
631  params.set_output("Geometry", GeometrySet());
632  return;
633  }
634 
636  geometry_set_gather_instances(geometry_set, set_groups);
637  if (set_groups.is_empty()) {
638  params.set_output("Geometry", GeometrySet());
639  return;
640  }
641 
642  /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */
643  for (int i = set_groups.size() - 1; i >= 0; i--) {
644  const GeometrySet &set = set_groups[i].geometry_set;
645  if (!set.has_mesh()) {
646  set_groups.remove_and_reorder(i);
647  }
648  }
649 
650  if (set_groups.is_empty()) {
651  params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
652  params.set_output("Geometry", GeometrySet());
653  return;
654  }
655 
656  int instances_len = 0;
657  for (GeometryInstanceGroup &set_group : set_groups) {
658  instances_len += set_group.transforms.size();
659  }
660 
661  /* Store data per-instance in order to simplify attribute access after the scattering,
662  * and to make the point elimination simpler for the poisson disk mode. Note that some
663  * vectors will be empty if any instances don't contain mesh data. */
664  Array<Vector<float3>> positions_all(instances_len);
665  Array<Vector<float3>> bary_coords_all(instances_len);
666  Array<Vector<int>> looptri_indices_all(instances_len);
667 
668  switch (distribute_method) {
670  distribute_points_random(set_groups,
671  density_attribute_name,
672  density,
673  seed,
674  positions_all,
675  bary_coords_all,
676  looptri_indices_all);
677  break;
678  }
680  const float minimum_distance = params.extract_input<float>("Distance Min");
682  density_attribute_name,
683  density,
684  seed,
685  minimum_distance,
686  positions_all,
687  bary_coords_all,
688  looptri_indices_all);
689  break;
690  }
691  }
692 
693  int final_points_len = 0;
694  Array<int> instance_start_offsets(set_groups.size());
695  for (const int i : positions_all.index_range()) {
696  Vector<float3> &positions = positions_all[i];
697  instance_start_offsets[i] = final_points_len;
698  final_points_len += positions.size();
699  }
700 
701  PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len);
702  for (const int instance_index : positions_all.index_range()) {
703  const int offset = instance_start_offsets[instance_index];
704  Span<float3> positions = positions_all[instance_index];
705  memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size());
706  }
707 
708  uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
709 
710  GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud);
711  PointCloudComponent &point_component =
712  geometry_set_out.get_component_for_write<PointCloudComponent>();
713 
716  set_groups, {GEO_COMPONENT_TYPE_MESH}, {"position", "normal", "id"}, attributes);
718  instance_start_offsets,
719  attributes,
720  point_component,
721  bary_coords_all,
722  looptri_indices_all);
723 
724  params.set_output("Geometry", std::move(geometry_set_out));
725 }
726 
727 } // namespace blender::nodes
728 
730 {
731  static bNodeType ntype;
732 
734  &ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
739  nodeRegisterType(&ntype);
740 }
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:46
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:45
@ GEO_COMPONENT_TYPE_MESH
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh)
Definition: mesh_runtime.c:155
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3726
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4623
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
General operations for point-clouds.
struct PointCloud * BKE_pointcloud_new_nomain(const int totpoint)
Definition: pointcloud.cc:240
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_NOINLINE
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:108
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
Definition: BLI_hash.h:103
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:116
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void mat4_to_rot(float rot[3][3], const float wmat[4][4])
Definition: math_matrix.c:2226
void quat_to_eul(float eul[3], const float quat[4])
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag)
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:191
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
CustomDataType
@ CD_PROP_FLOAT3
@ CD_PROP_INT32
GeometryNodePointDistributeMode
@ GEO_NODE_POINT_DISTRIBUTE_POISSON
@ GEO_NODE_POINT_DISTRIBUTE_RANDOM
@ SOCK_INT
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_STRING
@ OB_NEGZ
@ OB_POSY
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
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 GEO_NODE_POINT_DISTRIBUTE
@ PROP_DISTANCE
Definition: RNA_types.h:135
@ PROP_NONE
Definition: RNA_types.h:113
#define C
Definition: RandGen.cpp:39
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static unsigned long seed
Definition: btSoftBody.h:39
blender::bke::ReadAttributePtr attribute_try_get_for_read(const blender::StringRef attribute_name) const
blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type, const void *default_value) const
const Mesh * get_for_read() const
IndexRange index_range() const
Definition: BLI_array.hh:345
Span< T > as_span() const
Definition: BLI_array.hh:245
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:250
ItemIterator items() const
Definition: BLI_map.hh:825
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition: BLI_span.hh:594
constexpr IndexRange index_range() const
Definition: BLI_span.hh:659
constexpr const T * data() const
Definition: BLI_span.hh:217
constexpr int64_t size() const
Definition: BLI_span.hh:254
constexpr IndexRange index_range() const
Definition: BLI_span.hh:414
constexpr bool is_empty() const
int64_t size() const
Definition: BLI_vector.hh:662
void remove_and_reorder(const int64_t index)
Definition: BLI_vector.hh:711
void append(const T &value)
Definition: BLI_vector.hh:438
bool is_empty() const
Definition: BLI_vector.hh:674
fn::GMutableSpan get_span_for_write_only()
MutableSpan< T > typed() const
Span< T > typed() const
OperationNode * node
void * user_data
bNodeTree * ntree
static float normals[][3]
static void add_point(bGPDstroke *gps, float scale, const int32_t offset[2], float x, float y)
IconTextureDrawCall normal
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MINLINE float fractf(float a)
#define T
T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2)
void convert_to_static_type(const CustomDataType data_type, const Func &func)
TypedReadAttribute< float > FloatReadAttribute
void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector< GeometryInstanceGroup > &r_instance_groups)
void geometry_set_gather_instances_attribute_info(Span< GeometryInstanceGroup > set_groups, Span< GeometryComponentType > component_types, const Set< std::string > &ignored_attributes, Map< std::string, AttributeKind > &r_attributes)
std::unique_ptr< ReadAttribute > ReadAttributePtr
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< Vector< float3 >> positions_all, Span< int > instance_start_offsets, const float minimum_distance, MutableSpan< bool > elimination_mask, const int initial_points_len)
static void sample_mesh_surface(const Mesh &mesh, const float4x4 &transform, const float base_density, const FloatReadAttribute *density_factors, const int seed, Vector< float3 > &r_positions, Vector< float3 > &r_bary_coords, Vector< int > &r_looptri_indices)
static float3 normal_to_euler_rotation(const float3 normal)
static BLI_NOINLINE void interpolate_attribute(const Mesh &mesh, Span< float3 > bary_coords, Span< int > looptri_indices, const AttributeDomain source_domain, Span< T > source_span, MutableSpan< T > output_span)
static BLI_NOINLINE void add_remaining_point_attributes(Span< GeometryInstanceGroup > set_groups, Span< int > instance_start_offsets, const Map< std::string, AttributeKind > &attributes, GeometryComponent &component, Span< Vector< float3 >> bary_coords_array, Span< Vector< int >> looptri_indices_array)
static void distribute_points_poisson_disk(Span< GeometryInstanceGroup > set_groups, const StringRef density_attribute_name, const float density, const int seed, const float minimum_distance, MutableSpan< Vector< float3 >> positions_all, MutableSpan< Vector< float3 >> bary_coords_all, MutableSpan< Vector< int >> looptri_indices_all)
static void geo_node_point_distribute_exec(GeoNodeExecParams params)
static Span< MLoopTri > get_mesh_looptris(const Mesh &mesh)
static BLI_NOINLINE void compute_special_attributes(Span< GeometryInstanceGroup > sets, Span< int > instance_start_offsets, GeometryComponent &component, Span< Vector< float3 >> bary_coords_array, Span< Vector< int >> looptri_indices_array)
static BLI_NOINLINE KDTree_3d * build_kdtree(Span< Vector< float3 >> positions_all, const int initial_points_len)
static BLI_NOINLINE void eliminate_points_based_on_mask(Span< bool > elimination_mask, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &looptri_indices)
static BLI_NOINLINE void interpolate_attribute_point(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > looptri_indices, const Span< T > data_in, MutableSpan< T > data_out)
static void distribute_points_random(Span< GeometryInstanceGroup > set_groups, const StringRef density_attribute_name, const float density, const int seed, MutableSpan< Vector< float3 >> positions_all, MutableSpan< Vector< float3 >> bary_coords_all, MutableSpan< Vector< int >> looptri_indices_all)
static BLI_NOINLINE void interpolate_attribute_face(const Mesh &mesh, const Span< int > looptri_indices, const Span< T > data_in, MutableSpan< T > data_out)
static BLI_NOINLINE void interpolate_attribute_corner(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > looptri_indices, const Span< T > data_in, MutableSpan< T > data_out)
static BLI_NOINLINE void interpolate_existing_attributes(Span< GeometryInstanceGroup > set_groups, Span< int > instance_start_offsets, const Map< std::string, AttributeKind > &attributes, GeometryComponent &component, Span< Vector< float3 >> bary_coords_array, Span< Vector< int >> looptri_indices_array)
static BLI_NOINLINE void update_elimination_mask_based_on_density_factors(const Mesh &mesh, const FloatReadAttribute &density_factors, Span< float3 > bary_coords, Span< int > looptri_indices, MutableSpan< bool > elimination_mask)
void uninitialized_fill_n(T *dst, int64_t n, const T &value)
static void geo_node_point_distribute_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
void register_node_type_geo_point_distribute()
static bNodeSocketTemplate geo_node_point_distribute_in[]
static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node)
static bNodeSocketTemplate geo_node_point_distribute_out[]
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
#define hash
Definition: noise.c:169
unsigned __int64 uint64_t
Definition: stdint.h:93
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
static GeometrySet create_with_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
bool has_mesh() const
unsigned int poly
unsigned int tri[3]
unsigned int v
float co[3]
struct MVert * mvert
int totvert
struct MLoop * mloop
int totpoly
int totloop
float(* co)[3]
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
uint64_t hash() const
Definition: BLI_float3.hh:228
float max
PointerRNA * ptr
Definition: wm_files.c:3157