diff options
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.hh | 22 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set_instances.hh | 42 | ||||
-rw-r--r-- | source/blender/blenkernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set.cc | 143 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set_instances.cc | 163 | ||||
-rw-r--r-- | source/blender/nodes/geometry/node_geometry_util.cc | 4 | ||||
-rw-r--r-- | source/blender/nodes/geometry/node_geometry_util.hh | 3 |
7 files changed, 212 insertions, 167 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 5b429a61b3f..02b3c88183a 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -467,25 +467,3 @@ class VolumeComponent : public GeometryComponent { static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume; }; - -/** - * Used to keep track of a group of instances using the same geometry data. - */ -struct GeometryInstanceGroup { - /** - * The geometry set instanced on each of the transforms. The components are not necessarily - * owned here. For example, they may be owned by the instanced object. This cannot be a - * reference because not all instanced data will necessarily have a #geometry_set_eval. - */ - GeometrySet geometry_set; - - /** - * As an optimization to avoid copying, the same geometry set can be associated with multiple - * instances. Each instance is stored as a transform matrix here. Again, these must be owned - * because they may be transformed from the original data. TODO: Validate that last statement. - */ - blender::Vector<blender::float4x4> transforms; -}; - -blender::Vector<GeometryInstanceGroup> BKE_geometry_set_gather_instances( - const GeometrySet &geometry_set); diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh new file mode 100644 index 00000000000..11725d75df9 --- /dev/null +++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_geometry_set.hh" + +namespace blender::bke { + +/** + * Used to keep track of a group of instances using the same geometry data. + */ +struct GeometryInstanceGroup { + /** + * The geometry set instanced on each of the transforms. The components are not necessarily + * owned here. For example, they may be owned by the instanced object. This cannot be a + * reference because not all instanced data will necessarily have a #geometry_set_eval. + */ + GeometrySet geometry_set; + + /** + * As an optimization to avoid copying, the same geometry set can be associated with multiple + * instances. Each instance is stored as a transform matrix here. Again, these must be owned + * because they may be transformed from the original data. TODO: Validate that last statement. + */ + Vector<float4x4> transforms; +}; + +Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set); + +} // namespace blender::bke diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 6b6d2b45d02..ead01dbd6cb 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -130,6 +130,7 @@ set(SRC intern/font.c intern/freestyle.c intern/geometry_set.cc + intern/geometry_set_instances.cc intern/gpencil.c intern/gpencil_curve.c intern/gpencil_geom.c @@ -327,6 +328,7 @@ set(SRC BKE_freestyle.h BKE_geometry_set.h BKE_geometry_set.hh + BKE_geometry_set_instances.hh BKE_global.h BKE_gpencil.h BKE_gpencil_curve.h diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index e6ecb6e5821..74d8b9afd82 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -586,149 +586,6 @@ bool InstancesComponent::is_empty() const return transforms_.size() == 0; } -/** - * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances. - */ -static GeometrySet object_get_geometry_set_for_read(const Object &object) -{ - /* Objects evaluated with a nodes modifier will have a geometry set already. */ - if (object.runtime.geometry_set_eval != nullptr) { - return *object.runtime.geometry_set_eval; - } - - /* Otherwise, construct a new geometry set with the component based on the object type. */ - GeometrySet new_geometry_set; - - if (object.type == OB_MESH) { - Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object( - &const_cast<Object &>(object), false); - - if (mesh != nullptr) { - BKE_mesh_wrapper_ensure_mdata(mesh); - - MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); - mesh_component.copy_vertex_group_names_from_object(object); - } - } - - /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the - * #geometry_set_eval case above. */ - - /* TODO: Add volume support. */ - - /* Return by value since there is not always an existing geometry set owned elsewhere to use. */ - return new_geometry_set; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Geometry Set Gather Recursive Instances - * \{ */ - -static void geometry_set_collect_recursive(const GeometrySet &geometry_set, - const float4x4 &transform, - Vector<GeometryInstanceGroup> &r_sets); - -static void geometry_set_collect_recursive_collection(const Collection &collection, - const float4x4 &transform, - Vector<GeometryInstanceGroup> &r_sets); - -static void geometry_set_collect_recursive_collection_instance( - const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets) -{ - float4x4 offset_matrix; - unit_m4(offset_matrix.values); - sub_v3_v3(offset_matrix.values[3], collection.instance_offset); - const float4x4 instance_transform = transform * offset_matrix; - geometry_set_collect_recursive_collection(collection, instance_transform, r_sets); -} - -static void geometry_set_collect_recursive_object(const Object &object, - const float4x4 &transform, - Vector<GeometryInstanceGroup> &r_sets) -{ - GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object); - geometry_set_collect_recursive(instance_geometry_set, transform, r_sets); - - if (object.type == OB_EMPTY) { - const Collection *collection_instance = object.instance_collection; - if (collection_instance != nullptr) { - geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets); - } - } -} - -static void geometry_set_collect_recursive_collection(const Collection &collection, - const float4x4 &transform, - Vector<GeometryInstanceGroup> &r_sets) -{ - LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) { - BLI_assert(collection_object->ob != nullptr); - const Object &object = *collection_object->ob; - const float4x4 object_transform = transform * object.obmat; - geometry_set_collect_recursive_object(object, object_transform, r_sets); - } - LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) { - BLI_assert(collection_child->collection != nullptr); - const Collection &collection = *collection_child->collection; - geometry_set_collect_recursive_collection(collection, transform, r_sets); - } -} - -static void geometry_set_collect_recursive(const GeometrySet &geometry_set, - const float4x4 &transform, - Vector<GeometryInstanceGroup> &r_sets) -{ - r_sets.append({geometry_set, {transform}}); - - if (geometry_set.has_instances()) { - const InstancesComponent &instances_component = - *geometry_set.get_component_for_read<InstancesComponent>(); - - Span<float4x4> transforms = instances_component.transforms(); - Span<InstancedData> instances = instances_component.instanced_data(); - for (const int i : instances.index_range()) { - const InstancedData &data = instances[i]; - const float4x4 instance_transform = transform * transforms[i]; - - if (data.type == INSTANCE_DATA_TYPE_OBJECT) { - BLI_assert(data.data.object != nullptr); - const Object &object = *data.data.object; - geometry_set_collect_recursive_object(object, instance_transform, r_sets); - } - else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) { - BLI_assert(data.data.collection != nullptr); - const Collection &collection = *data.data.collection; - geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets); - } - } - } -} - -/** - * Return flattened vector of the geometry component's recursive instances. I.e. all collection - * instances and object instances will be expanded into the instances of their geometry components. - * Even the instances in those geometry components' will be included. - * - * \note For convenience (to avoid duplication in the caller), the returned vector also contains - * the argument geometry set. - * - * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances. - */ -Vector<GeometryInstanceGroup> BKE_geometry_set_gather_instances(const GeometrySet &geometry_set) -{ - Vector<GeometryInstanceGroup> result_vector; - - float4x4 unit_transform; - unit_m4(unit_transform.values); - - geometry_set_collect_recursive(geometry_set, unit_transform, result_vector); - - return result_vector; -} - static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) { using namespace blender; diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc new file mode 100644 index 00000000000..6410aeb49fa --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -0,0 +1,163 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_geometry_set_instances.hh" +#include "BKE_mesh_wrapper.h" +#include "BKE_modifier.h" + +#include "DNA_collection_types.h" +#include "DNA_object_types.h" + +namespace blender::bke { + +static void geometry_set_collect_recursive(const GeometrySet &geometry_set, + const float4x4 &transform, + Vector<GeometryInstanceGroup> &r_sets); + +static void geometry_set_collect_recursive_collection(const Collection &collection, + const float4x4 &transform, + Vector<GeometryInstanceGroup> &r_sets); + +/** + * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances. + */ +static GeometrySet object_get_geometry_set_for_read(const Object &object) +{ + /* Objects evaluated with a nodes modifier will have a geometry set already. */ + if (object.runtime.geometry_set_eval != nullptr) { + return *object.runtime.geometry_set_eval; + } + + /* Otherwise, construct a new geometry set with the component based on the object type. */ + GeometrySet new_geometry_set; + + if (object.type == OB_MESH) { + Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object( + &const_cast<Object &>(object), false); + + if (mesh != nullptr) { + BKE_mesh_wrapper_ensure_mdata(mesh); + + MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>(); + mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); + mesh_component.copy_vertex_group_names_from_object(object); + } + } + + /* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the + * #geometry_set_eval case above. */ + + /* TODO: Add volume support. */ + + /* Return by value since there is not always an existing geometry set owned elsewhere to use. */ + return new_geometry_set; +} + +static void geometry_set_collect_recursive_collection_instance( + const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets) +{ + float4x4 offset_matrix; + unit_m4(offset_matrix.values); + sub_v3_v3(offset_matrix.values[3], collection.instance_offset); + const float4x4 instance_transform = transform * offset_matrix; + geometry_set_collect_recursive_collection(collection, instance_transform, r_sets); +} + +static void geometry_set_collect_recursive_object(const Object &object, + const float4x4 &transform, + Vector<GeometryInstanceGroup> &r_sets) +{ + GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object); + geometry_set_collect_recursive(instance_geometry_set, transform, r_sets); + + if (object.type == OB_EMPTY) { + const Collection *collection_instance = object.instance_collection; + if (collection_instance != nullptr) { + geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets); + } + } +} + +static void geometry_set_collect_recursive_collection(const Collection &collection, + const float4x4 &transform, + Vector<GeometryInstanceGroup> &r_sets) +{ + LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) { + BLI_assert(collection_object->ob != nullptr); + const Object &object = *collection_object->ob; + const float4x4 object_transform = transform * object.obmat; + geometry_set_collect_recursive_object(object, object_transform, r_sets); + } + LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) { + BLI_assert(collection_child->collection != nullptr); + const Collection &collection = *collection_child->collection; + geometry_set_collect_recursive_collection(collection, transform, r_sets); + } +} + +static void geometry_set_collect_recursive(const GeometrySet &geometry_set, + const float4x4 &transform, + Vector<GeometryInstanceGroup> &r_sets) +{ + r_sets.append({geometry_set, {transform}}); + + if (geometry_set.has_instances()) { + const InstancesComponent &instances_component = + *geometry_set.get_component_for_read<InstancesComponent>(); + + Span<float4x4> transforms = instances_component.transforms(); + Span<InstancedData> instances = instances_component.instanced_data(); + for (const int i : instances.index_range()) { + const InstancedData &data = instances[i]; + const float4x4 instance_transform = transform * transforms[i]; + + if (data.type == INSTANCE_DATA_TYPE_OBJECT) { + BLI_assert(data.data.object != nullptr); + const Object &object = *data.data.object; + geometry_set_collect_recursive_object(object, instance_transform, r_sets); + } + else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) { + BLI_assert(data.data.collection != nullptr); + const Collection &collection = *data.data.collection; + geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets); + } + } + } +} + +/** + * Return flattened vector of the geometry component's recursive instances. I.e. all collection + * instances and object instances will be expanded into the instances of their geometry components. + * Even the instances in those geometry components' will be included. + * + * \note For convenience (to avoid duplication in the caller), the returned vector also contains + * the argument geometry set. + * + * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances. + */ +Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set) +{ + Vector<GeometryInstanceGroup> result_vector; + + float4x4 unit_transform; + unit_m4(unit_transform.values); + + geometry_set_collect_recursive(geometry_set, unit_transform, result_vector); + + return result_vector; +} + +} // namespace blender::bke diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 08de467cd55..daee693c24f 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -26,6 +26,8 @@ namespace blender::nodes { +using bke::GeometryInstanceGroup; + void gather_attribute_info(Map<std::string, AttributeInfo> &attributes, const GeometryComponentType component_type, Span<GeometryInstanceGroup> set_groups, @@ -261,7 +263,7 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set) GeometrySet new_geometry_set; - Vector<GeometryInstanceGroup> set_groups = BKE_geometry_set_gather_instances(geometry_set); + Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set); join_instance_groups_mesh(set_groups, new_geometry_set); join_instance_groups_pointcloud(set_groups, new_geometry_set); join_instance_groups_volume(set_groups, new_geometry_set); diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 687763b4728..78418b37011 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -25,6 +25,7 @@ #include "DNA_node_types.h" +#include "BKE_geometry_set_instances.hh" #include "BKE_node.h" #include "BLT_translation.h" @@ -61,7 +62,7 @@ struct AttributeInfo { */ void gather_attribute_info(Map<std::string, AttributeInfo> &attributes, const GeometryComponentType component_type, - Span<GeometryInstanceGroup> set_groups, + Span<bke::GeometryInstanceGroup> set_groups, const Set<std::string> &ignored_attributes); } // namespace blender::nodes |