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:
@@ -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);
|
||||
|
||||
@@ -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 ¶ms)
|
||||
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 ¶ms) {
|
||||
bNode &node = params.add_node("GeometryNodeInputNamedAttribute");
|
||||
params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams ¶ms) {
|
||||
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 ¶ms) {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user