Commit: d985751324a81d0227d163981cc561968a88ff68 Author: Jacques Lucke Date: Wed Jan 13 12:34:48 2021 +0100 Branches: master https://developer.blender.org/rBd985751324a81d0227d163981cc561968a88ff68
Geometry Nodes: improve Point Distribute node This greatly simplifies the Point Distribute node. For a poisson disk distribution, it now uses a simpler dart throwing variant. This results in a slightly lower quality poisson disk distribution, but it still fulfills our requirements: have a max density, minimum distance input and stability while painting the density attribute. This new implementation has a number of benefits over the old one: * Much less and more readable code. * Easier to extend with other distribution algorithms. * Easier to transfer more attributes to the generated points later on. * More predictable output when changing the max density and min distance. * Works in 3d, so no projection on the xy plane is necessary. This is related to T84640. Differential Revision: https://developer.blender.org/D10104 =================================================================== M source/blender/makesrna/intern/rna_nodetree.c M source/blender/nodes/CMakeLists.txt M source/blender/nodes/geometry/node_geometry_util.hh M source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc D source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc =================================================================== diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index cf44d8a84be..1f6359c2ed4 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -436,7 +436,8 @@ static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] "POISSON", 0, "Poisson Disk", - "Project points on the surface evenly with a Poisson disk distribution"}, + "Distribute the points randomly on the surface while taking a minimum distance between " + "points into account"}, {0, NULL, 0, NULL, NULL}, }; @@ -6291,7 +6292,8 @@ static void rna_def_cmp_output_file_slot_file(BlenderRNA *brna) prop = RNA_def_property(srna, "save_as_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "save_as_render", 1); - RNA_def_property_ui_text(prop, "Save as Render", "Apply render part of display transform when saving byte image"); + RNA_def_property_ui_text( + prop, "Save as Render", "Apply render part of display transform when saving byte image"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); prop = RNA_def_property(srna, "format", PROP_POINTER, PROP_NONE); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 64667faa735..d72189636e4 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -154,7 +154,6 @@ set(SRC geometry/nodes/node_geo_join_geometry.cc geometry/nodes/node_geo_object_info.cc geometry/nodes/node_geo_point_distribute.cc - geometry/nodes/node_geo_point_distribute_poisson_disk.cc geometry/nodes/node_geo_point_instance.cc geometry/nodes/node_geo_point_separate.cc geometry/nodes/node_geo_rotate_points.cc diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 0cabe5e1155..b7b2afeefcb 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -46,11 +46,6 @@ void update_attribute_input_socket_availabilities(bNode &node, CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType>); -void poisson_disk_point_elimination(Vector<float3> const *input_points, - Vector<float3> *output_points, - float maximum_distance, - float3 boundbox); - Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, const AttributeDomain domain); diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index f5f9c9f8830..1370f45877d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -16,9 +16,11 @@ #include "BLI_float3.hh" #include "BLI_hash.h" +#include "BLI_kdtree.h" #include "BLI_math_vector.h" #include "BLI_rand.hh" #include "BLI_span.hh" +#include "BLI_timeit.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -34,7 +36,7 @@ static bNodeSocketTemplate geo_node_point_distribute_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_FLOAT, N_("Distance Min"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, + {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, {SOCK_FLOAT, N_("Density Max"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, {SOCK_STRING, N_("Density Attribute")}, {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, @@ -67,213 +69,196 @@ static float3 normal_to_euler_rotation(const float3 normal) return rotation; } -static Vector<float3> random_scatter_points_from_mesh(const Mesh *mesh, - const float density, - const FloatReadAttribute &density_factors, - Vector<float3> &r_normals, - Vector<int> &r_ids, - const int seed) +static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh) { /* This only updates a cache and can be considered to be logically const. */ - const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(mesh)); - const int looptris_len = BKE_mesh_runtime_looptri_len(mesh); + const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh)); + const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh); + return {looptris, looptris_len}; +} - Vector<float3> points; +static void sample_mesh_surface(const Mesh &mesh, + 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) +{ + Span<MLoopTri> looptris = get_mesh_looptris(mesh); - for (const int looptri_index : IndexRange(looptris_len)) { + for (const int looptri_index : looptris.index_range()) { const MLoopTri &looptri = looptris[looptri_index]; - const int v0_index = mesh->mloop[looptri.tri[0]].v; - const int v1_index = mesh->mloop[looptri.tri[1]].v; - const int v2_index = mesh->mloop[looptri.tri[2]].v; - const float3 v0_pos = mesh->mvert[v0_index].co; - const float3 v1_pos = mesh->mvert[v1_index].co; - const float3 v2_pos = mesh->mvert[v2_index].co; - const float v0_density_factor = std::max(0.0f, density_factors[v0_index]); - const float v1_density_factor = std::max(0.0f, density_factors[v1_index]); - const float v2_density_factor = std::max(0.0f, density_factors[v2_index]); - const float looptri_density_factor = (v0_density_factor + v1_density_factor + - v2_density_factor) / - 3.0f; + const int v0_index = mesh.mloop[looptri.tri[0]].v; + const int v1_index = mesh.mloop[looptri.tri[1]].v; + const int v2_index = mesh.mloop[looptri.tri[2]].v; + const float3 v0_pos = mesh.mvert[v0_index].co; + const float3 v1_pos = mesh.mvert[v1_index].co; + const float3 v2_pos = mesh.mvert[v2_index].co; + + float looptri_density_factor = 1.0f; + if (density_factors != nullptr) { + const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_index]); + const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_index]); + const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_index]); + looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f; + } const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); const int looptri_seed = BLI_hash_int(looptri_index + seed); RandomNumberGenerator looptri_rng(looptri_seed); - const float points_amount_fl = area * density * looptri_density_factor; + const float points_amount_fl = area * base_density * looptri_density_factor; const float add_point_probability = fractf(points_amount_fl); const bool add_point = add_point_probability > looptri_rng.get_float(); const int point_amount = (int)points_amount_fl + (int)add_point; for (int i = 0; i < point_amount; i++) { - const float3 bary_coords = looptri_rng.get_barycentric_coordinates(); + const float3 bary_coord = looptri_rng.get_barycentric_coordinates(); float3 point_pos; - interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coords); - points.append(point_pos); - - /* Build a hash stable even when the mesh is deformed. */ - r_ids.append(((int)(bary_coords.hash()) + looptri_index)); - - float3 tri_normal; - normal_tri_v3(tri_normal, v0_pos, v1_pos, v2_pos); - r_normals.append(tri_normal); + interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord); + r_positions.append(point_pos); + r_bary_coords.append(bary_coord); + r_looptri_indices.append(looptri_index); } } +} - return points; +BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions) +{ + KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size()); + for (const int i : positions.index_range()) { + BLI_kdtree_3d_insert(kdtree, i, positions[i]); + } + BLI_kdtree_3d_balance(kdtree); + return kdtree; } -struct RayCastAll_Data { - void *bvhdata; +BLI_NOINLINE static void update_elimination_mask_for_close_points( + Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask) +{ + if (minimum_distance <= 0.0f) { + return; + } - BVHTree_RayCastCallback raycast_callback; + KDTree_3d *kdtree = build_kdtree(positions); - /** The original coordinate the result point was projected from. */ - float2 raystart; + for (const int i : positions.index_range()) { + if (elimination_mask[i]) { + continue; + } - const Mesh *mesh; - float base_weight; - FloatReadAttribute *density_factors; - Vector<float3> *projected_points; - Vector<float3> *normals; - Vector<int> *stable_ids; - float cur_point_weight; -}; + struct CallbackData { + int index; + MutableSpan<bool> elimination_mask; + } callback_data = {i, elimination_mask}; + + BLI_kdtree_3d_range_search_cb( + kdtree, + positions[i], + minimum_distance, + [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) { + CallbackData &callback_data = *static_cast<CallbackData *>(user_data); + if (index != callback_data.index) { + callback_data.elimination_mask[index] = true; + } + return true; + }, + &callback_data); + } + BLI_kdtree_3d_free(kdtree); +} -static void project_2d_bvh_callback(void *userdata, - int index, - @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs