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-09-28 19:36:28 +0300
committerHans Goudey <h.goudey@me.com>2021-09-28 19:36:28 +0300
commit44e4f077a9d7b5b609f6199874802675d75f7266 (patch)
treea9714f312e31638643a202ad16a5b4dab429ff3e
parentb32b38b3805fea5baec551acd1a98c4a58b2bb1c (diff)
Geometry Nodes: Run nodes once on unique instance data
As described in T91672, often it can be much more efficient to run each node only on the unique geometry of the instances, rather than realizing all instances and potentially processing redundant data. Sometimes the performance difference can be completely smooth vs. completely unusable. Geometry nodes used to hide that choice from users by always realizing instances, but recently we have decided to expose it. So this commit makes nodes run once per unique reference in the entire tree of nested instances in their input geometries, continuing the work started in rB0559971ab377 and rBf94164d89629f0d2. For the old behavior, a realize instances node can be added before the nodes, which is done in the versioning code. Differential Revision: https://developer.blender.org/D12656
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh1
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc10
-rw-r--r--source/blender/blenloader/intern/versioning_300.c75
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc53
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc16
17 files changed, 279 insertions, 131 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index b973d8b9a18..5ef0459663b 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 27
+#define BLENDER_FILE_SUBVERSION 28
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 4954b1d5ab2..724ca224cab 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -330,6 +330,7 @@ struct GeometrySet {
bool has_volume() const;
bool has_curve() const;
bool has_realized_data() const;
+ bool is_empty() const;
const Mesh *get_mesh_for_read() const;
const PointCloud *get_pointcloud_for_read() const;
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 400e0fda518..0aac6ae3adf 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -318,6 +318,16 @@ bool GeometrySet::has_realized_data() const
return this->get_component_for_read<InstancesComponent>() == nullptr;
}
+/* Return true if the geometry set has any component that isn't empty. */
+bool GeometrySet::is_empty() const
+{
+ if (components_.is_empty()) {
+ return true;
+ }
+ return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() ||
+ this->has_instances());
+}
+
/* Create a new geometry set that only contains the given mesh. */
GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership)
{
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 86755cbaf95..3b51e40c218 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -449,6 +449,73 @@ static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const Lis
#undef SEQ_SPEED_COMPRESS_IPO_Y
}
+static bNodeLink *find_connected_link(bNodeTree *ntree, bNodeSocket *in_socket)
+{
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ if (link->tosock == in_socket) {
+ return link;
+ }
+ }
+ return NULL;
+}
+
+static void add_realize_instances_before_socket(bNodeTree *ntree,
+ bNode *node,
+ bNodeSocket *geometry_socket)
+{
+ BLI_assert(geometry_socket->type == SOCK_GEOMETRY);
+ bNodeLink *link = find_connected_link(ntree, geometry_socket);
+ if (link == NULL) {
+ return;
+ }
+
+ /* If the realize instances node is already before this socket, no need to continue. */
+ if (link->fromnode->type == GEO_NODE_REALIZE_INSTANCES) {
+ return;
+ }
+
+ bNode *realize_node = nodeAddStaticNode(NULL, ntree, GEO_NODE_REALIZE_INSTANCES);
+ realize_node->parent = node->parent;
+ realize_node->locx = node->locx - 100;
+ realize_node->locy = node->locy;
+ nodeAddLink(ntree, link->fromnode, link->fromsock, realize_node, realize_node->inputs.first);
+ link->fromnode = realize_node;
+ link->fromsock = realize_node->outputs.first;
+}
+
+/**
+ * If a node used to realize instances implicitly and will no longer do so in 3.0, add a "Realize
+ * Instances" node in front of it to avoid changing behavior. Don't do this if the node will be
+ * replaced anyway though.
+ */
+static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (ELEM(node->type,
+ GEO_NODE_ATTRIBUTE_CAPTURE,
+ GEO_NODE_SEPARATE_COMPONENTS,
+ GEO_NODE_CONVEX_HULL,
+ GEO_NODE_CURVE_LENGTH,
+ GEO_NODE_BOOLEAN,
+ GEO_NODE_CURVE_FILLET,
+ GEO_NODE_CURVE_RESAMPLE,
+ GEO_NODE_CURVE_TO_MESH,
+ GEO_NODE_CURVE_TRIM,
+ GEO_NODE_MATERIAL_REPLACE,
+ GEO_NODE_MESH_SUBDIVIDE,
+ GEO_NODE_ATTRIBUTE_REMOVE,
+ GEO_NODE_TRIANGULATE)) {
+ bNodeSocket *geometry_socket = node->inputs.first;
+ add_realize_instances_before_socket(ntree, node, geometry_socket);
+ }
+ /* Also realize instances for the profile input of the curve to mesh node. */
+ if (node->type == GEO_NODE_CURVE_TO_MESH) {
+ bNodeSocket *profile_socket = node->inputs.last;
+ add_realize_instances_before_socket(ntree, node, profile_socket);
+ }
+ }
+}
+
void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -531,6 +598,14 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 300, 28)) {
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_geometry_nodes_add_realize_instance_nodes(ntree);
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index 81629a0f8b4..43fb00a482c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -117,8 +117,6 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
const bNode &node = params.node();
const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *)
node.storage;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index 21a9a338857..f93ef6f1db3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -47,8 +47,6 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute");
- geometry_set = geometry_set_realize_instances(geometry_set);
-
if (geometry_set.has<MeshComponent>()) {
remove_attribute(
geometry_set.get_component_for_write<MeshComponent>(), params, attribute_names);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 2a1c43a89fe..21b425c0ed4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -83,10 +83,14 @@ static void geo_node_boolean_exec(GeoNodeExecParams params)
GeometrySet set_a;
if (operation == GEO_NODE_BOOLEAN_DIFFERENCE) {
set_a = params.extract_input<GeometrySet>("Geometry 1");
+ if (set_a.has_instances()) {
+ params.error_message_add(
+ NodeWarningType::Info,
+ TIP_("Instances are not supported for the first geometry input, and will not be used"));
+ }
/* Note that it technically wouldn't be necessary to realize the instances for the first
* geometry input, but the boolean code expects the first shape for the difference operation
* to be a single mesh. */
- set_a = geometry_set_realize_instances(set_a);
const Mesh *mesh_in_a = set_a.get_mesh_for_read();
if (mesh_in_a != nullptr) {
meshes.append(mesh_in_a);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index f1e10e3d276..4377d32210d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -227,9 +227,13 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
return hull_from_bullet(geometry_set.get_mesh_for_read(), positions);
}
+/* Since only positions are read from the instances, this can be used as an internal optimization
+ * to avoid the cost of realizing instances before the node. But disable this for now, since
+ * re-enabling that optimization will be a separate step. */
+# if 0
static void read_positions(const GeometryComponent &component,
- Span<float4x4> transforms,
- Vector<float3> *r_coords)
+ Span<float4x4> transforms,
+ Vector<float3> *r_coords)
{
GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
@@ -265,6 +269,31 @@ static void read_curve_positions(const CurveEval &curve,
}
}
+static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
+{
+ Vector<GeometryInstanceGroup> set_groups;
+ bke::geometry_set_gather_instances(geometry_set, set_groups);
+
+ Vector<float3> coords;
+
+ for (const GeometryInstanceGroup &set_group : set_groups) {
+ const GeometrySet &set = set_group.geometry_set;
+ Span<float4x4> transforms = set_group.transforms;
+
+ if (set.has_pointcloud()) {
+ read_positions(*set.get_component_for_read<PointCloudComponent>(), transforms, &coords);
+ }
+ if (set.has_mesh()) {
+ read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
+ }
+ if (set.has_curve()) {
+ read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
+ }
+ }
+ return hull_from_bullet(nullptr, coords);
+}
+# endif
+
#endif /* WITH_BULLET */
static void geo_node_convex_hull_exec(GeoNodeExecParams params)
@@ -272,33 +301,14 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
#ifdef WITH_BULLET
- Mesh *mesh = nullptr;
- if (geometry_set.has_instances()) {
- Vector<GeometryInstanceGroup> set_groups;
- bke::geometry_set_gather_instances(geometry_set, set_groups);
-
- Vector<float3> coords;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- Span<float4x4> transforms = set_group.transforms;
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = compute_hull(geometry_set);
+ geometry_set.replace_mesh(mesh);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
+ });
- if (set.has_pointcloud()) {
- read_positions(*set.get_component_for_read<PointCloudComponent>(), transforms, &coords);
- }
- if (set.has_mesh()) {
- read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
- }
- if (set.has_curve()) {
- read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
- }
- }
- mesh = hull_from_bullet(nullptr, coords);
- }
- else {
- mesh = compute_hull(geometry_set);
- }
- params.set_output("Convex Hull", GeometrySet::create_with_mesh(mesh));
+ params.set_output("Convex Hull", std::move(geometry_set));
#else
params.error_message_add(NodeWarningType::Error,
TIP_("Disabled, Blender was compiled without Bullet"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index 830cfcc8331..67ce20efd9d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -563,19 +563,16 @@ static std::unique_ptr<CurveEval> fillet_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_fillet_exec(GeoNodeExecParams params)
+static void calculate_curve_fillet(GeometrySet &geometry_set,
+ const GeometryNodeCurveFilletMode mode,
+ const Field<float> &radius_field,
+ const std::optional<Field<int>> &count_field,
+ const bool limit_radius)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
-
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
if (!geometry_set.has_curve()) {
- params.set_output("Curve", geometry_set);
return;
}
- NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
- const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
FilletParam fillet_param;
fillet_param.mode = mode;
@@ -584,19 +581,16 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
fn::FieldEvaluator field_evaluator{field_context, domain_size};
- Field<float> radius_field = params.extract_input<Field<float>>("Radius");
- field_evaluator.add(std::move(radius_field));
+ field_evaluator.add(radius_field);
if (mode == GEO_NODE_CURVE_FILLET_POLY) {
- Field<int> count_field = params.extract_input<Field<int>>("Count");
- field_evaluator.add(std::move(count_field));
+ field_evaluator.add(*count_field);
}
field_evaluator.evaluate();
fillet_param.radii = &field_evaluator.get_evaluated<float>(0);
if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) {
- params.set_output("Geometry", geometry_set);
return;
}
@@ -604,13 +598,36 @@ static void geo_node_fillet_exec(GeoNodeExecParams params)
fillet_param.counts = &field_evaluator.get_evaluated<int>(1);
}
- fillet_param.limit_radius = params.extract_input<bool>("Limit Radius");
+ fillet_param.limit_radius = limit_radius;
const CurveEval &input_curve = *geometry_set.get_curve_for_read();
std::unique_ptr<CurveEval> output_curve = fillet_curve(input_curve, fillet_param);
- params.set_output("Curve", GeometrySet::create_with_curve(output_curve.release()));
+ geometry_set.replace_curve(output_curve.release());
+}
+
+static void geo_node_fillet_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+
+ NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)params.node().storage;
+ const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode;
+
+ Field<float> radius_field = params.extract_input<Field<float>>("Radius");
+ const bool limit_radius = params.extract_input<bool>("Limit Radius");
+
+ std::optional<Field<int>> count_field;
+ if (mode == GEO_NODE_CURVE_FILLET_POLY) {
+ count_field.emplace(params.extract_input<Field<int>>("Count"));
+ }
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ calculate_curve_fillet(geometry_set, mode, radius_field, count_field, limit_radius);
+ });
+
+ params.set_output("Curve", std::move(geometry_set));
}
+
} // namespace blender::nodes
void register_node_type_geo_curve_fillet()
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 8fe054633a1..ac7df35bb72 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -28,7 +28,6 @@ static void geo_node_curve_length_declare(NodeDeclarationBuilder &b)
static void geo_node_curve_length_exec(GeoNodeExecParams params)
{
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
- curve_set = bke::geometry_set_realize_instances(curve_set);
if (!curve_set.has_curve()) {
params.set_output("Length", 0.0f);
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 208525f17f6..b8f62460069 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -202,20 +202,26 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
return output_curve;
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void geometry_set_curve_resample(GeometrySet &geometry_set,
+ const SampleModeParam &mode_param)
{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
if (!geometry_set.has_curve()) {
- params.set_output("Geometry", GeometrySet());
return;
}
const CurveEval &input_curve = *geometry_set.get_curve_for_read();
+ std::unique_ptr<CurveEval> output_curve = resample_curve(input_curve, mode_param);
+
+ geometry_set.replace_curve(output_curve.release());
+}
+
+static void geo_node_resample_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)params.node().storage;
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
+
SampleModeParam mode_param;
mode_param.mode = mode;
if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) {
@@ -232,9 +238,10 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
mode_param.length.emplace(resolution);
}
- std::unique_ptr<CurveEval> output_curve = resample_curve(input_curve, mode_param);
+ geometry_set.modify_geometry_sets(
+ [&](GeometrySet &geometry_set) { geometry_set_curve_resample(geometry_set, mode_param); });
- params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+ params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index 89ba635ff4b..f7cef9bbf63 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -32,39 +32,52 @@ static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Mesh");
}
-static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
+static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
+ const GeometrySet &profile_set,
+ const GeoNodeExecParams &params)
{
- GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
- GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
-
- curve_set = bke::geometry_set_realize_instances(curve_set);
- profile_set = bke::geometry_set_realize_instances(profile_set);
-
- /* NOTE: Theoretically an "is empty" check would be more correct for errors. */
- if (profile_set.has_mesh() && !profile_set.has_curve()) {
- params.error_message_add(NodeWarningType::Warning,
- TIP_("No curve data available in profile input"));
- }
-
- if (!curve_set.has_curve()) {
- if (curve_set.has_mesh()) {
+ if (!geometry_set.has_curve()) {
+ if (!geometry_set.is_empty()) {
params.error_message_add(NodeWarningType::Warning,
TIP_("No curve data available in curve input"));
}
- params.set_output("Mesh", GeometrySet());
return;
}
const CurveEval *profile_curve = profile_set.get_curve_for_read();
if (profile_curve == nullptr) {
- Mesh *mesh = bke::curve_to_wire_mesh(*curve_set.get_curve_for_read());
- params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
+ Mesh *mesh = bke::curve_to_wire_mesh(*geometry_set.get_curve_for_read());
+ geometry_set.replace_mesh(mesh);
}
else {
- Mesh *mesh = bke::curve_to_mesh_sweep(*curve_set.get_curve_for_read(), *profile_curve);
- params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
+ Mesh *mesh = bke::curve_to_mesh_sweep(*geometry_set.get_curve_for_read(), *profile_curve);
+ geometry_set.replace_mesh(mesh);
+ }
+}
+
+static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
+{
+ GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
+ GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
+
+ if (profile_set.has_instances()) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Instances are not supported in the profile input"));
+ params.set_output("Mesh", GeometrySet());
+ return;
+ }
+
+ if (!profile_set.has_curve() && !profile_set.is_empty()) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("No curve data available in the profile input"));
}
+
+ curve_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_curve_to_mesh(geometry_set, profile_set, params);
+ });
+
+ params.set_output("Mesh", std::move(curve_set));
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 2b6d25b6bf3..97043980899 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -320,28 +320,18 @@ static void trim_bezier_spline(Spline &spline,
bezier_spline.resize(size);
}
-static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+static void geometry_set_curve_trim(GeometrySet &geometry_set,
+ const GeometryNodeCurveSampleMode mode,
+ const float start,
+ const float end)
{
- const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
- const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
if (!geometry_set.has_curve()) {
- params.set_output("Curve", std::move(geometry_set));
return;
}
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
+ CurveEval &curve = *geometry_set.get_curve_for_write();
MutableSpan<SplinePtr> splines = curve.splines();
- const float start = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ?
- params.extract_input<float>("Start") :
- params.extract_input<float>("Start_001");
- const float end = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ? params.extract_input<float>("End") :
- params.extract_input<float>("End_001");
-
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
Spline &spline = *splines[i];
@@ -382,6 +372,29 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params)
splines[i]->mark_cache_invalid();
}
});
+}
+
+static void geo_node_curve_trim_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage;
+ const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
+
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
+
+ if (mode == GEO_NODE_CURVE_SAMPLE_FACTOR) {
+ const float start = params.extract_input<float>("Start");
+ const float end = params.extract_input<float>("End");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_curve_trim(geometry_set, mode, start, end);
+ });
+ }
+ else if (mode == GEO_NODE_CURVE_SAMPLE_LENGTH) {
+ const float start = params.extract_input<float>("Start_001");
+ const float end = params.extract_input<float>("End_001");
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ geometry_set_curve_trim(geometry_set, mode, start, end);
+ });
+ }
params.set_output("Curve", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index a9c3bfc6ce0..a917434fa00 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -40,11 +40,9 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
Material *new_material = params.extract_input<Material *>("New");
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry_set_realize_instances(geometry_set);
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ Mesh *mesh = geometry_set.get_mesh_for_write();
if (mesh != nullptr) {
for (const int i : IndexRange(mesh->totcol)) {
if (mesh->mat[i] == old_material) {
@@ -52,7 +50,7 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params)
}
}
}
- }
+ });
params.set_output("Geometry", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index 9ca74fed9a7..c436f5bd480 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -32,28 +32,9 @@ static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Geometry");
}
-static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int level)
{
- 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;
- }
-
-#ifndef WITH_OPENSUBDIV
- params.error_message_add(NodeWarningType::Error,
- TIP_("Disabled, Blender was compiled without OpenSubdiv"));
- params.set_output("Geometry", std::move(geometry_set));
- return;
-#endif
-
- /* See CCGSUBSURF_LEVEL_MAX for max limit. */
- const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
-
- if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
return;
}
@@ -61,7 +42,7 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
/* Initialize mesh settings. */
SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = (1 << subdiv_level) + 1;
+ mesh_settings.resolution = (1 << level) + 1;
mesh_settings.use_optimal_display = false;
/* Initialize subdivision settings. */
@@ -79,7 +60,6 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
/* In case of bad topology, skip to input mesh. */
if (subdiv == nullptr) {
- params.set_output("Geometry", std::move(geometry_set));
return;
}
@@ -90,6 +70,29 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
mesh_component.replace(mesh_out);
BKE_subdiv_free(subdiv);
+}
+
+static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+#ifndef WITH_OPENSUBDIV
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenSubdiv"));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+#endif
+
+ /* See CCGSUBSURF_LEVEL_MAX for max limit. */
+ const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 11);
+
+ if (subdiv_level == 0) {
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
+
+ geometry_set.modify_geometry_sets(
+ [&](GeometrySet &geometry_set) { geometry_set_mesh_subdivide(geometry_set, subdiv_level); });
params.set_output("Geometry", std::move(geometry_set));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index c63e4ec49d9..dafd10cee2d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -25,20 +25,18 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>("Point Cloud");
b.add_output<decl::Geometry>("Curve");
b.add_output<decl::Geometry>("Volume");
+ b.add_output<decl::Geometry>("Instances");
}
static void geo_node_separate_components_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- /* Note that it will be possible to skip realizing instances here when instancing
- * geometry directly is supported by creating corresponding geometry instances. */
- geometry_set = bke::geometry_set_realize_instances(geometry_set);
-
GeometrySet meshes;
GeometrySet point_clouds;
GeometrySet volumes;
GeometrySet curves;
+ GeometrySet instances;
if (geometry_set.has<MeshComponent>()) {
meshes.add(*geometry_set.get_component_for_read<MeshComponent>());
@@ -52,11 +50,15 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params)
if (geometry_set.has<VolumeComponent>()) {
volumes.add(*geometry_set.get_component_for_read<VolumeComponent>());
}
+ if (geometry_set.has<InstancesComponent>()) {
+ instances.add(*geometry_set.get_component_for_read<InstancesComponent>());
+ }
params.set_output("Mesh", meshes);
params.set_output("Point Cloud", point_clouds);
params.set_output("Curve", curves);
params.set_output("Volume", volumes);
+ params.set_output("Instances", instances);
}
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 8886c7194db..7ef0913622c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -58,14 +58,14 @@ 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) {
- Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
- geometry_set.replace_mesh(mesh_out);
- }
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ /* #triangulate_mesh might modify the input mesh currently. */
+ Mesh *mesh_in = geometry_set.get_mesh_for_write();
+ if (mesh_in != nullptr) {
+ Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
+ geometry_set.replace_mesh(mesh_out);
+ }
+ });
params.set_output("Geometry", std::move(geometry_set));
}