39 auto &distance_min =
b.add_input<
decl::Float>(
"Distance Min")
42 .make_available(enable_poisson)
44 auto &density_max =
b.add_input<
decl::Float>(
"Density Max")
55 auto &density_factor =
b.add_input<
decl::Float>(
"Density Factor")
61 .make_available(enable_poisson)
69 const bNode *node =
b.node_or_null();
70 if (node !=
nullptr) {
71 switch (node->custom1) {
73 distance_min.available(
true);
74 density_max.available(
true);
75 density_factor.available(
true);
78 density.available(
true);
105 const float base_density,
113 const Span<int> corner_verts = mesh.corner_verts();
114 const Span<int3> corner_tris = mesh.corner_tris();
116 for (
const int tri_i : corner_tris.
index_range()) {
117 const int3 &tri = corner_tris[tri_i];
118 const int v0_loop = tri[0];
119 const int v1_loop = tri[1];
120 const int v2_loop = tri[2];
121 const float3 &v0_pos = positions[corner_verts[v0_loop]];
122 const float3 &v1_pos = positions[corner_verts[v1_loop]];
123 const float3 &v2_pos = positions[corner_verts[v2_loop]];
125 float corner_tri_density_factor = 1.0f;
127 const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
128 const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
129 const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
130 corner_tri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) /
133 const float area =
area_tri_v3(v0_pos, v1_pos, v2_pos);
139 corner_tri_density_factor);
141 for (
int i = 0; i < point_amount; i++) {
145 r_positions.
append(point_pos);
146 r_bary_coords.
append(bary_coord);
147 r_tri_indices.
append(tri_i);
154 KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size());
157 for (
const float3 position : positions) {
158 BLI_kdtree_3d_insert(kdtree, i_point, position);
162 BLI_kdtree_3d_balance(kdtree);
169 if (minimum_distance <= 0.0f) {
176 for (
const int i : positions.index_range()) {
177 if (elimination_mask[i]) {
181 struct CallbackData {
184 } callback_data = {i, elimination_mask};
186 BLI_kdtree_3d_range_search_cb(
190 [](
void *user_data,
int index,
const float * ,
float ) {
191 CallbackData &callback_data = *
static_cast<CallbackData *
>(user_data);
192 if (index != callback_data.index) {
193 callback_data.elimination_mask[index] =
true;
208 const Span<int3> corner_tris = mesh.corner_tris();
210 if (elimination_mask[i]) {
214 const int3 &tri = corner_tris[tri_indices[i]];
215 const float3 bary_coord = bary_coords[i];
217 const float v0_density_factor = std::max(0.0f, density_factors[tri[0]]);
218 const float v1_density_factor = std::max(0.0f, density_factors[tri[1]]);
219 const float v2_density_factor = std::max(0.0f, density_factors[tri[2]]);
221 const float probability = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
222 v2_density_factor * bary_coord.z;
225 if (
hash > probability) {
226 elimination_mask[i] =
true;
236 for (
int i = positions.size() - 1; i >= 0; i--) {
237 if (elimination_mask[i]) {
238 positions.remove_and_reorder(i);
248 const AttrDomain source_domain,
252 switch (source_domain) {
253 case AttrDomain::Point: {
263 case AttrDomain::Corner: {
272 case AttrDomain::Face: {
298 const StringRef attribute_id = entry.key;
305 if (src.
domain == AttrDomain::Edge) {
310 attribute_id, AttrDomain::Point, output_data_type);
321struct AttributeOutputs {
332 switch (mesh.normals_domain()) {
334 const Span<int> corner_verts = mesh.corner_verts();
335 const Span<int3> corner_tris = mesh.corner_tris();
338 bke::mesh_surface_sample::sample_point_normals(
339 corner_verts, corner_tris, tri_indices, bary_coords, vert_normals, range, r_normals);
344 const Span<int> tri_faces = mesh.corner_tri_faces();
347 bke::mesh_surface_sample::sample_face_attribute(
348 tri_faces, tri_indices, face_normals, range, r_normals);
353 const Span<int3> corner_tris = mesh.corner_tris();
354 const Span<float3> corner_normals = mesh.corner_normals();
356 bke::mesh_surface_sample::sample_corner_normals(
357 corner_tris, tri_indices, bary_coords, corner_normals, range, r_normals);
370 const Span<int> corner_verts = mesh.corner_verts();
371 const Span<int3> corner_tris = mesh.corner_tris();
374 const int tri_i = tri_indices[i];
375 const int3 &tri = corner_tris[tri_i];
377 const int v0_index = corner_verts[tri[0]];
378 const int v1_index = corner_verts[tri[1]];
379 const int v2_index = corner_verts[tri[2]];
380 const float3 v0_pos = positions[v0_index];
381 const float3 v1_pos = positions[v1_index];
382 const float3 v2_pos = positions[v2_index];
386 r_normals[i] = normal;
394 for (const int i : range) {
395 r_rotations[i] = normal_to_rotation(normals[i]);
404 const AttributeOutputs &attribute_outputs,
405 const bool use_legacy_normal)
410 "id", AttrDomain::Point);
415 if (attribute_outputs.normal_id) {
417 *attribute_outputs.normal_id, AttrDomain::Point);
419 if (attribute_outputs.rotation_id) {
421 *attribute_outputs.rotation_id, AttrDomain::Point);
425 for (const int i : range) {
426 const int tri_i = tri_indices[i];
427 const float3 &bary_coord = bary_coords[i];
428 ids.span[i] = noise::hash(noise::hash_float(bary_coord), tri_i);
433 if (use_legacy_normal) {
434 compute_legacy_normal_outputs(mesh, bary_coords, tri_indices, normals.span);
437 compute_normal_outputs(mesh, bary_coords, tri_indices, normals.span);
441 compute_rotation_output(normals.span, rotations.span);
454 const AttrDomain domain = AttrDomain::Corner;
455 const int domain_size = mesh.attributes().domain_size(domain);
461 evaluator.add_with_destination(density_field, densities.
as_mutable_span());
462 evaluator.evaluate();
475 mesh, density_field, selection_field);
480 const float minimum_distance,
481 const float max_density,
491 Array<bool> elimination_mask(positions.size(),
false);
495 mesh, density_factor_field, selection_field);
498 mesh, density_factors, bary_coords, tri_indices, elimination_mask.
as_mutable_span());
507 const AttributeOutputs &attribute_outputs,
524 mesh, density_field, selection_field,
seed, positions, bary_coords, tri_indices);
528 const float minimum_distance =
params.get_input<
float>(
"Distance Min");
529 const float density_max =
params.get_input<
float>(
"Density Max");
534 density_factors_field,
544 if (positions.is_empty()) {
552 pointcloud->positions_for_write().copy_from(positions);
553 point_radii.
span.fill(0.05f);
560 GeometryComponent::Type::PointCloud,
562 params.get_attribute_filter(
"Points"),
566 attributes.remove(
"position");
570 const bool use_legacy_normal =
params.node().custom2 != 0;
572 mesh, *pointcloud, bary_coords, tri_indices, attribute_outputs, use_legacy_normal);
574 geometry::debug_randomize_point_order(pointcloud);
584 const int seed =
params.get_input<
int>(
"Seed") * 5383843;
587 AttributeOutputs attribute_outputs;
588 attribute_outputs.rotation_id =
params.get_output_anonymous_attribute_id_if_needed(
"Rotation");
589 attribute_outputs.normal_id =
params.get_output_anonymous_attribute_id_if_needed(
590 "Normal",
bool(attribute_outputs.rotation_id));
592 lazy_threading::send_hint();
596 geometry_set, selection_field, method,
seed, attribute_outputs,
params);
602 params.set_output(
"Points", std::move(geometry_set));
610 GEO_NODE_DISTRIBUTE_POINTS_ON_FACES,
611 "Distribute Points on Faces",
#define NODE_CLASS_GEOMETRY
General operations for point clouds.
PointCloud * BKE_pointcloud_new_nomain(int totpoint)
A KD-tree for nearest neighbor search.
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
void vec_to_quat(float q[4], const float vec[3], short axis, 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])
#define BLI_SCOPED_DEFER(function_to_defer)
GeometryNodeDistributePointsOnFacesMode
@ GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM
@ GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
static unsigned long seed
MutableSpan< T > as_mutable_span()
int round_probabilistic(float x)
float3 get_barycentric_coordinates()
constexpr IndexRange index_range() const
constexpr bool is_empty() const
static VArray ForSpan(Span< T > values)
void remove_and_reorder(const int64_t index)
void append(const T &value)
MutableSpan< T > as_mutable_span()
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
void set_selection(Field< bool > selection)
void make_available(bNode &node) const
local_group_size(16, 16) .push_constant(Type b
GPU_SHADER_INTERFACE_INFO(depth_2d_update_iface, "").smooth(Type fragColor push_constant(Type::VEC2, "extent") .push_constant(Type source_data
static float normals[][3]
void sample_point_attribute(Span< int > corner_verts, Span< int3 > corner_tris, Span< int > tri_indices, Span< float3 > bary_coords, const GVArray &src, const IndexMask &mask, GMutableSpan dst)
void sample_corner_attribute(Span< int3 > corner_tris, Span< int > tri_indices, Span< float3 > bary_coords, const GVArray &src, const IndexMask &mask, GMutableSpan dst)
void sample_face_attribute(Span< int > corner_tri_faces, Span< int > tri_indices, const GVArray &src, const IndexMask &mask, GMutableSpan dst)
void node_type_size(bNodeType *ntype, int width, int minwidth, int maxwidth)
void node_register_type(bNodeType *ntype)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
static BLI_NOINLINE void update_elimination_mask_for_close_points(Span< float3 > positions, const float minimum_distance, MutableSpan< bool > elimination_mask)
static BLI_NOINLINE KDTree_3d * build_kdtree(Span< float3 > positions)
static void node_register()
static BLI_NOINLINE void interpolate_attribute(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > tri_indices, const AttrDomain source_domain, const GVArray &source_data, GMutableSpan output_data)
static void distribute_points_poisson_disk(const Mesh &mesh, 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 > &tri_indices)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static math::Quaternion normal_to_rotation(const float3 normal)
static BLI_NOINLINE void compute_attribute_outputs(const Mesh &mesh, PointCloud &points, const Span< float3 > bary_coords, const Span< int > tri_indices, const AttributeOutputs &attribute_outputs, const bool use_legacy_normal)
static void compute_normal_outputs(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > tri_indices, MutableSpan< float3 > r_normals)
static void node_geo_exec(GeoNodeExecParams params)
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 > tri_indices, const MutableSpan< bool > elimination_mask)
static void node_layout_ex(uiLayout *layout, bContext *, PointerRNA *ptr)
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_tri_indices)
static void node_declare(NodeDeclarationBuilder &b)
static Array< float > calc_full_density_factors_with_selection(const Mesh &mesh, const Field< float > &density_field, const Field< bool > &selection_field)
static void compute_rotation_output(const Span< float3 > normals, MutableSpan< math::Quaternion > r_rotations)
static BLI_NOINLINE void propagate_existing_attributes(const Mesh &mesh, const Map< StringRef, AttributeKind > &attributes, PointCloud &points, const Span< float3 > bary_coords, const Span< int > tri_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 ¶ms)
static BLI_NOINLINE void eliminate_points_based_on_mask(const Span< bool > elimination_mask, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &tri_indices)
static void compute_legacy_normal_outputs(const Mesh &mesh, const Span< float3 > bary_coords, const Span< int > tri_indices, MutableSpan< float3 > r_normals)
static void distribute_points_random(const Mesh &mesh, const Field< float > &density_field, const Field< bool > &selection_field, const int seed, Vector< float3 > &positions, Vector< float3 > &bary_coords, Vector< int > &tri_indices)
float hash_float_to_float(float k)
uint32_t hash(uint32_t kx)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
std::optional< std::string > rotation_id
std::optional< std::string > normal_id
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void gather_attributes_for_propagation(Span< GeometryComponent::Type > component_types, GeometryComponent::Type dst_component_type, bool include_instances, const AttributeFilter &attribute_filter, Map< StringRef, AttributeKind > &r_attributes) const
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void keep_only_during_modify(Span< GeometryComponent::Type > component_types)
const Mesh * get_mesh() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
MutableVArraySpan< T > span
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeDeclareFunction declare