Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
| Show All 20 Lines | |||||
| #include "BLI_rand.hh" | #include "BLI_rand.hh" | ||||
| #include "BLI_span.hh" | #include "BLI_span.hh" | ||||
| #include "BLI_timeit.hh" | #include "BLI_timeit.hh" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_pointcloud_types.h" | #include "DNA_pointcloud_types.h" | ||||
| #include "BKE_attribute_math.hh" | |||||
| #include "BKE_bvhutils.h" | #include "BKE_bvhutils.h" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_pointcloud.h" | #include "BKE_pointcloud.h" | ||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| ▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | for (int i = positions.size() - 1; i >= 0; i--) { | ||||
| if (elimination_mask[i]) { | if (elimination_mask[i]) { | ||||
| positions.remove_and_reorder(i); | positions.remove_and_reorder(i); | ||||
| bary_coords.remove_and_reorder(i); | bary_coords.remove_and_reorder(i); | ||||
| looptri_indices.remove_and_reorder(i); | looptri_indices.remove_and_reorder(i); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLI_NOINLINE static void compute_remaining_point_data(const Mesh &mesh, | template<typename T> | ||||
| BLI_NOINLINE static 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) | |||||
| { | |||||
| BLI_assert(data_in.size() == mesh.totvert); | |||||
| Span<MLoopTri> looptris = get_mesh_looptris(mesh); | |||||
| for (const int i : bary_coords.index_range()) { | |||||
| const int looptri_index = looptri_indices[i]; | |||||
| const MLoopTri &looptri = looptris[looptri_index]; | |||||
| const float3 &bary_coord = bary_coords[i]; | |||||
| 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 T &v0 = data_in[v0_index]; | |||||
| const T &v1 = data_in[v1_index]; | |||||
| const T &v2 = data_in[v2_index]; | |||||
| const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); | |||||
| data_out[i] = interpolated_value; | |||||
| } | |||||
| } | |||||
| template<typename T> | |||||
| BLI_NOINLINE static 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) | |||||
| { | |||||
| BLI_assert(data_in.size() == mesh.totloop); | |||||
| Span<MLoopTri> looptris = get_mesh_looptris(mesh); | |||||
| for (const int i : bary_coords.index_range()) { | |||||
| const int looptri_index = looptri_indices[i]; | |||||
| const MLoopTri &looptri = looptris[looptri_index]; | |||||
| const float3 &bary_coord = bary_coords[i]; | |||||
| const int loop_index_0 = looptri.tri[0]; | |||||
| const int loop_index_1 = looptri.tri[1]; | |||||
| const int loop_index_2 = looptri.tri[2]; | |||||
| const T &v0 = data_in[loop_index_0]; | |||||
| const T &v1 = data_in[loop_index_1]; | |||||
| const T &v2 = data_in[loop_index_2]; | |||||
| const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); | |||||
| data_out[i] = interpolated_value; | |||||
| } | |||||
| } | |||||
| BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, | |||||
| Span<float3> bary_coords, | Span<float3> bary_coords, | ||||
| Span<int> looptri_indices, | Span<int> looptri_indices, | ||||
| MutableSpan<float3> r_normals, | const StringRef attribute_name, | ||||
| MutableSpan<int> r_ids, | const ReadAttribute &attribute_in, | ||||
| MutableSpan<float3> r_rotations) | GeometryComponent &component) | ||||
| { | |||||
| const CustomDataType data_type = attribute_in.custom_data_type(); | |||||
| const AttributeDomain domain = attribute_in.domain(); | |||||
| if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { | |||||
| /* Not supported currently. */ | |||||
| return; | |||||
| } | |||||
| OutputAttributePtr attribute_out = component.attribute_try_get_for_output( | |||||
| attribute_name, ATTR_DOMAIN_POINT, data_type); | |||||
| if (!attribute_out) { | |||||
| return; | |||||
| } | |||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | |||||
| using T = decltype(dummy); | |||||
| Span data_in = attribute_in.get_span<T>(); | |||||
| MutableSpan data_out = attribute_out->get_span_for_write_only<T>(); | |||||
| switch (domain) { | |||||
| case ATTR_DOMAIN_POINT: { | |||||
| interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out); | |||||
| break; | |||||
| } | |||||
| case ATTR_DOMAIN_CORNER: { | |||||
| interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out); | |||||
| break; | |||||
| } | |||||
| default: { | |||||
| BLI_assert(false); | |||||
| break; | |||||
| } | |||||
| } | |||||
| }); | |||||
| attribute_out.apply_span_and_save(); | |||||
| } | |||||
| BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component, | |||||
| GeometryComponent &component, | |||||
| Span<float3> bary_coords, | |||||
| Span<int> looptri_indices) | |||||
| { | { | ||||
| const Mesh &mesh = *mesh_component.get_for_read(); | |||||
| Set<std::string> attribute_names = mesh_component.attribute_names(); | |||||
| for (StringRefNull attribute_name : attribute_names) { | |||||
| if (ELEM(attribute_name, "position", "normal", "id")) { | |||||
| continue; | |||||
| } | |||||
| ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name); | |||||
| interpolate_attribute( | |||||
| mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component); | |||||
| } | |||||
| } | |||||
| BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, | |||||
| GeometryComponent &component, | |||||
| Span<float3> bary_coords, | |||||
| Span<int> looptri_indices) | |||||
| { | |||||
| OutputAttributePtr id_attribute = component.attribute_try_get_for_output( | |||||
| "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); | |||||
| OutputAttributePtr normal_attribute = component.attribute_try_get_for_output( | |||||
| "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); | |||||
| OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( | |||||
| "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); | |||||
| MutableSpan<int> ids = id_attribute->get_span_for_write_only<int>(); | |||||
| MutableSpan<float3> normals = normal_attribute->get_span_for_write_only<float3>(); | |||||
| MutableSpan<float3> rotations = rotation_attribute->get_span_for_write_only<float3>(); | |||||
| Span<MLoopTri> looptris = get_mesh_looptris(mesh); | Span<MLoopTri> looptris = get_mesh_looptris(mesh); | ||||
| for (const int i : bary_coords.index_range()) { | for (const int i : bary_coords.index_range()) { | ||||
| const int looptri_index = looptri_indices[i]; | const int looptri_index = looptri_indices[i]; | ||||
| const MLoopTri &looptri = looptris[looptri_index]; | const MLoopTri &looptri = looptris[looptri_index]; | ||||
| const float3 &bary_coord = bary_coords[i]; | const float3 &bary_coord = bary_coords[i]; | ||||
| const int v0_index = mesh.mloop[looptri.tri[0]].v; | const int v0_index = mesh.mloop[looptri.tri[0]].v; | ||||
| const int v1_index = mesh.mloop[looptri.tri[1]].v; | const int v1_index = mesh.mloop[looptri.tri[1]].v; | ||||
| const int v2_index = mesh.mloop[looptri.tri[2]].v; | const int v2_index = mesh.mloop[looptri.tri[2]].v; | ||||
| const float3 v0_pos = mesh.mvert[v0_index].co; | const float3 v0_pos = mesh.mvert[v0_index].co; | ||||
| const float3 v1_pos = mesh.mvert[v1_index].co; | const float3 v1_pos = mesh.mvert[v1_index].co; | ||||
| const float3 v2_pos = mesh.mvert[v2_index].co; | const float3 v2_pos = mesh.mvert[v2_index].co; | ||||
| r_ids[i] = (int)(bary_coord.hash()) + looptri_index; | ids[i] = (int)(bary_coord.hash()) + looptri_index; | ||||
| normal_tri_v3(r_normals[i], v0_pos, v1_pos, v2_pos); | normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos); | ||||
| r_rotations[i] = normal_to_euler_rotation(r_normals[i]); | rotations[i] = normal_to_euler_rotation(normals[i]); | ||||
| } | |||||
| id_attribute.apply_span_and_save(); | |||||
| normal_attribute.apply_span_and_save(); | |||||
| rotation_attribute.apply_span_and_save(); | |||||
| } | } | ||||
| BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component, | |||||
| GeometryComponent &component, | |||||
| Span<float3> bary_coords, | |||||
| Span<int> looptri_indices) | |||||
| { | |||||
| interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices); | |||||
| compute_special_attributes( | |||||
| *mesh_component.get_for_read(), component, bary_coords, looptri_indices); | |||||
| } | } | ||||
| static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh, | static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh, | ||||
| const float max_density, | const float max_density, | ||||
| const float minimum_distance, | const float minimum_distance, | ||||
| const FloatReadAttribute &density_factors, | const FloatReadAttribute &density_factors, | ||||
| const int seed, | const int seed, | ||||
| Vector<float3> &r_positions, | Vector<float3> &r_positions, | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | case GEO_NODE_POINT_DISTRIBUTE_POISSON: | ||||
| density_factors, | density_factors, | ||||
| seed, | seed, | ||||
| positions, | positions, | ||||
| bary_coords, | bary_coords, | ||||
| looptri_indices); | looptri_indices); | ||||
| break; | break; | ||||
| } | } | ||||
| const int tot_points = positions.size(); | const int tot_points = positions.size(); | ||||
| Array<float3> normals(tot_points); | |||||
| Array<int> stable_ids(tot_points); | |||||
| Array<float3> rotations(tot_points); | |||||
| compute_remaining_point_data( | |||||
| *mesh_in, bary_coords, looptri_indices, normals, stable_ids, rotations); | |||||
| PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points); | PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points); | ||||
| memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points); | memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points); | ||||
| for (const int i : positions.index_range()) { | for (const int i : positions.index_range()) { | ||||
| *(float3 *)(pointcloud->co + i) = positions[i]; | *(float3 *)(pointcloud->co + i) = positions[i]; | ||||
| pointcloud->radius[i] = 0.05f; | pointcloud->radius[i] = 0.05f; | ||||
| } | } | ||||
| PointCloudComponent &point_component = | PointCloudComponent &point_component = | ||||
| geometry_set_out.get_component_for_write<PointCloudComponent>(); | geometry_set_out.get_component_for_write<PointCloudComponent>(); | ||||
| point_component.replace(pointcloud); | point_component.replace(pointcloud); | ||||
| { | add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices); | ||||
| OutputAttributePtr stable_id_attribute = point_component.attribute_try_get_for_output( | |||||
| "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); | |||||
| MutableSpan<int> stable_ids_span = stable_id_attribute->get_span<int>(); | |||||
| stable_ids_span.copy_from(stable_ids); | |||||
| stable_id_attribute.apply_span_and_save(); | |||||
| } | |||||
| { | |||||
| OutputAttributePtr normals_attribute = point_component.attribute_try_get_for_output( | |||||
| "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); | |||||
| MutableSpan<float3> normals_span = normals_attribute->get_span<float3>(); | |||||
| normals_span.copy_from(normals); | |||||
| normals_attribute.apply_span_and_save(); | |||||
| } | |||||
| { | |||||
| OutputAttributePtr rotations_attribute = point_component.attribute_try_get_for_output( | |||||
| "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); | |||||
| MutableSpan<float3> rotations_span = rotations_attribute->get_span<float3>(); | |||||
| rotations_span.copy_from(rotations); | |||||
| rotations_attribute.apply_span_and_save(); | |||||
| } | |||||
| params.set_output("Geometry", std::move(geometry_set_out)); | params.set_output("Geometry", std::move(geometry_set_out)); | ||||
| } | } | ||||
| } // namespace blender::nodes | } // namespace blender::nodes | ||||
| void register_node_type_geo_point_distribute() | void register_node_type_geo_point_distribute() | ||||
| { | { | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| geo_node_type_base( | geo_node_type_base( | ||||
| &ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); | &ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); | ||||
| node_type_socket_templates(&ntype, geo_node_point_distribute_in, geo_node_point_distribute_out); | node_type_socket_templates(&ntype, geo_node_point_distribute_in, geo_node_point_distribute_out); | ||||
| node_type_update(&ntype, node_point_distribute_update); | node_type_update(&ntype, node_point_distribute_update); | ||||
| ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; | ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; | ||||
| nodeRegisterType(&ntype); | nodeRegisterType(&ntype); | ||||
| } | } | ||||