diff options
author | Hans Goudey <h.goudey@me.com> | 2022-03-14 19:48:11 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-03-14 19:48:11 +0300 |
commit | d4e46c13cc92e01489a031a6afe6bafb5af5ca18 (patch) | |
tree | 5c6294d006044d4100500f9e92bce8fea36c8841 /source/blender/nodes | |
parent | a5578351c38e2b2bb45d940a2fc57354e5fe3a5e (diff) |
Geometry Nodes: Add named attribute nodes behind experimental flag
This commit adds three nodes:
- `Remove Attribute`: Removes an attribute with the given name
- `Named Attribute`: A field input node
- `Store Named Attribute`: Puts results of a field in a named attribute
They are added behind a new experimental feature flag, because further
development of attribute search and name dependency visualization will
happen as separate steps.
Ref T91742
Differential Revision: https://developer.blender.org/D12685
Diffstat (limited to 'source/blender/nodes')
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 5 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 5 | ||||
-rw-r--r-- | source/blender/nodes/geometry/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc) | 11 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc | 131 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc | 87 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc | 188 |
7 files changed, 424 insertions, 8 deletions
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 8aea54f8ac5..be21dd4b88f 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -49,7 +49,7 @@ void register_node_type_geo_attribute_fill(void); void register_node_type_geo_attribute_map_range(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_attribute_mix(void); -void register_node_type_geo_attribute_remove(void); +void register_node_type_geo_legacy_attribute_remove(void); void register_node_type_geo_attribute_separate_xyz(void); void register_node_type_geo_attribute_statistic(void); void register_node_type_geo_attribute_vector_math(void); @@ -91,6 +91,7 @@ void register_node_type_geo_field_at_index(void); void register_node_type_geo_flip_faces(void); void register_node_type_geo_geometry_to_instance(void); void register_node_type_geo_image_texture(void); +void register_node_type_geo_input_named_attribute(void); void register_node_type_geo_input_curve_handles(void); void register_node_type_geo_input_curve_tilt(void); void register_node_type_geo_input_id(void); @@ -144,6 +145,7 @@ void register_node_type_geo_points_to_volume(void); void register_node_type_geo_proximity(void); void register_node_type_geo_raycast(void); void register_node_type_geo_realize_instances(void); +void register_node_type_geo_remove_attribute(void); void register_node_type_geo_rotate_instances(void); void register_node_type_geo_sample_texture(void); void register_node_type_geo_scale_elements(void); @@ -162,6 +164,7 @@ void register_node_type_geo_set_position(void); void register_node_type_geo_set_shade_smooth(void); void register_node_type_geo_set_spline_cyclic(void); void register_node_type_geo_set_spline_resolution(void); +void register_node_type_geo_store_named_attribute(void); void register_node_type_geo_string_join(void); void register_node_type_geo_string_to_curves(void); void register_node_type_geo_subdivision_surface(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 700c3a83b70..97a6b8a6e63 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -286,6 +286,7 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MATH, def_geo_attribute_math, "L DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MIX, def_geo_attribute_mix, "LEGACY_ATTRIBUTE_MIX", LegacyAttributeMix, "Attribute Mix", "") DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, def_geo_legacy_attribute_proximity, "LEGACY_ATTRIBUTE_PROXIMITY", LegacyAttributeProximity, "Attribute Proximity", "") DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "LEGACY_ATTRIBUTE_RANDOMIZE", LegacyAttributeRandomize, "Attribute Randomize", "") +DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, 0, "LEGACY_ATTRIBUTE_REMOVE", LegacyAttributeRemove, "Attribute Remove", "") DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE, 0, "LEGACY_ATTRIBUTE_SAMPLE_TEXTURE", LegacyAttributeSampleTexture, "Attribute Sample Texture", "") DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "LEGACY_ATTRIBUTE_SEPARATE_XYZ", LegacyAttributeSeparateXYZ, "Attribute Separate XYZ", "") DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "LEGACY_ATTRIBUTE_TRANSFER", LegacyAttributeTransfer, "Attribute Transfer", "") @@ -315,7 +316,6 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_s DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "") -DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "") DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "") DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "") @@ -349,6 +349,7 @@ DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE DefNode(GeometryNode, GEO_NODE_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "") DefNode(GeometryNode, GEO_NODE_GEOMETRY_TO_INSTANCE, 0, "GEOMETRY_TO_INSTANCE", GeometryToInstance, "Geometry to Instance", "") DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "") +DefNode(GeometryNode, GEO_NODE_INPUT_NAMED_ATTRIBUTE, def_geo_input_named_attribute, "INPUT_ATTRIBUTE", InputNamedAttribute, "Named Attribute", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", InputCurveHandlePositions, "Curve Handle Positions", "") DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_TILT, 0, "INPUT_CURVE_TILT", InputCurveTilt, "Curve Tilt", "") DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "") @@ -394,6 +395,7 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", Poin DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "") DefNode(GeometryNode, GEO_NODE_PROXIMITY, def_geo_proximity, "PROXIMITY", Proximity, "Geometry Proximity", "") DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "") +DefNode(GeometryNode, GEO_NODE_REMOVE_ATTRIBUTE, 0, "REMOVE_ATTRIBUTE", RemoveAttribute, "Remove Attribute", "") DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, def_geo_realize_instances, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "") DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "") DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE_CURVE", ResampleCurve, "Resample Curve", "") @@ -416,6 +418,7 @@ DefNode(GeometryNode, GEO_NODE_SET_SHADE_SMOOTH, 0, "SET_SHADE_SMOOTH", SetShade DefNode(GeometryNode, GEO_NODE_SET_SPLINE_CYCLIC, 0, "SET_SPLINE_CYCLIC", SetSplineCyclic, "Set Spline Cyclic", "") DefNode(GeometryNode, GEO_NODE_SET_SPLINE_RESOLUTION, 0, "SET_SPLINE_RESOLUTION", SetSplineResolution, "Set Spline Resolution", "") DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "") +DefNode(GeometryNode, GEO_NODE_STORE_NAMED_ATTRIBUTE, def_geo_store_named_attribute, "STORE_NAMED_ATTRIBUTE", StoreNamedAttribute, "Store Named Attribute", "") DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "Join Strings", "") DefNode(GeometryNode, GEO_NODE_STRING_TO_CURVES, def_geo_string_to_curves, "STRING_TO_CURVES", StringToCurves, "String to Curves", "") DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_CURVE, 0, "SUBDIVIDE_CURVE", SubdivideCurve, "Subdivide Curve", "") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index 4d39240fed4..0e99d8ad646 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -38,6 +38,7 @@ set(SRC nodes/legacy/node_geo_legacy_attribute_mix.cc nodes/legacy/node_geo_legacy_attribute_proximity.cc nodes/legacy/node_geo_legacy_attribute_randomize.cc + nodes/legacy/node_geo_legacy_attribute_remove.cc nodes/legacy/node_geo_legacy_attribute_sample_texture.cc nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -69,7 +70,6 @@ set(SRC nodes/node_geo_accumulate_field.cc nodes/node_geo_attribute_capture.cc nodes/node_geo_attribute_domain_size.cc - nodes/node_geo_attribute_remove.cc nodes/node_geo_attribute_statistic.cc nodes/node_geo_boolean.cc nodes/node_geo_bounding_box.cc @@ -123,6 +123,7 @@ set(SRC nodes/node_geo_input_mesh_face_neighbors.cc nodes/node_geo_input_mesh_island.cc nodes/node_geo_input_mesh_vertex_neighbors.cc + nodes/node_geo_input_named_attribute.cc nodes/node_geo_input_normal.cc nodes/node_geo_input_position.cc nodes/node_geo_input_radius.cc @@ -156,6 +157,7 @@ set(SRC nodes/node_geo_proximity.cc nodes/node_geo_raycast.cc nodes/node_geo_realize_instances.cc + nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_scale_elements.cc nodes/node_geo_scale_instances.cc @@ -172,6 +174,7 @@ set(SRC nodes/node_geo_set_shade_smooth.cc nodes/node_geo_set_spline_cyclic.cc nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_store_named_attribute.cc nodes/node_geo_string_join.cc nodes/node_geo_string_to_curves.cc nodes/node_geo_subdivision_surface.cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc index cb7132d5ea2..cc7118fd305 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc @@ -2,7 +2,7 @@ #include "node_geometry_util.hh" -namespace blender::nodes::node_geo_attribute_remove_cc { +namespace blender::nodes::node_geo_legacy_attribute_remove_cc { static void node_declare(NodeDeclarationBuilder &b) { @@ -45,15 +45,16 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes::node_geo_attribute_remove_cc +} // namespace blender::nodes::node_geo_legacy_attribute_remove_cc -void register_node_type_geo_attribute_remove() +void register_node_type_geo_legacy_attribute_remove() { - namespace file_ns = blender::nodes::node_geo_attribute_remove_cc; + namespace file_ns = blender::nodes::node_geo_legacy_attribute_remove_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE); + geo_node_type_base( + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc new file mode 100644 index 00000000000..f6e2be9119c --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "NOD_socket_search_link.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_named_attribute_cc { + +NODE_STORAGE_FUNCS(NodeGeometryInputNamedAttribute) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::String>(N_("Name")).is_attribute_name(); + + b.add_output<decl::Vector>(N_("Attribute"), "Attribute_Vector").field_source(); + b.add_output<decl::Float>(N_("Attribute"), "Attribute_Float").field_source(); + b.add_output<decl::Color>(N_("Attribute"), "Attribute_Color").field_source(); + b.add_output<decl::Bool>(N_("Attribute"), "Attribute_Bool").field_source(); + b.add_output<decl::Int>(N_("Attribute"), "Attribute_Int").field_source(); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryInputNamedAttribute *data = MEM_cnew<NodeGeometryInputNamedAttribute>(__func__); + data->data_type = CD_PROP_FLOAT; + node->storage = data; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + const NodeGeometryInputNamedAttribute &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + + bNodeSocket *socket_vector = (bNodeSocket *)node->outputs.first; + bNodeSocket *socket_float = socket_vector->next; + bNodeSocket *socket_color4f = socket_float->next; + bNodeSocket *socket_boolean = socket_color4f->next; + bNodeSocket *socket_int32 = socket_boolean->next; + + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + if (U.experimental.use_named_attribute_nodes == 0) { + return; + } + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs()); + + if (params.in_out() == SOCK_OUT) { + const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + static_cast<eNodeSocketDatatype>(params.other_socket().type)); + if (type && *type != CD_PROP_STRING) { + /* The input and output sockets have the same name. */ + params.add_item(IFACE_("Attribute"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeInputNamedAttribute"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Attribute"); + }); + } + } +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + const NodeGeometryInputNamedAttribute &storage = node_storage(params.node()); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + + const std::string name = params.extract_input<std::string>("Name"); + + if (!U.experimental.use_named_attribute_nodes) { + params.set_default_remaining_outputs(); + return; + } + + switch (data_type) { + case CD_PROP_FLOAT: + params.set_output("Attribute_Float", AttributeFieldInput::Create<float>(std::move(name))); + break; + case CD_PROP_FLOAT3: + params.set_output("Attribute_Vector", AttributeFieldInput::Create<float3>(std::move(name))); + break; + case CD_PROP_COLOR: + params.set_output("Attribute_Color", + AttributeFieldInput::Create<ColorGeometry4f>(std::move(name))); + break; + case CD_PROP_BOOL: + params.set_output("Attribute_Bool", AttributeFieldInput::Create<bool>(std::move(name))); + break; + case CD_PROP_INT32: + params.set_output("Attribute_Int", AttributeFieldInput::Create<int>(std::move(name))); + break; + default: + break; + } +} + +} // namespace blender::nodes::node_geo_input_named_attribute_cc + +void register_node_type_geo_input_named_attribute() +{ + namespace file_ns = blender::nodes::node_geo_input_named_attribute_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_INPUT_NAMED_ATTRIBUTE, "Named Attribute", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + ntype.updatefunc = file_ns::node_update; + node_type_init(&ntype, file_ns::node_init); + node_type_storage(&ntype, + "NodeGeometryInputNamedAttribute", + node_free_standard_storage, + node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc new file mode 100644 index 00000000000..202241affeb --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_geometry_util.hh" + +#include "NOD_socket_search_link.hh" + +namespace blender::nodes::node_geo_remove_attribute_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::String>(N_("Name")).is_attribute_name(); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + if (U.experimental.use_named_attribute_nodes == 0) { + return; + } + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs()); + search_link_ops_for_declarations(params, declaration.outputs()); +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + const std::string name = params.extract_input<std::string>("Name"); + if (name.empty() || !U.experimental.use_named_attribute_nodes) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + std::atomic<bool> attribute_exists = false; + std::atomic<bool> cannot_delete = false; + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}) { + if (geometry_set.has(type)) { + /* First check if the attribute exists before getting write access, + * to avoid potentially expensive unnecessary copies. */ + const GeometryComponent &read_only_component = *geometry_set.get_component_for_read(type); + if (read_only_component.attribute_exists(name)) { + attribute_exists = true; + } + else { + continue; + } + + GeometryComponent &component = geometry_set.get_component_for_write(type); + if (!component.attribute_try_delete(name)) { + cannot_delete = true; + } + } + } + }); + + if (!attribute_exists) { + params.error_message_add(NodeWarningType::Info, + TIP_("Attribute does not exist: \"") + name + "\""); + } + if (cannot_delete) { + params.error_message_add(NodeWarningType::Info, + TIP_("Cannot delete attribute with name \"") + name + "\""); + } + + params.set_output("Geometry", std::move(geometry_set)); +} + +} // namespace blender::nodes::node_geo_remove_attribute_cc + +void register_node_type_geo_remove_attribute() +{ + namespace file_ns = blender::nodes::node_geo_remove_attribute_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_REMOVE_ATTRIBUTE, "Remove Attribute", NODE_CLASS_ATTRIBUTE); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc new file mode 100644 index 00000000000..5b0816fa3e3 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "NOD_socket_search_link.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_store_named_attribute_cc { + +NODE_STORAGE_FUNCS(NodeGeometryStoreNamedAttribute) + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::String>(N_("Name")).is_attribute_name(); + b.add_input<decl::Vector>(N_("Value"), "Value_Vector").supports_field(); + b.add_input<decl::Float>(N_("Value"), "Value_Float").supports_field(); + b.add_input<decl::Color>(N_("Value"), "Value_Color").supports_field(); + b.add_input<decl::Bool>(N_("Value"), "Value_Bool").supports_field(); + b.add_input<decl::Int>(N_("Value"), "Value_Int").supports_field(); + + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryStoreNamedAttribute *data = MEM_cnew<NodeGeometryStoreNamedAttribute>(__func__); + data->data_type = CD_PROP_FLOAT; + data->domain = ATTR_DOMAIN_POINT; + node->storage = data; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + const NodeGeometryStoreNamedAttribute &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + + bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first; + bNodeSocket *socket_name = socket_geometry->next; + bNodeSocket *socket_vector = socket_name->next; + bNodeSocket *socket_float = socket_vector->next; + bNodeSocket *socket_color4f = socket_float->next; + bNodeSocket *socket_boolean = socket_color4f->next; + bNodeSocket *socket_int32 = socket_boolean->next; + + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + if (U.experimental.use_named_attribute_nodes == 0) { + return; + } + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs().take_front(2)); + + if (params.in_out() == SOCK_OUT) { + const std::optional<CustomDataType> type = node_data_type_to_custom_data_type( + static_cast<eNodeSocketDatatype>(params.other_socket().type)); + if (type && *type != CD_PROP_STRING) { + /* The input and output sockets have the same name. */ + params.add_item(IFACE_("Value"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeStoreNamedAttribute"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + }); + } + } +} + +static void try_capture_field_on_geometry(GeometryComponent &component, + const StringRef name, + const AttributeDomain domain, + const GField &field) +{ + GeometryComponentFieldContext field_context{component, domain}; + const int domain_size = component.attribute_domain_size(domain); + const IndexMask mask{IndexMask(domain_size)}; + + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type()); + + /* Don't use #add_with_destination because the field might depend on an attribute + * with that name, and changing it as part of evaluation might affect the result. */ + fn::FieldEvaluator evaluator{field_context, &mask}; + evaluator.add(field); + evaluator.evaluate(); + const GVArray &result = evaluator.get_evaluated(0); + OutputAttribute attribute = component.attribute_try_get_for_output_only(name, domain, data_type); + if (attribute) { + result.materialize(attribute.as_span().data()); + attribute.save(); + } +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + std::string name = params.extract_input<std::string>("Name"); + + if (!U.experimental.use_named_attribute_nodes) { + params.set_output("Geometry", std::move(geometry_set)); + return; + } + + const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node()); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + + GField field; + switch (data_type) { + case CD_PROP_FLOAT: + field = params.get_input<Field<float>>("Value_Float"); + break; + case CD_PROP_FLOAT3: + field = params.get_input<Field<float3>>("Value_Vector"); + break; + case CD_PROP_COLOR: + field = params.get_input<Field<ColorGeometry4f>>("Value_Color"); + break; + case CD_PROP_BOOL: + field = params.get_input<Field<bool>>("Value_Bool"); + break; + case CD_PROP_INT32: + field = params.get_input<Field<int>>("Value_Int"); + break; + default: + break; + } + + /* Run on the instances component separately to only affect the top level of instances. */ + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry_set.has_instances()) { + GeometryComponent &component = geometry_set.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + try_capture_field_on_geometry(component, name, domain, field); + } + } + else { + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : + {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) { + if (geometry_set.has(type)) { + GeometryComponent &component = geometry_set.get_component_for_write(type); + try_capture_field_on_geometry(component, name, domain, field); + } + } + }); + } + + params.set_output("Geometry", std::move(geometry_set)); +} + +} // namespace blender::nodes::node_geo_store_named_attribute_cc + +void register_node_type_geo_store_named_attribute() +{ + namespace file_ns = blender::nodes::node_geo_store_named_attribute_cc; + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_STORE_NAMED_ATTRIBUTE, "Store Named Attribute", NODE_CLASS_ATTRIBUTE); + node_type_storage(&ntype, + "NodeGeometryStoreNamedAttribute", + node_free_standard_storage, + node_copy_standard_storage); + node_type_size(&ntype, 140, 100, 700); + node_type_init(&ntype, file_ns::node_init); + ntype.updatefunc = file_ns::node_update; + ntype.declare = file_ns::node_declare; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + nodeRegisterType(&ntype); +} |