Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh22
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc150
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc249
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_scale.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_separate.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc2
26 files changed, 502 insertions, 28 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 02b3c88183a..5b429a61b3f 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -467,3 +467,25 @@ 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/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 7eb41a6c623..0bc248299ca 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -14,13 +14,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_map.hh"
+
+#include "BKE_attribute.h"
+#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
#include "BKE_volume.h"
+#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "BLI_rand.hh"
@@ -29,6 +35,7 @@
using blender::float3;
using blender::float4x4;
+using blender::Map;
using blender::MutableSpan;
using blender::Span;
using blender::StringRef;
@@ -579,6 +586,149 @@ 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 pointclouds 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/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index daaccf4450b..95c25795356 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -17,8 +17,257 @@
#include "node_geometry_util.hh"
#include "node_util.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_pointcloud.h"
+
namespace blender::nodes {
+void gather_attribute_info(Map<std::string, AttributeInfo> &attributes,
+ const GeometryComponentType component_type,
+ Span<GeometryInstanceGroup> set_groups,
+ const Set<std::string> &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)) {
+ 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 = 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<GeometryInstanceGroup> set_groups)
+{
+ int totverts = 0;
+ int totloops = 0;
+ int totedges = 0;
+ int totpolys = 0;
+ int64_t cd_dirty_vert = 0;
+ int64_t cd_dirty_poly = 0;
+ int64_t cd_dirty_edge = 0;
+ int64_t cd_dirty_loop = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has_mesh()) {
+ const Mesh &mesh = *set.get_mesh_for_read();
+ totverts += mesh.totvert * set_group.transforms.size();
+ totloops += mesh.totloop * set_group.transforms.size();
+ totedges += mesh.totedge * set_group.transforms.size();
+ totpolys += mesh.totpoly * set_group.transforms.size();
+ cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
+ cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
+ cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
+ cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
+ }
+ }
+
+ Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
+ /* Copy settings from the first input geometry set with a mesh. */
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has_mesh()) {
+ const Mesh &mesh = *set.get_mesh_for_read();
+ BKE_mesh_copy_settings(new_mesh, &mesh);
+ break;
+ }
+ }
+ new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
+ new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
+ new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
+ new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
+
+ int vert_offset = 0;
+ int loop_offset = 0;
+ int edge_offset = 0;
+ int poly_offset = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has_mesh()) {
+ const Mesh &mesh = *set.get_mesh_for_read();
+ for (const float4x4 &transform : set_group.transforms) {
+ for (const int i : IndexRange(mesh.totvert)) {
+ const MVert &old_vert = mesh.mvert[i];
+ MVert &new_vert = new_mesh->mvert[vert_offset + i];
+
+ new_vert = old_vert;
+
+ const float3 new_position = transform * float3(old_vert.co);
+ copy_v3_v3(new_vert.co, new_position);
+ }
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &old_edge = mesh.medge[i];
+ MEdge &new_edge = new_mesh->medge[edge_offset + i];
+ new_edge = old_edge;
+ new_edge.v1 += vert_offset;
+ new_edge.v2 += vert_offset;
+ }
+ for (const int i : IndexRange(mesh.totloop)) {
+ const MLoop &old_loop = mesh.mloop[i];
+ MLoop &new_loop = new_mesh->mloop[loop_offset + i];
+ new_loop = old_loop;
+ new_loop.v += vert_offset;
+ new_loop.e += edge_offset;
+ }
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &old_poly = mesh.mpoly[i];
+ MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
+ new_poly = old_poly;
+ new_poly.loopstart += loop_offset;
+ }
+
+ vert_offset += mesh.totvert;
+ loop_offset += mesh.totloop;
+ edge_offset += mesh.totedge;
+ poly_offset += mesh.totpoly;
+ }
+ }
+ }
+
+ return new_mesh;
+}
+
+static void join_attributes(Span<GeometryInstanceGroup> set_groups,
+ const GeometryComponentType component_type,
+ const Map<std::string, AttributeInfo> &attribute_info,
+ GeometryComponent &result)
+{
+ for (Map<std::string, AttributeInfo>::Item entry : attribute_info.items()) {
+ StringRef name = entry.key;
+ const AttributeDomain domain_output = entry.value.domain;
+ const CustomDataType data_type_output = entry.value.data_type;
+ const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
+ BLI_assert(cpp_type != nullptr);
+
+ result.attribute_try_create(entry.key, domain_output, data_type_output);
+ WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
+ if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
+ write_attribute->domain() != domain_output) {
+ continue;
+ }
+ fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
+
+ 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;
+ }
+ }
+ else {
+ offset += domain_size * set_group.transforms.size();
+ }
+ }
+ }
+
+ write_attribute->apply_span();
+ }
+}
+
+static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
+{
+ Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups);
+
+ MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
+ dst_component.replace(new_mesh);
+
+ /* The position attribute is handled above already. */
+ Map<std::string, AttributeInfo> attributes;
+ gather_attribute_info(attributes, GeometryComponentType::Mesh, set_groups, {"position"});
+ join_attributes(set_groups,
+ GeometryComponentType::Mesh,
+ attributes,
+ static_cast<GeometryComponent &>(dst_component));
+}
+
+static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
+ GeometrySet &result)
+{
+ int totpoint = 0;
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ if (set.has<PointCloudComponent>()) {
+ const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
+ totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ }
+ }
+
+ PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
+ dst_component.replace(pointcloud);
+ Map<std::string, AttributeInfo> attributes;
+ gather_attribute_info(attributes, GeometryComponentType::Mesh, set_groups, {});
+ join_attributes(set_groups,
+ GeometryComponentType::PointCloud,
+ attributes,
+ static_cast<GeometryComponent &>(dst_component));
+}
+
+static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
+ GeometrySet &result)
+{
+ /* Not yet supported. Joining volume grids with the same name requires resampling of at least
+ * one of the grids. The cell size of the resulting volume has to be determined somehow. */
+ VolumeComponent &dst_component = result.get_component_for_write<VolumeComponent>();
+ UNUSED_VARS(set_groups, dst_component);
+}
+
+GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
+{
+ if (!geometry_set.has_instances()) {
+ return geometry_set;
+ }
+
+ GeometrySet new_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);
+
+ return new_geometry_set;
+}
+
/**
* Update the availability of a group of input sockets with the same name,
* used for switching between attribute inputs or single values.
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index b7b2afeefcb..7ca44d82a38 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -49,4 +49,21 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType>);
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
const AttributeDomain domain);
+GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);
+
+struct AttributeInfo {
+ CustomDataType data_type;
+ AttributeDomain domain;
+};
+
+/**
+ * Add information about all the attributes on every component of the type. The resulting info
+ * will contain the highest complexity data type and the highest priority domain among every
+ * attribute with the given name on all of the input components.
+ */
+void gather_attribute_info(Map<std::string, AttributeInfo> &attributes,
+ const GeometryComponentType component_type,
+ Span<GeometryInstanceGroup> set_groups,
+ const Set<std::string> &ignored_attributes);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
index e592bd0bda8..02a6ac49c29 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
@@ -163,6 +163,8 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
align_rotations_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index 179e418214c..fc5fb4c5488 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -81,6 +81,8 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index 5e434a7f96d..ee97102de7b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -318,6 +318,8 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index 92b47769d1f..a5ac1926963 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -119,6 +119,8 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index 076f7a9ee28..1780ec69df2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -267,6 +267,8 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index 976970d06b1..2dbfcd2819c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -174,6 +174,8 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index 45f20ca553a..e46fdaa127a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -202,6 +202,12 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
+ /* This isn't required. This node should be rewritten to handle instances
+ * for the target geometry set. However, the generic BVH API complicates this. */
+ geometry_set_target = geometry_set_realize_instances(geometry_set_target);
+
if (geometry_set.has<MeshComponent>()) {
attribute_calc_proximity(
geometry_set.get_component_for_write<MeshComponent>(), geometry_set_target, params);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index f5765af83b3..f4399b45b2e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -202,6 +202,8 @@ static void geo_node_random_attribute_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const int seed = params.get_input<int>("Seed");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
randomize_attribute(geometry_set.get_component_for_write<MeshComponent>(), params, seed);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index b6a960e5617..fc3cd099d41 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -88,6 +88,8 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index 62a291e8506..adcdab58e30 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -419,6 +419,8 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 403b74b2fef..38215b54640 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -124,6 +124,12 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
return;
}
+ /* TODO: Boolean does support an input of multiple meshes. Currently they must all be
+ * converted to BMesh before running the operation though. D9957 will make it possible
+ * to use the mesh structure directly. */
+ geometry_set_in_a = geometry_set_realize_instances(geometry_set_in_a);
+ geometry_set_in_b = geometry_set_realize_instances(geometry_set_in_b);
+
const Mesh *mesh_in_a = geometry_set_in_a.get_mesh_for_read();
const Mesh *mesh_in_b = geometry_set_in_b.get_mesh_for_read();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index 48ff8f2f683..1c794d1f43e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -51,6 +51,8 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", std::move(geometry_set));
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 4e26977b85a..7249a34134f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -77,35 +77,15 @@ static void geo_node_object_info_exec(GeoNodeExecParams params)
quat_to_eul(rotation, quaternion);
if (object != self_object) {
- if (object->type == OB_MESH) {
- Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object, false);
- if (mesh != nullptr) {
- BKE_mesh_wrapper_ensure_mdata(mesh);
-
- /* Make a copy because the life time of the other mesh might be shorter. */
- Mesh *copied_mesh = BKE_mesh_copy_for_eval(mesh, false);
-
- if (transform_space_relative) {
- /* Transform into the local space of the object that is being modified. */
- BKE_mesh_transform(copied_mesh, transform, true);
- }
-
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(copied_mesh);
- mesh_component.copy_vertex_group_names_from_object(*object);
- }
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+
+ if (transform_space_relative) {
+ instances.add_instance(object, transform);
}
- if (object->type == OB_VOLUME) {
- InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
-
- if (transform_space_relative) {
- instances.add_instance(object, transform);
- }
- else {
- float unit_transform[4][4];
- unit_m4(unit_transform);
- instances.add_instance(object, unit_transform);
- }
+ else {
+ float unit_transform[4][4];
+ unit_m4(unit_transform);
+ instances.add_instance(object, unit_transform);
}
}
}
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 93abed7926e..581c356742b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -419,6 +419,9 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
+ /* TODO: This node only needs read-only access to input instances. */
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
GeometryNodePointDistributeMethod distribute_method =
static_cast<GeometryNodePointDistributeMethod>(params.node().custom1);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 1e7cf21f921..5cb98901d8d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -194,6 +194,10 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
+ /* TODO: This node should be able to instance on the input instances component
+ * rather than making the entire input geometry set real. */
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
if (geometry_set.has<MeshComponent>()) {
add_instances_from_geometry_component(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
index 3ca898bfd83..013dbf5045f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
@@ -165,6 +165,8 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
point_rotate_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
index 78e23b783db..b73c8251e72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
@@ -64,6 +64,8 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
index 5f9d208a440..8bb8c5e980a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -178,6 +178,10 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params)
GeometrySet out_set_a(geometry_set);
GeometrySet out_set_b;
+ /* TODO: This is not necessary-- the input goemetry set can be read only,
+ * but it must be rewritten to handle instance groups. */
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<PointCloudComponent>()) {
separate_point_cloud(*geometry_set.get_component_for_read<PointCloudComponent>(),
params,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index f7f369f5d66..0b9d561bccb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -63,6 +63,8 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (geometry_set.has<MeshComponent>()) {
execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 428f129fb36..b79ca0a6197 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -215,6 +215,9 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params)
GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
GeometrySet geometry_set_out;
+ /* TODO: Read-only access to instances should be supported here, for now they are made real. */
+ geometry_set_in = geometry_set_realize_instances(geometry_set_in);
+
#ifdef WITH_OPENVDB
initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
#endif
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 99f7339a1cc..4cdb669f964 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -55,6 +55,8 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
if (!geometry_set.has_mesh()) {
params.set_output("Geometry", geometry_set);
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 32fa32a9f13..0c754ad3b37 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -65,6 +65,8 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params)
GeometryNodeTriangulateNGons ngon_method = static_cast<GeometryNodeTriangulateNGons>(
params.node().custom2);
+ geometry_set = geometry_set_realize_instances(geometry_set);
+
/* #triangulate_mesh might modify the input mesh currently. */
Mesh *mesh_in = geometry_set.get_mesh_for_write();
if (mesh_in != nullptr) {