Geometry Nodes: Add "Exists" output to Named Attribute input node

As described in T100004, add an output socket that returns true if the
attribute accessed by the node was already present in that context.

Initial patch by Edward (@edward88).

Differential Revision: https://developer.blender.org/D16316
This commit is contained in:
Hans Goudey
2022-11-16 17:27:28 -06:00
parent 145839aa42
commit 0d3a33e45e
2 changed files with 50 additions and 11 deletions

View File

@@ -197,10 +197,14 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
/* Relink all node links to the newly active output socket. */
bNodeSocket *output_socket = bke::node_find_enabled_output_socket(*node, "Attribute");
LISTBASE_FOREACH (bNodeLink *, link, &node_tree->links) {
if (link->fromnode == node) {
link->fromsock = output_socket;
BKE_ntree_update_tag_link_changed(node_tree);
if (link->fromnode != node) {
continue;
}
if (!STREQ(link->fromsock->name, "Attribute")) {
continue;
}
link->fromsock = output_socket;
BKE_ntree_update_tag_link_changed(node_tree);
}
}
BKE_ntree_update_tag_node_property(node_tree, node);

View File

@@ -20,6 +20,8 @@ static void node_declare(NodeDeclarationBuilder &b)
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();
b.add_output<decl::Bool>(N_("Exists")).field_source();
}
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
@@ -57,20 +59,52 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
search_link_ops_for_declarations(params, declaration.inputs());
const bNodeType &node_type = params.node_type();
if (params.in_out() == SOCK_OUT) {
const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
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");
params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
bNode &node = params.add_node(node_type);
node_storage(node).data_type = *type;
params.update_and_connect_available_socket(node, "Attribute");
});
params.add_item(IFACE_("Exists"), [node_type](LinkSearchOpParams &params) {
bNode &node = params.add_node(node_type);
params.update_and_connect_available_socket(node, "Exists");
});
}
}
}
class AttributeExistsFieldInput final : public bke::GeometryFieldInput {
private:
std::string name_;
public:
AttributeExistsFieldInput(std::string name, const CPPType &type)
: GeometryFieldInput(type, name), name_(std::move(name))
{
category_ = Category::Generated;
}
static Field<bool> Create(std::string name)
{
const CPPType &type = CPPType::get<bool>();
auto field_input = std::make_shared<AttributeExistsFieldInput>(std::move(name), type);
return Field<bool>(field_input);
}
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
const IndexMask /*mask*/) const final
{
const bool exists = context.attributes()->contains(name_);
const int domain_size = context.attributes()->domain_size(context.domain());
return VArray<bool>::ForSingle(exists, domain_size);
}
};
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(params.node());
@@ -92,24 +126,25 @@ static void node_geo_exec(GeoNodeExecParams params)
switch (data_type) {
case CD_PROP_FLOAT:
params.set_output("Attribute_Float", AttributeFieldInput::Create<float>(std::move(name)));
params.set_output("Attribute_Float", AttributeFieldInput::Create<float>(name));
break;
case CD_PROP_FLOAT3:
params.set_output("Attribute_Vector", AttributeFieldInput::Create<float3>(std::move(name)));
params.set_output("Attribute_Vector", AttributeFieldInput::Create<float3>(name));
break;
case CD_PROP_COLOR:
params.set_output("Attribute_Color",
AttributeFieldInput::Create<ColorGeometry4f>(std::move(name)));
params.set_output("Attribute_Color", AttributeFieldInput::Create<ColorGeometry4f>(name));
break;
case CD_PROP_BOOL:
params.set_output("Attribute_Bool", AttributeFieldInput::Create<bool>(std::move(name)));
params.set_output("Attribute_Bool", AttributeFieldInput::Create<bool>(name));
break;
case CD_PROP_INT32:
params.set_output("Attribute_Int", AttributeFieldInput::Create<int>(std::move(name)));
params.set_output("Attribute_Int", AttributeFieldInput::Create<int>(name));
break;
default:
break;
}
params.set_output("Exists", AttributeExistsFieldInput::Create(std::move(name)));
}
} // namespace blender::nodes::node_geo_input_named_attribute_cc