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>2021-09-17 04:49:10 +0300
committerHans Goudey <h.goudey@me.com>2021-09-17 04:49:10 +0300
commit8e21d528cab98447fd072718a649906551de78d9 (patch)
tree930d9144bd0c810593243954cb156b0d82e09cc9 /source/blender/modifiers
parent4fa0bbb5ac3db31cd0ce6f765ee9eb93566f1e53 (diff)
Geometry Nodes: Add a toggle to use attributes as input values
This adds a toggle to node group inputs exposed in the modifier to use an attribute instead of a single value. When the toggle is pressed, the button switches to a text button to choose an attribute name. Attribute search isn't implemented here yet. One confusing thing is that some values can't be driven by attributes at all, like the size of a primitive node. In that case, we should have a node warning, but that will be separate since it's more general. We can also have an option to turn off this toggle in node group input settings. The two new properties for each input are stored with the same name as the value, but with `"_use_attribute"` and `"_attribute_name"`` suffixes. The properties are not added for socket types that don't support attribute input, like object sockets. Differential Revision: https://developer.blender.org/D12504
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc106
1 files changed, 99 insertions, 7 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 3b952e1e649..011890f4d43 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -68,6 +68,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "WM_types.h"
+
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -291,6 +293,17 @@ static bool logging_enabled(const ModifierEvalContext *ctx)
return true;
}
+static const std::string use_attribute_suffix = "_use_attribute";
+static const std::string attribute_name_suffix = "_attribute_name";
+
+/**
+ * \return Whether using an attribute to input values of this type is supported.
+ */
+static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
+{
+ return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
+}
+
static IDProperty *id_property_create_from_socket(const bNodeSocket &socket)
{
switch (socket.type) {
@@ -546,6 +559,32 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
new_prop->ui_data = ui_data;
}
}
+
+ if (socket_type_has_attribute_toggle(*socket)) {
+ const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
+ const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
+
+ IDPropertyTemplate idprop = {0};
+ IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str());
+ IDP_AddToGroup(nmd->settings.properties, use_attribute_prop);
+
+ IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
+ IDP_AddToGroup(nmd->settings.properties, attribute_prop);
+
+ if (old_properties != nullptr) {
+ IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
+ use_attribute_id.c_str());
+ if (old_prop_use_attribute != nullptr) {
+ IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute);
+ }
+
+ IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties,
+ attribute_name_id.c_str());
+ if (old_attribute_name_prop != nullptr) {
+ IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop);
+ }
+ }
+ }
}
if (old_properties != nullptr) {
@@ -601,8 +640,31 @@ static void initialize_group_input(NodesModifierData &nmd,
return;
}
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ if (!socket_type_has_attribute_toggle(socket)) {
+ init_socket_cpp_value_from_property(
+ *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ }
+
+ const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
+ nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str());
+ const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
+ nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str());
+ if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
+ socket.typeinfo->get_geometry_nodes_cpp_value(socket, r_value);
+ return;
+ }
+
+ const bool use_attribute = IDP_Int(property_use_attribute) != 0;
+ if (use_attribute) {
+ const StringRef attribute_name{IDP_String(property_attribute_name)};
+ auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
+ attribute_name, *socket.typeinfo->get_base_cpp_type());
+ new (r_value) blender::fn::GField(std::move(attribute_input), 0);
+ }
+ else {
+ init_socket_cpp_value_from_property(
+ *property, static_cast<eNodeSocketDatatype>(socket.type), r_value);
+ }
}
static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
@@ -912,13 +974,13 @@ static void modifyGeometrySet(ModifierData *md,
* the node socket identifier for the property names, since they are unique, but also having
* the correct label displayed in the UI. */
static void draw_property_for_socket(uiLayout *layout,
+ NodesModifierData *nmd,
PointerRNA *bmain_ptr,
PointerRNA *md_ptr,
- const IDProperty *modifier_props,
const bNodeSocket &socket)
{
/* The property should be created in #MOD_nodes_update_interface with the correct type. */
- IDProperty *property = IDP_GetPropertyFromGroup(modifier_props, socket.identifier);
+ IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier);
/* IDProperties can be removed with python, so there could be a situation where
* there isn't a property for a socket or it doesn't have the correct type. */
@@ -959,8 +1021,38 @@ static void draw_property_for_socket(uiLayout *layout,
uiItemPointerR(layout, md_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
break;
}
- default:
- uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ default: {
+ if (socket_type_has_attribute_toggle(socket) &&
+ USER_EXPERIMENTAL_TEST(&U, use_geometry_nodes_fields)) {
+ const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
+ use_attribute_suffix + "\"]";
+ const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
+ attribute_name_suffix + "\"]";
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
+ if (use_attribute) {
+ uiItemR(row, md_ptr, rna_path_attribute_name.c_str(), 0, socket.name, ICON_NONE);
+ }
+ else {
+ uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ }
+ PointerRNA props;
+ uiItemFullO(row,
+ "object.geometry_nodes_input_attribute_toggle",
+ "",
+ ICON_SPREADSHEET,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "modifier_name", nmd->modifier.name);
+ RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
+ }
+ else {
+ uiItemR(layout, md_ptr, rna_path, 0, socket.name, ICON_NONE);
+ }
+ }
}
}
@@ -991,7 +1083,7 @@ static void panel_draw(const bContext *C, Panel *panel)
RNA_main_pointer_create(bmain, &bmain_ptr);
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
- draw_property_for_socket(layout, &bmain_ptr, ptr, nmd->settings.properties, *socket);
+ draw_property_for_socket(layout, nmd, &bmain_ptr, ptr, *socket);
}
}