From c2c6abd5a7d7e40cabd51ba760b1469155daae75 Mon Sep 17 00:00:00 2001 From: illua1 Date: Thu, 6 Apr 2023 23:29:30 +0300 Subject: [PATCH 1/4] init commit --- .../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 + .../nodes/geometry/node_geometry_register.cc | 1 + .../nodes/geometry/node_geometry_register.hh | 1 + .../nodes/node_geo_sample_material.cc | 77 +++++++++++++++++++ 7 files changed, 83 insertions(+) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_sample_material.cc diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index f5407790067..71f1ddf6968 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -307,6 +307,7 @@ class NODE_MT_geometry_node_GEO_MATERIAL(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeReplaceMaterial") + node_add_menu.add_node_type(layout, "GeometryNodeSampleMaterial") layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeInputMaterialIndex") node_add_menu.add_node_type(layout, "GeometryNodeMaterialSelection") diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 3039334b8f8..f15b8d95225 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1575,6 +1575,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define GEO_NODE_SDF_VOLUME_SPHERE 1196 #define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197 #define GEO_NODE_OFFSET_SDF_VOLUME 1198 +#define GEO_NODE_SAMPLE_MATERIAL 1199 /** \} */ diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index bbd44be2f61..5968c5b0e61 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -397,6 +397,7 @@ DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, 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_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements") +DefNode(GeometryNode, GEO_NODE_SAMPLE_MATERIAL, 0, "SAMPLE_MATERIAL", SampleMaterial, "Sample Material", "") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "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, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position") DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, def_geo_sample_uv_surface, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 99990f9cfad..f5cabeb4c48 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -148,6 +148,7 @@ set(SRC nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_sample_index.cc + nodes/node_geo_sample_material.cc nodes/node_geo_sample_nearest.cc nodes/node_geo_sample_nearest_surface.cc nodes/node_geo_sample_uv_surface.cc diff --git a/source/blender/nodes/geometry/node_geometry_register.cc b/source/blender/nodes/geometry/node_geometry_register.cc index 4df52203529..a867ae87dcb 100644 --- a/source/blender/nodes/geometry/node_geometry_register.cc +++ b/source/blender/nodes/geometry/node_geometry_register.cc @@ -132,6 +132,7 @@ void register_geometry_nodes() register_node_type_geo_remove_attribute(); register_node_type_geo_rotate_instances(); register_node_type_geo_sample_index(); + register_node_type_geo_sample_material(); register_node_type_geo_sample_nearest_surface(); register_node_type_geo_sample_nearest(); register_node_type_geo_sample_uv_surface(); diff --git a/source/blender/nodes/geometry/node_geometry_register.hh b/source/blender/nodes/geometry/node_geometry_register.hh index 003515f9d63..d7f1fb09591 100644 --- a/source/blender/nodes/geometry/node_geometry_register.hh +++ b/source/blender/nodes/geometry/node_geometry_register.hh @@ -129,6 +129,7 @@ void register_node_type_geo_realize_instances(); void register_node_type_geo_remove_attribute(); void register_node_type_geo_rotate_instances(); void register_node_type_geo_sample_index(); +void register_node_type_geo_sample_material(); void register_node_type_geo_sample_nearest_surface(); void register_node_type_geo_sample_nearest(); void register_node_type_geo_sample_uv_surface(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc new file mode 100644 index 00000000000..944e8e26ab5 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "DEG_depsgraph_query.h" + +#include "BLI_task.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_curves.hh" +#include "BKE_mesh.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_sample_material_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input(N_("Geometry")); + b.add_input(N_("Material Source")); + b.add_input(N_("Selection")).default_value(true).hide_value().field_on({0}); + b.add_input(N_("Material Index")).default_value(1).field_on({0}); + /* TODO: It's possible to avoid propagation from second geometry input? Or i miss something? */ + b.add_output(N_("Geometry")).propagate_all(); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry = params.extract_input("Geometry"); + Field selection_field = params.extract_input>("Selection"); + Field index_field = params.extract_input>("Material Index"); + + geometry.modify_geometry_sets([&](GeometrySet &geometry_set) { + const MeshComponent *component = geometry_set.get_component_for_read(); + Mesh *mesh = geometry_set.get_mesh_for_write(); + if (!mesh) { + return; + } + + bke::GeometryFieldContext field_context{*component, ATTR_DOMAIN_FACE}; + fn::FieldEvaluator evaluator{field_context, mesh->totpoly}; + evaluator.set_selection(selection_field); + evaluator.add(index_field); + evaluator.evaluate(); + + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); + if (selection.is_empty()) { + return; + } + + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + SpanAttributeWriter dst_indices_attribute = attributes.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); + MutableSpan dst_indices = dst_indices_attribute.span; + + const VArray &indices = evaluator.get_evaluated(0); + + indices.materialize(selection, dst_indices); + + dst_indices_attribute.finish(); + }); + + params.set_output("Geometry", std::move(geometry)); +} + +} // namespace blender::nodes::node_geo_sample_material_cc + +void register_node_type_geo_sample_material() +{ + namespace file_ns = blender::nodes::node_geo_sample_material_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_SAMPLE_MATERIAL, "Sample Material", NODE_CLASS_GEOMETRY); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} -- 2.30.2 From 415007da136ba5d8ddd50ca2ebeb9023f8f4839d Mon Sep 17 00:00:00 2001 From: illua1 Date: Fri, 7 Apr 2023 16:31:38 +0300 Subject: [PATCH 2/4] progress --- source/blender/blenlib/BLI_vector.hh | 9 ++++ .../nodes/node_geo_sample_material.cc | 54 ++++++++++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 0d04a77999f..d8161860729 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -486,6 +486,15 @@ class Vector { } } + int append_non_duplicates_and_get_index(const T &value) + { + const int index = this->first_index_of_try(value); + if (index == -1) { + return this->append_and_get_index(value); + } + return index; + } + /** * Append the value and assume that vector has enough memory reserved. This invokes undefined * behavior when not enough capacity has been reserved beforehand. Only use this in performance diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc index 944e8e26ab5..2588106b7ac 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc @@ -7,6 +7,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_attribute.hh" #include "BKE_curves.hh" #include "BKE_mesh.hh" @@ -27,9 +28,22 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input("Geometry"); + GeometrySet source_geometry = params.extract_input("Material Source"); Field selection_field = params.extract_input>("Selection"); Field index_field = params.extract_input>("Material Index"); + const Mesh *source_mesh = source_geometry.get_mesh_for_read(); + + if (source_mesh == nullptr) { + params.set_output("Geometry", std::move(geometry)); + return; + } + + if (source_mesh->totcol == 0) { + params.set_output("Geometry", std::move(geometry)); + return; + } + geometry.modify_geometry_sets([&](GeometrySet &geometry_set) { const MeshComponent *component = geometry_set.get_component_for_read(); Mesh *mesh = geometry_set.get_mesh_for_write(); @@ -47,16 +61,44 @@ static void node_geo_exec(GeoNodeExecParams params) if (selection.is_empty()) { return; } - + + const Span original_materials(mesh->mat, mesh->totcol); + + Vector materials = original_materials; + + const auto append_material = [source_mesh, &materials](const int index) -> int { + if (index < 0 || source_mesh->totcol < index) { + return 0; + } + Material *material = source_mesh->mat[index]; + return materials.append_non_duplicates_and_get_index(material); + }; + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); - SpanAttributeWriter dst_indices_attribute = attributes.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); + SpanAttributeWriter dst_indices_attribute = + attributes.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); MutableSpan dst_indices = dst_indices_attribute.span; - + const VArray &indices = evaluator.get_evaluated(0); - - indices.materialize(selection, dst_indices); - + devirtualize_varray(indices, [&](auto indices) { + selection.foreach_index( + [&](const int index) { dst_indices[index] = append_material(indices[index]); }); + }); dst_indices_attribute.finish(); + + const int result_tot_material = materials.size(); + const Span new_materials = materials.as_span().drop_front(mesh->totcol); + + if (new_materials.is_empty()) { + return; + } + + Array old_src_material = original_materials; + mesh->mat = static_cast( + MEM_recallocN_id(mesh->mat, sizeof(void *) * result_tot_material, "matarray")); + MutableSpan r_materials(mesh->mat, result_tot_material); + r_materials.drop_front(mesh->totcol).copy_from(new_materials); + mesh->totcol = result_tot_material; }); params.set_output("Geometry", std::move(geometry)); -- 2.30.2 From 4bf870957af32b6b1c0171f75ffbda0bb1f8ceef Mon Sep 17 00:00:00 2001 From: illua1 Date: Fri, 7 Apr 2023 16:56:03 +0300 Subject: [PATCH 3/4] progress --- .../startup/bl_ui/node_add_menu_geometry.py | 2 +- source/blender/blenkernel/BKE_node.h | 2 +- source/blender/nodes/NOD_static_types.h | 2 +- source/blender/nodes/geometry/CMakeLists.txt | 2 +- .../nodes/geometry/node_geometry_register.cc | 2 +- .../nodes/geometry/node_geometry_register.hh | 2 +- ...aterial.cc => node_geo_sample_materials.cc} | 18 ++++++++---------- 7 files changed, 14 insertions(+), 16 deletions(-) rename source/blender/nodes/geometry/nodes/{node_geo_sample_material.cc => node_geo_sample_materials.cc} (87%) diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index 71f1ddf6968..1c705aa570f 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -307,7 +307,7 @@ class NODE_MT_geometry_node_GEO_MATERIAL(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeReplaceMaterial") - node_add_menu.add_node_type(layout, "GeometryNodeSampleMaterial") + node_add_menu.add_node_type(layout, "GeometryNodeSampleMaterials") layout.separator() node_add_menu.add_node_type(layout, "GeometryNodeInputMaterialIndex") node_add_menu.add_node_type(layout, "GeometryNodeMaterialSelection") diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f15b8d95225..9ed8744d4e4 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1575,7 +1575,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define GEO_NODE_SDF_VOLUME_SPHERE 1196 #define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197 #define GEO_NODE_OFFSET_SDF_VOLUME 1198 -#define GEO_NODE_SAMPLE_MATERIAL 1199 +#define GEO_NODE_SAMPLE_MATERIALS 1199 /** \} */ diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 5968c5b0e61..a8538b11ae9 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -397,7 +397,7 @@ DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, 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_INDEX, def_geo_sample_index, "SAMPLE_INDEX", SampleIndex, "Sample Index", "Retrieve values from specific geometry elements") -DefNode(GeometryNode, GEO_NODE_SAMPLE_MATERIAL, 0, "SAMPLE_MATERIAL", SampleMaterial, "Sample Material", "") +DefNode(GeometryNode, GEO_NODE_SAMPLE_MATERIALS, 0, "SAMPLE_MATERIALS", SampleMaterials, "Sample Materials", "") DefNode(GeometryNode, GEO_NODE_SAMPLE_NEAREST_SURFACE, def_geo_sample_nearest_surface, "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, def_geo_sample_nearest, "SAMPLE_NEAREST", SampleNearest, "Sample Nearest", "Find the element of a geometry closest to a position") DefNode(GeometryNode, GEO_NODE_SAMPLE_UV_SURFACE, def_geo_sample_uv_surface, "SAMPLE_UV_SURFACE", SampleUVSurface, "Sample UV Surface", "Calculate the interpolated values of a mesh attribute at a UV coordinate") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index f5cabeb4c48..f0e60e54419 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -148,7 +148,7 @@ set(SRC nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_sample_index.cc - nodes/node_geo_sample_material.cc + nodes/node_geo_sample_materials.cc nodes/node_geo_sample_nearest.cc nodes/node_geo_sample_nearest_surface.cc nodes/node_geo_sample_uv_surface.cc diff --git a/source/blender/nodes/geometry/node_geometry_register.cc b/source/blender/nodes/geometry/node_geometry_register.cc index a867ae87dcb..d0c6be963ee 100644 --- a/source/blender/nodes/geometry/node_geometry_register.cc +++ b/source/blender/nodes/geometry/node_geometry_register.cc @@ -132,7 +132,7 @@ void register_geometry_nodes() register_node_type_geo_remove_attribute(); register_node_type_geo_rotate_instances(); register_node_type_geo_sample_index(); - register_node_type_geo_sample_material(); + register_node_type_geo_sample_materials(); register_node_type_geo_sample_nearest_surface(); register_node_type_geo_sample_nearest(); register_node_type_geo_sample_uv_surface(); diff --git a/source/blender/nodes/geometry/node_geometry_register.hh b/source/blender/nodes/geometry/node_geometry_register.hh index d7f1fb09591..a55eed36086 100644 --- a/source/blender/nodes/geometry/node_geometry_register.hh +++ b/source/blender/nodes/geometry/node_geometry_register.hh @@ -129,7 +129,7 @@ void register_node_type_geo_realize_instances(); void register_node_type_geo_remove_attribute(); void register_node_type_geo_rotate_instances(); void register_node_type_geo_sample_index(); -void register_node_type_geo_sample_material(); +void register_node_type_geo_sample_materials(); void register_node_type_geo_sample_nearest_surface(); void register_node_type_geo_sample_nearest(); void register_node_type_geo_sample_uv_surface(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc similarity index 87% rename from source/blender/nodes/geometry/nodes/node_geo_sample_material.cc rename to source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc index 2588106b7ac..49d44f6c532 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc @@ -13,14 +13,14 @@ #include "node_geometry_util.hh" -namespace blender::nodes::node_geo_sample_material_cc { +namespace blender::nodes::node_geo_sample_materials_cc { static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Geometry")); b.add_input(N_("Material Source")); b.add_input(N_("Selection")).default_value(true).hide_value().field_on({0}); - b.add_input(N_("Material Index")).default_value(1).field_on({0}); + b.add_input(N_("Material Index")).field_on({0}); /* TODO: It's possible to avoid propagation from second geometry input? Or i miss something? */ b.add_output(N_("Geometry")).propagate_all(); } @@ -67,10 +67,8 @@ static void node_geo_exec(GeoNodeExecParams params) Vector materials = original_materials; const auto append_material = [source_mesh, &materials](const int index) -> int { - if (index < 0 || source_mesh->totcol < index) { - return 0; - } - Material *material = source_mesh->mat[index]; + const int limited_index = math::clamp(index, 0, source_mesh->totcol - 1); + Material *material = source_mesh->mat[limited_index]; return materials.append_non_duplicates_and_get_index(material); }; @@ -104,15 +102,15 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry)); } -} // namespace blender::nodes::node_geo_sample_material_cc +} // namespace blender::nodes::node_geo_sample_materials_cc -void register_node_type_geo_sample_material() +void register_node_type_geo_sample_materials() { - namespace file_ns = blender::nodes::node_geo_sample_material_cc; + namespace file_ns = blender::nodes::node_geo_sample_materials_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SAMPLE_MATERIAL, "Sample Material", NODE_CLASS_GEOMETRY); + geo_node_type_base(&ntype, GEO_NODE_SAMPLE_MATERIALS, "Sample Materials", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); -- 2.30.2 From 0be5a4eda73afede829617875c6e93aa356fa262 Mon Sep 17 00:00:00 2001 From: illua1 Date: Fri, 7 Apr 2023 17:08:44 +0300 Subject: [PATCH 4/4] progress --- .../nodes/geometry/nodes/node_geo_sample_materials.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc index 49d44f6c532..67a844511e6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_materials.cc @@ -1,15 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "DEG_depsgraph_query.h" - -#include "BLI_task.hh" - #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "BKE_attribute.hh" -#include "BKE_curves.hh" -#include "BKE_mesh.hh" #include "node_geometry_util.hh" -- 2.30.2