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:
authorHans Goudey <h.goudey@me.com>2021-02-12 20:58:15 +0300
committerHans Goudey <h.goudey@me.com>2021-02-12 20:58:15 +0300
commita4baedea91196176cb07d15a4d8acfab52cf9f83 (patch)
tree5d0d7c06fdab146a1abc3495a882bd8ef3b68463
parentff3df2ea568f6f55cdee74ce6ed5586c15af2062 (diff)
Geometry Nodes: Make instances real on-demand
This commit makes the geometry output of the collection info usable. The output is the geometry of a collection instance, but this commit adds a utility to convert the instances to real geometry, used in the background whenever it is needed, like copy on write. The recursive nature of the "realize instances" code is essential, because collection instances in the `InstancesComponent`, might have no geometry sets of their own containing even more collection instances, which might then contain object instances, etc. Another consideration is that currently, every single instance contains a reference to its data. This is inefficient since most of the time there are many locations and only a few sets of unique data. So this commit adds a `GeometryInstanceGroup` to support this future optimization. The API for instances returns a vector of `GeometryInstanceGroup`. This may be less efficient when there are many instances, but it makes more complicated operations like point distribution that need to iterate over input geometry multiple times much simpler. Any code that needs to change data, like most of the attribute nodes, can simply call `geometry_set_realize_instances(geometry_set)`, which will move any geometry in the `InstancesComponent` to new "real" geometry components. Many nodes can support read-only access to instances in order to avoid making them real, this will be addressed where needed in the near future. Instances from the existing "dupli" system are not supported yet. Differential Revision: https://developer.blender.org/D10327
-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) {