diff options
author | Hans Goudey <h.goudey@me.com> | 2021-09-28 19:36:28 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-09-28 19:36:28 +0300 |
commit | 44e4f077a9d7b5b609f6199874802675d75f7266 (patch) | |
tree | a9714f312e31638643a202ad16a5b4dab429ff3e /source/blender/nodes | |
parent | b32b38b3805fea5baec551acd1a98c4a58b2bb1c (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
Diffstat (limited to 'source/blender/nodes')
13 files changed, 192 insertions, 130 deletions
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 ¶ms) { - 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)); } |