Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-03-14 19:48:11 +0300
committerHans Goudey <h.goudey@me.com>2022-03-14 19:48:11 +0300
commitd4e46c13cc92e01489a031a6afe6bafb5af5ca18 (patch)
tree5c6294d006044d4100500f9e92bce8fea36c8841
parenta5578351c38e2b2bb45d940a2fc57354e5fe3a5e (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
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py1
-rw-r--r--release/scripts/startup/nodeitems_builtins.py8
-rw-r--r--source/blender/blenkernel/BKE_node.h5
-rw-r--r--source/blender/blenkernel/intern/node.cc5
-rw-r--r--source/blender/blenloader/intern/versioning_300.c13
-rw-r--r--source/blender/makesdna/DNA_node_types.h12
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c34
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c6
-rw-r--r--source/blender/nodes/NOD_geometry.h5
-rw-r--r--source/blender/nodes/NOD_static_types.h5
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt5
-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.cc131
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc87
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc188
16 files changed, 506 insertions, 13 deletions
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index f80ad378b3c..09716c77917 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -2262,6 +2262,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
+ ({"property": "use_named_attribute_nodes"}, ("T91742")),
),
)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index a0205a2bcb1..705b98c4d11 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -201,6 +201,8 @@ def geometry_input_node_items(context):
yield NodeItem("ShaderNodeValue")
yield NodeItem("FunctionNodeInputVector")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ if named_attribute_poll(context):
+ yield NodeItem("GeometryNodeInputNamedAttribute")
yield NodeItem("GeometryNodeInputID")
yield NodeItem("GeometryNodeInputIndex")
yield NodeItem("GeometryNodeInputNormal")
@@ -358,6 +360,10 @@ def geometry_nodes_legacy_poll(context):
return context.preferences.experimental.use_geometry_nodes_legacy
+def named_attribute_poll(context):
+ return context.preferences.experimental.use_named_attribute_nodes
+
+
# All standard node categories currently used in nodes.
shader_node_categories = [
@@ -683,6 +689,8 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeDomainSize"),
NodeItem("GeometryNodeAttributeStatistic"),
NodeItem("GeometryNodeAttributeTransfer"),
+ NodeItem("GeometryNodeStoreNamedAttribute", poll=named_attribute_poll),
+ NodeItem("GeometryNodeRemoveAttribute", poll=named_attribute_poll),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeMixRGB"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 4e664192019..904f06f2734 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1392,7 +1392,7 @@ struct TexResult;
#define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027
#define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028
#define GEO_NODE_SUBDIVIDE_MESH 1029
-#define GEO_NODE_ATTRIBUTE_REMOVE 1030
+#define GEO_NODE_LEGACY_ATTRIBUTE_REMOVE 1030
#define GEO_NODE_LEGACY_ATTRIBUTE_CONVERT 1031
#define GEO_NODE_MESH_PRIMITIVE_CUBE 1032
#define GEO_NODE_MESH_PRIMITIVE_CIRCLE 1033
@@ -1517,6 +1517,9 @@ struct TexResult;
#define GEO_NODE_MERGE_BY_DISTANCE 1153
#define GEO_NODE_DUPLICATE_ELEMENTS 1154
#define GEO_NODE_INPUT_MESH_FACE_IS_PLANAR 1155
+#define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156
+#define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157
+#define GEO_NODE_REMOVE_ATTRIBUTE 1158
/** \} */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 51a2545d7b9..9a573919165 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4694,6 +4694,7 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_attribute_proximity();
register_node_type_geo_legacy_attribute_randomize();
+ register_node_type_geo_legacy_attribute_remove();
register_node_type_geo_legacy_attribute_transfer();
register_node_type_geo_legacy_curve_endpoints();
register_node_type_geo_legacy_curve_reverse();
@@ -4726,7 +4727,6 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
register_node_type_geo_attribute_mix();
- register_node_type_geo_attribute_remove();
register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_statistic();
register_node_type_geo_attribute_vector_math();
@@ -4768,6 +4768,7 @@ static void registerGeometryNodes()
register_node_type_geo_flip_faces();
register_node_type_geo_geometry_to_instance();
register_node_type_geo_image_texture();
+ register_node_type_geo_input_named_attribute();
register_node_type_geo_input_curve_handles();
register_node_type_geo_input_curve_tilt();
register_node_type_geo_input_id();
@@ -4821,6 +4822,7 @@ static void registerGeometryNodes()
register_node_type_geo_proximity();
register_node_type_geo_raycast();
register_node_type_geo_realize_instances();
+ register_node_type_geo_remove_attribute();
register_node_type_geo_rotate_instances();
register_node_type_geo_sample_texture();
register_node_type_geo_scale_elements();
@@ -4838,6 +4840,7 @@ static void registerGeometryNodes()
register_node_type_geo_set_shade_smooth();
register_node_type_geo_set_spline_cyclic();
register_node_type_geo_set_spline_resolution();
+ register_node_type_geo_store_named_attribute();
register_node_type_geo_string_join();
register_node_type_geo_string_to_curves();
register_node_type_geo_subdivision_surface();
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 9afaad04066..eead735b305 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -527,7 +527,7 @@ static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
GEO_NODE_TRIM_CURVE,
GEO_NODE_REPLACE_MATERIAL,
GEO_NODE_SUBDIVIDE_MESH,
- GEO_NODE_ATTRIBUTE_REMOVE,
+ GEO_NODE_LEGACY_ATTRIBUTE_REMOVE,
GEO_NODE_TRIANGULATE)) {
bNodeSocket *geometry_socket = node->inputs.first;
add_realize_instances_before_socket(ntree, node, geometry_socket);
@@ -999,7 +999,7 @@ static bool geometry_node_is_293_legacy(const short node_type)
/* Maybe legacy: Might need special attribute handling, depending on design. */
case GEO_NODE_SWITCH:
case GEO_NODE_JOIN_GEOMETRY:
- case GEO_NODE_ATTRIBUTE_REMOVE:
+ case GEO_NODE_LEGACY_ATTRIBUTE_REMOVE:
case GEO_NODE_OBJECT_INFO:
case GEO_NODE_COLLECTION_INFO:
return false;
@@ -2637,5 +2637,14 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Deprecate the attribute remove node. It was hidden and is replaced by a version without a
+ * multi-input socket. */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_id(
+ ntree, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, "GeometryNodeLegacyAttributeRemove");
+ }
+ }
}
}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 18b79a6fc25..5bd44868741 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1592,6 +1592,18 @@ typedef struct NodeGeometryAttributeCapture {
int8_t domain;
} NodeGeometryAttributeCapture;
+typedef struct NodeGeometryStoreNamedAttribute {
+ /* CustomDataType. */
+ int8_t data_type;
+ /* AttributeDomain. */
+ int8_t domain;
+} NodeGeometryStoreNamedAttribute;
+
+typedef struct NodeGeometryInputNamedAttribute {
+ /* CustomDataType. */
+ int8_t data_type;
+} NodeGeometryInputNamedAttribute;
+
typedef struct NodeGeometryStringToCurves {
/* GeometryNodeStringToCurvesOverflowMode */
uint8_t overflow;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 80a107e4bae..5784d437048 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -650,7 +650,8 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
- char _pad[2];
+ char use_named_attribute_nodes;
+ char _pad[1];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index d1c37eff36f..f212b4a1d23 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -11281,6 +11281,40 @@ static void def_geo_curve_fill(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_store_named_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryStoreNamedAttribute", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "Which domain to store the data in");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_geo_input_named_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryInputNamedAttribute", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "The data type used to read the attribute values");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
static void def_geo_attribute_capture(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 3b9632342ec..78e6bfec03f 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -6441,6 +6441,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_geometry_nodes_legacy", 1);
RNA_def_property_ui_text(
prop, "Geometry Nodes Legacy", "Enable legacy geometry nodes in the menu");
+
+ prop = RNA_def_property(srna, "use_named_attribute_nodes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_named_attribute_nodes", 1);
+ RNA_def_property_ui_text(prop,
+ "Named Attribute Nodes",
+ "Enable named attribute nodes in the geometry nodes add menu");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
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 &params)
+{
+ 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 &params) {
+ 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 &params)
+{
+ 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 &params)
+{
+ 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 &params) {
+ 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);
+}