From 999abee874bd7d69f6a40c27969598869799e8dc Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 18 Feb 2021 10:13:56 +0100 Subject: Geometry Nodes: convert point cloud to mesh vertices for modifiers Previously, when a Geometry Nodes modifier outputs a point cloud (e.g. generated using the Point Distribute node), other modifiers could not use that data. Now, the point cloud data is converted to mesh vertices for such modifiers. Ref T85281. Differential Revision: https://developer.blender.org/D10451 --- .../blenkernel/BKE_geometry_set_instances.hh | 3 +- source/blender/blenkernel/intern/DerivedMesh.cc | 5 +- .../blenkernel/intern/geometry_set_instances.cc | 170 +++++++++++++-------- 3 files changed, 113 insertions(+), 65 deletions(-) diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh index 4f3c9c65203..f918adaff7c 100644 --- a/source/blender/blenkernel/BKE_geometry_set_instances.hh +++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh @@ -41,6 +41,7 @@ struct GeometryInstanceGroup { Vector geometry_set_gather_instances(const GeometrySet &geometry_set); +GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set); GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set); struct AttributeInfo { @@ -54,7 +55,7 @@ struct AttributeInfo { * attribute with the given name on all of the input components. */ void gather_attribute_info(Map &attributes, - const GeometryComponentType component_type, + Span component_types, Span set_groups, const Set &ignored_attributes); diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 213e72d496b..4aa7cfae009 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -890,7 +890,7 @@ void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval, */ static Mesh *prepare_geometry_set_for_mesh_modifier(Mesh *mesh, GeometrySet &r_geometry_set) { - if (!r_geometry_set.has_instances()) { + if (!r_geometry_set.has_instances() && !r_geometry_set.has_pointcloud()) { return mesh; } @@ -901,7 +901,8 @@ static Mesh *prepare_geometry_set_for_mesh_modifier(Mesh *mesh, GeometrySet &r_g } { /* Combine mesh and all instances into a single mesh that can be passed to the modifier. */ - GeometrySet new_geometry_set = blender::bke::geometry_set_realize_instances(r_geometry_set); + GeometrySet new_geometry_set = blender::bke::geometry_set_realize_mesh_for_modifier( + r_geometry_set); MeshComponent &mesh_component = new_geometry_set.get_component_for_write(); Mesh *new_mesh = mesh_component.release(); r_geometry_set = new_geometry_set; diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 436fc0f1d1d..66c7f53cdf5 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -24,6 +24,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_pointcloud_types.h" namespace blender::bke { @@ -165,44 +166,47 @@ Vector geometry_set_gather_instances(const GeometrySet &g } void gather_attribute_info(Map &attributes, - const GeometryComponentType component_type, + Span component_types, Span set_groups, const Set &ignored_attributes) { for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; - if (!set.has(component_type)) { - continue; - } - const GeometryComponent &component = *set.get_component_for_read(component_type); - - for (const std::string &name : component.attribute_names()) { - if (ignored_attributes.contains(name)) { + for (const GeometryComponentType component_type : component_types) { + if (!set.has(component_type)) { continue; } - const ReadAttributePtr read_attribute = component.attribute_try_get_for_read(name); - if (!read_attribute) { - continue; + const GeometryComponent &component = *set.get_component_for_read(component_type); + + for (const std::string &name : component.attribute_names()) { + if (ignored_attributes.contains(name)) { + continue; + } + const ReadAttributePtr read_attribute = component.attribute_try_get_for_read(name); + if (!read_attribute) { + continue; + } + const AttributeDomain domain = read_attribute->domain(); + const CustomDataType data_type = read_attribute->custom_data_type(); + + auto add_info = [&, data_type, domain](AttributeInfo *info) { + info->domain = domain; + info->data_type = data_type; + }; + auto modify_info = [&, data_type, domain](AttributeInfo *info) { + info->domain = domain; /* TODO: Use highest priority domain. */ + info->data_type = bke::attribute_data_type_highest_complexity( + {info->data_type, data_type}); + }; + + attributes.add_or_modify(name, add_info, modify_info); } - const AttributeDomain domain = read_attribute->domain(); - const CustomDataType data_type = read_attribute->custom_data_type(); - - auto add_info = [&, data_type, domain](AttributeInfo *info) { - info->domain = domain; - info->data_type = data_type; - }; - auto modify_info = [&, data_type, domain](AttributeInfo *info) { - info->domain = domain; /* TODO: Use highest priority domain. */ - info->data_type = bke::attribute_data_type_highest_complexity( - {info->data_type, data_type}); - }; - - attributes.add_or_modify(name, add_info, modify_info); } } } -static Mesh *join_mesh_topology_and_builtin_attributes(Span set_groups) +static Mesh *join_mesh_topology_and_builtin_attributes(Span set_groups, + const bool convert_points_to_vertices) { int totverts = 0; int totloops = 0; @@ -214,17 +218,22 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Spanmvert[vert_offset + i]; + const float3 old_position = pointcloud.co[i]; + const float3 new_position = transform * old_position; + copy_v3_v3(new_vert.co, new_position); + } + vert_offset += pointcloud.totpoint; + } + } } return new_mesh; } static void join_attributes(Span set_groups, - const GeometryComponentType component_type, + Span component_types, const Map &attribute_info, GeometryComponent &result) { @@ -315,26 +336,28 @@ static void join_attributes(Span set_groups, int offset = 0; for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; - if (set.has(component_type)) { - const GeometryComponent &component = *set.get_component_for_read(component_type); - const int domain_size = component.attribute_domain_size(domain_output); - if (domain_size == 0) { - continue; /* Domain size is 0, so no need to increment the offset. */ - } - ReadAttributePtr source_attribute = component.attribute_try_get_for_read( - name, domain_output, data_type_output); - - if (source_attribute) { - fn::GSpan src_span = source_attribute->get_span(); - const void *src_buffer = src_span.data(); - for (const int UNUSED(i) : set_group.transforms.index_range()) { - void *dst_buffer = dst_span[offset]; - cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size); - offset += domain_size; + for (const GeometryComponentType component_type : component_types) { + if (set.has(component_type)) { + const GeometryComponent &component = *set.get_component_for_read(component_type); + const int domain_size = component.attribute_domain_size(domain_output); + if (domain_size == 0) { + continue; /* Domain size is 0, so no need to increment the offset. */ + } + ReadAttributePtr source_attribute = component.attribute_try_get_for_read( + name, domain_output, data_type_output); + + if (source_attribute) { + fn::GSpan src_span = source_attribute->get_span(); + const void *src_buffer = src_span.data(); + for (const int UNUSED(i) : set_group.transforms.index_range()) { + void *dst_buffer = dst_span[offset]; + cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size); + offset += domain_size; + } + } + else { + offset += domain_size * set_group.transforms.size(); } - } - else { - offset += domain_size * set_group.transforms.size(); } } } @@ -343,21 +366,27 @@ static void join_attributes(Span set_groups, } } -static void join_instance_groups_mesh(Span set_groups, GeometrySet &result) +static void join_instance_groups_mesh(Span set_groups, + bool convert_points_to_vertices, + GeometrySet &result) { - Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups); + Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups, + convert_points_to_vertices); MeshComponent &dst_component = result.get_component_for_write(); dst_component.replace(new_mesh); + Vector component_types; + component_types.append(GeometryComponentType::Mesh); + if (convert_points_to_vertices) { + component_types.append(GeometryComponentType::PointCloud); + } + /* Don't copy attributes that are stored directly in the mesh data structs. */ Map attributes; - gather_attribute_info( - attributes, GeometryComponentType::Mesh, set_groups, {"position", "material_index"}); - join_attributes(set_groups, - GeometryComponentType::Mesh, - attributes, - static_cast(dst_component)); + gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"}); + join_attributes( + set_groups, component_types, attributes, static_cast(dst_component)); } static void join_instance_groups_pointcloud(Span set_groups, @@ -376,9 +405,9 @@ static void join_instance_groups_pointcloud(Span set_grou PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint); dst_component.replace(pointcloud); Map attributes; - gather_attribute_info(attributes, GeometryComponentType::Mesh, set_groups, {}); + gather_attribute_info(attributes, {GeometryComponentType::PointCloud}, set_groups, {}); join_attributes(set_groups, - GeometryComponentType::PointCloud, + {GeometryComponentType::PointCloud}, attributes, static_cast(dst_component)); } @@ -392,6 +421,23 @@ static void join_instance_groups_volume(Span set_groups, UNUSED_VARS(set_groups, dst_component); } +GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set) +{ + if (!geometry_set.has_instances() && !geometry_set.has_pointcloud()) { + return geometry_set; + } + + GeometrySet new_geometry_set = geometry_set; + Vector set_groups = geometry_set_gather_instances(geometry_set); + join_instance_groups_mesh(set_groups, true, new_geometry_set); + /* Remove all instances, even though some might contain other non-mesh data. We can't really + * keep only non-mesh instances in general. */ + new_geometry_set.remove(); + /* If there was a point cloud, it is now part of the mesh. */ + new_geometry_set.remove(); + return new_geometry_set; +} + GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set) { if (!geometry_set.has_instances()) { @@ -400,8 +446,8 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set) GeometrySet new_geometry_set; - Vector set_groups = bke::geometry_set_gather_instances(geometry_set); - join_instance_groups_mesh(set_groups, new_geometry_set); + Vector set_groups = geometry_set_gather_instances(geometry_set); + join_instance_groups_mesh(set_groups, false, new_geometry_set); join_instance_groups_pointcloud(set_groups, new_geometry_set); join_instance_groups_volume(set_groups, new_geometry_set); -- cgit v1.2.3