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
This commit is contained in:
parent
a5578351c3
commit
d4e46c13cc
Notes:
blender-bot
2023-02-13 17:35:32 +01:00
Referenced by issue #91742, Named Attribute Nodes
|
@ -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")),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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", "")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue