From d75b3c6889c794702ee1f64cb21ae55cc0504db7 Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Sat, 10 Feb 2024 23:54:03 +0300 Subject: [PATCH 1/7] init --- .../startup/bl_ui/node_add_menu_geometry.py | 1 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + source/blender/nodes/geometry/CMakeLists.txt | 1 + .../geometry/nodes/node_geo_sample_by_id.cc | 180 ++++++++++++++++++ 5 files changed, 184 insertions(+) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index af54f2d961d..e5ce6716ce9 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -235,6 +235,7 @@ class NODE_MT_geometry_node_GEO_GEOMETRY_SAMPLE(Menu): node_add_menu.add_node_type(layout, "GeometryNodeRaycast") node_add_menu.add_node_type(layout, "GeometryNodeSampleIndex") node_add_menu.add_node_type(layout, "GeometryNodeSampleNearest") + node_add_menu.add_node_type(layout, "GeometryNodeSampleByID") node_add_menu.draw_assets_for_catalog(layout, "Geometry/Sample") diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 0fbc59f166e..afc7acea7d9 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1331,6 +1331,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define GEO_NODE_STORE_NAMED_GRID 2122 #define GEO_NODE_SORT_ELEMENTS 2123 #define GEO_NODE_MENU_SWITCH 2124 +#define GEO_NODE_SAMPLE_BY_ID 2125 /** \} */ diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 7bbdd2dbad1..1960a965d1d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -417,6 +417,7 @@ DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, 0, "RESAMPLE_CURVE", ResampleCurv DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "Change the direction of curves by swapping their start and end data") DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "Rotate geometry instances in local or global space") DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "Retrieve data from a point on a curve at a certain distance from its start") +DefNode(GeometryNode, GEO_NODE_SAMPLE_BY_ID, 0, "SAMPLE_BY_ID", SampleByID, "Sample by ID", "") DefNode(GeometryNode, GEO_NODE_SAMPLE_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, 0, "SAMPLE_NEAREST_SURFACE", SampleNearestSurface, "Sample Nearest Surface", "Calculate the interpolated value of a mesh attribute on the closest point of its surface") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST, 0, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position. Similar to the \"Index of Nearest\" node") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 72c672048db..77be41ae47e 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -154,6 +154,7 @@ set(SRC nodes/node_geo_realize_instances.cc nodes/node_geo_remove_attribute.cc nodes/node_geo_repeat.cc + nodes/node_geo_sample_by_id.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_sample_index.cc nodes/node_geo_sample_nearest.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc new file mode 100644 index 00000000000..41d8029757c --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -0,0 +1,180 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "UI_interface.hh" +#include "UI_resources.hh" + +#include "NOD_socket_search_link.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_sample_by_id_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input("Geometry").supported_type({GeometryComponent::Type::Mesh, GeometryComponent::Type::PointCloud, GeometryComponent::Type::Curve,GeometryComponent::Type::Instance}); + + b.add_input("ID").implicit_field_on(implicit_field_inputs::id_or_index, {0}); + b.add_input("Sample ID").supports_field(); + + b.add_output("Index").dependent_field({2}); +} + +static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) +{ + uiItemR(layout, ptr, "domain", UI_ITEM_NONE, "", ICON_NONE); +} + +static void node_init(bNodeTree * /*tree*/, bNode *node) +{ + node->custom1 = int(AttrDomain::Point); +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const NodeDeclaration &declaration = *params.node_type().static_declaration; + search_link_ops_for_declarations(params, declaration.inputs); + search_link_ops_for_declarations(params, declaration.outputs); +} + +static bool component_is_available(const GeometrySet &geometry, + const GeometryComponent::Type type, + const AttrDomain domain) +{ + if (!geometry.has(type)) { + return false; + } + const GeometryComponent &component = *geometry.get_component(type); + return component.attribute_domain_size(domain) != 0; +} + +static const GeometryComponent *find_source_component(const GeometrySet &geometry, + const AttrDomain domain) +{ + /* Choose the other component based on a consistent order, rather than some more complicated + * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */ + static const Array supported_types = { + GeometryComponent::Type::Mesh, + GeometryComponent::Type::PointCloud, + GeometryComponent::Type::Curve, + GeometryComponent::Type::Instance}; + for (const GeometryComponent::Type src_type : supported_types) { + if (component_is_available(geometry, src_type, domain)) { + return geometry.get_component(src_type); + } + } + + return nullptr; +} + +static Map id_to_index_map(const VArray &id_varray) +{ + BLI_assert(!id_varray.is_empty()); + Map map; + + if (const std::optional id = id_varray.get_if_single()) { + map.add_new(*id, 0); + return map; + } + + const IndexRange range = id_varray.index_range(); + devirtualize_varray(id_varray, [&](auto &id_varray) { + for (const int index : range) { + map.add(id_varray[index], index); + } + }); + + return map; +} + +class SampleIDFunction : public mf::MultiFunction { + mf::Signature signature_; + Map id_map_; + + public: + SampleIDFunction(GeometrySet geometry, Field id_field, const AttrDomain domain) + { + geometry.ensure_owns_direct_data(); + + mf::SignatureBuilder builder{"Sample ID", signature_}; + builder.single_input("Sample ID"); + builder.single_output("Index"); + this->set_signature(&signature_); + + const GeometryComponent *component = find_source_component(geometry, domain); + if (component == nullptr) { + throw std::runtime_error("no component to sample"); + } + + bke::GeometryFieldContext context(*component, domain); + FieldEvaluator evaluator(context, component->attribute_domain_size(domain)); + evaluator.add(std::move(id_field)); + evaluator.evaluate(); + + const VArray id_varray = evaluator.get_evaluated(0); + id_map_ = id_to_index_map(id_varray); + } + + void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override + { + const VArray &ids = params.readonly_single_input(0, "Sample ID"); + MutableSpan indices = params.uninitialized_single_output(1, "Index"); + + devirtualize_varray(ids, [&](auto &ids) { + mask.foreach_index_optimized([&](const int i) { + indices[i] = id_map_.lookup_default(ids[i], 0); + }); + }); + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry = params.extract_input("Geometry"); + const AttrDomain domain = AttrDomain(params.node().custom1); + + Field id_field = params.extract_input>("ID"); + Field sample_id_field = params.extract_input>("Sample ID"); + + std::unique_ptr sample_id_fn; + try { + sample_id_fn = std::make_unique(std::move(geometry), std::move(id_field), domain); + } + catch (const std::runtime_error &) { + params.set_default_remaining_outputs(); + return; + } + + auto sample_id_op = FieldOperation::Create(std::move(sample_id_fn), {std::move(sample_id_field)}); + params.set_output("Index", GField(std::move(sample_id_op))); +} + +static void node_rna(StructRNA *srna) +{ + RNA_def_node_enum(srna, + "domain", + "Domain", + "", + rna_enum_attribute_domain_items, + NOD_inline_enum_accessors(custom1), + int(AttrDomain::Point)); +} + +static void node_register() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_SAMPLE_BY_ID, "Sample by ID", NODE_CLASS_GEOMETRY); + ntype.initfunc = node_init; + ntype.declare = node_declare; + ntype.geometry_node_execute = node_geo_exec; + ntype.draw_buttons = node_layout; + ntype.gather_link_search_ops = node_gather_link_searches; + nodeRegisterType(&ntype); + + node_rna(ntype.rna_ext.srna); +} +NOD_REGISTER_NODE(node_register) + +} // namespace blender::nodes::node_geo_sample_by_id_cc -- 2.30.2 From 3ae7183aae23fc69e62b30fe71ac310cbc280d41 Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Sat, 10 Feb 2024 23:55:19 +0300 Subject: [PATCH 2/7] format --- .../geometry/nodes/node_geo_sample_by_id.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index 41d8029757c..48dec80fa01 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -13,7 +13,11 @@ namespace blender::nodes::node_geo_sample_by_id_cc { static void node_declare(NodeDeclarationBuilder &b) { - b.add_input("Geometry").supported_type({GeometryComponent::Type::Mesh, GeometryComponent::Type::PointCloud, GeometryComponent::Type::Curve,GeometryComponent::Type::Instance}); + b.add_input("Geometry") + .supported_type({GeometryComponent::Type::Mesh, + GeometryComponent::Type::PointCloud, + GeometryComponent::Type::Curve, + GeometryComponent::Type::Instance}); b.add_input("ID").implicit_field_on(implicit_field_inputs::id_or_index, {0}); b.add_input("Sample ID").supports_field(); @@ -122,9 +126,8 @@ class SampleIDFunction : public mf::MultiFunction { MutableSpan indices = params.uninitialized_single_output(1, "Index"); devirtualize_varray(ids, [&](auto &ids) { - mask.foreach_index_optimized([&](const int i) { - indices[i] = id_map_.lookup_default(ids[i], 0); - }); + mask.foreach_index_optimized( + [&](const int i) { indices[i] = id_map_.lookup_default(ids[i], 0); }); }); } }; @@ -139,14 +142,16 @@ static void node_geo_exec(GeoNodeExecParams params) std::unique_ptr sample_id_fn; try { - sample_id_fn = std::make_unique(std::move(geometry), std::move(id_field), domain); + sample_id_fn = std::make_unique( + std::move(geometry), std::move(id_field), domain); } catch (const std::runtime_error &) { params.set_default_remaining_outputs(); return; } - auto sample_id_op = FieldOperation::Create(std::move(sample_id_fn), {std::move(sample_id_field)}); + auto sample_id_op = FieldOperation::Create(std::move(sample_id_fn), + {std::move(sample_id_field)}); params.set_output("Index", GField(std::move(sample_id_op))); } -- 2.30.2 From b0d46def11a4fade45cac9095758c31389481d7a Mon Sep 17 00:00:00 2001 From: Iliya Katushenock Date: Sat, 10 Feb 2024 23:14:23 +0100 Subject: [PATCH 3/7] Update source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc --- source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index 48dec80fa01..8dc150fb72c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors +/* SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ -- 2.30.2 From 7acb6dc7f0bceaf8d294483665e9758bc18c767d Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Thu, 15 Feb 2024 01:51:30 +0300 Subject: [PATCH 4/7] add valid out --- .../geometry/nodes/node_geo_sample_by_id.cc | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index 8dc150fb72c..f3b4a229aa7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -23,6 +23,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input("Sample ID").supports_field(); b.add_output("Index").dependent_field({2}); + b.add_output("Is Valid").dependent_field({2}); } static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) @@ -103,7 +104,8 @@ class SampleIDFunction : public mf::MultiFunction { mf::SignatureBuilder builder{"Sample ID", signature_}; builder.single_input("Sample ID"); - builder.single_output("Index"); + builder.single_output("Index", mf::ParamFlag::SupportsUnusedOutput); + builder.single_output("Is Valid", mf::ParamFlag::SupportsUnusedOutput); this->set_signature(&signature_); const GeometryComponent *component = find_source_component(geometry, domain); @@ -123,12 +125,23 @@ class SampleIDFunction : public mf::MultiFunction { void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override { const VArray &ids = params.readonly_single_input(0, "Sample ID"); - MutableSpan indices = params.uninitialized_single_output(1, "Index"); + MutableSpan indices = params.uninitialized_single_output_if_required(1, "Index"); + MutableSpan is_valid = params.uninitialized_single_output_if_required(2, + "Is Valid"); - devirtualize_varray(ids, [&](auto &ids) { - mask.foreach_index_optimized( - [&](const int i) { indices[i] = id_map_.lookup_default(ids[i], 0); }); - }); + if (!indices.is_empty()) { + devirtualize_varray(ids, [&](auto &ids) { + mask.foreach_index_optimized( + [&](const int i) { indices[i] = id_map_.lookup_default(ids[i], 0); }); + }); + } + + if (!is_valid.is_empty()) { + devirtualize_varray(ids, [&](auto &ids) { + mask.foreach_index_optimized( + [&](const int i) { is_valid[i] = id_map_.contains(ids[i]); }); + }); + } } }; @@ -152,7 +165,8 @@ static void node_geo_exec(GeoNodeExecParams params) auto sample_id_op = FieldOperation::Create(std::move(sample_id_fn), {std::move(sample_id_field)}); - params.set_output("Index", GField(std::move(sample_id_op))); + params.set_output("Index", Field(sample_id_op, 0)); + params.set_output("Is Valid", Field(std::move(sample_id_op), 1)); } static void node_rna(StructRNA *srna) -- 2.30.2 From f66ba4ee6d290fa6299704701cc4b4858e161654 Mon Sep 17 00:00:00 2001 From: Iliya Katushenock Date: Wed, 14 Feb 2024 23:52:57 +0100 Subject: [PATCH 5/7] Cleanup --- source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index f3b4a229aa7..36ce30a6eb8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -130,14 +130,14 @@ class SampleIDFunction : public mf::MultiFunction { "Is Valid"); if (!indices.is_empty()) { - devirtualize_varray(ids, [&](auto &ids) { + devirtualize_varray(ids, [&](auto ids) { mask.foreach_index_optimized( [&](const int i) { indices[i] = id_map_.lookup_default(ids[i], 0); }); }); } if (!is_valid.is_empty()) { - devirtualize_varray(ids, [&](auto &ids) { + devirtualize_varray(ids, [&](auto ids) { mask.foreach_index_optimized( [&](const int i) { is_valid[i] = id_map_.contains(ids[i]); }); }); -- 2.30.2 From 010a7866e6b3897addab766a711a7db623c67e28 Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Sat, 24 Feb 2024 19:31:48 +0300 Subject: [PATCH 6/7] progress add descriptions --- .../blender/nodes/geometry/nodes/node_geo_sample_by_id.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index 07fed7ce09b..db4172086f9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -22,8 +22,11 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input("ID").implicit_field_on(implicit_field_inputs::id_or_index, {0}); b.add_input("Sample ID").supports_field(); - b.add_output("Index").dependent_field({2}); - b.add_output("Is Valid").dependent_field({2}); + b.add_output("Index").dependent_field({2}).description( + "First index of sample ID in sampled geometry"); + b.add_output("Is Valid") + .dependent_field({2}) + .description("Sample ID is exists in sempled geometry at least once"); } static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) -- 2.30.2 From 1ed9c77271cd6b6fd3804d4b43781b3f94fdca6b Mon Sep 17 00:00:00 2001 From: Iliya Katueshenock Date: Tue, 14 May 2024 16:09:52 +0300 Subject: [PATCH 7/7] merge main --- source/blender/blenkernel/BKE_node.hh | 5 +---- source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.hh b/source/blender/blenkernel/BKE_node.hh index 54c8bc79e89..d1f6cda2d10 100644 --- a/source/blender/blenkernel/BKE_node.hh +++ b/source/blender/blenkernel/BKE_node.hh @@ -1323,14 +1323,11 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index #define GEO_NODE_POINTS_TO_SDF_GRID 2128 #define GEO_NODE_GRID_TO_MESH 2129 #define GEO_NODE_DISTRIBUTE_POINTS_IN_GRID 2130 -<<<<<<< HEAD -#define GEO_NODE_SAMPLE_BY_ID 2131 -======= #define GEO_NODE_SDF_GRID_BOOLEAN 2131 #define GEO_NODE_TOOL_VIEWPORT_TRANSFORM 2132 #define GEO_NODE_TOOL_MOUSE_POSITION 2133 #define GEO_NODE_SAMPLE_GRID_INDEX 2134 ->>>>>>> main +#define GEO_NODE_SAMPLE_BY_ID 2135 /** \} */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc index db4172086f9..a66fe2f8988 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_by_id.cc @@ -185,7 +185,7 @@ static void node_rna(StructRNA *srna) static void node_register() { - static bNodeType ntype; + static blender::bke::bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SAMPLE_BY_ID, "Sample by ID", NODE_CLASS_GEOMETRY); ntype.initfunc = node_init; @@ -193,7 +193,7 @@ static void node_register() ntype.geometry_node_execute = node_geo_exec; ntype.draw_buttons = node_layout; ntype.gather_link_search_ops = node_gather_link_searches; - nodeRegisterType(&ntype); + blender::bke::nodeRegisterType(&ntype); node_rna(ntype.rna_ext.srna); } -- 2.30.2