[Bf-blender-cvs] [8e21d528cab] master: Geometry Nodes: Add a toggle to use attributes as input values

Hans Goudey noreply at git.blender.org
Fri Sep 17 03:50:59 CEST 2021


Commit: 8e21d528cab98447fd072718a649906551de78d9
Author: Hans Goudey
Date:   Thu Sep 16 20:49:10 2021 -0500
Branches: master
https://developer.blender.org/rB8e21d528cab98447fd072718a649906551de78d9

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

===================================================================

M	source/blender/blenkernel/intern/attribute_access.cc
M	source/blender/editors/object/object_intern.h
M	source/blender/editors/object/object_modifier.c
M	source/blender/editors/object/object_ops.c
M	source/blender/modifiers/intern/MOD_nodes.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index ee0477faefe..8c4f87be91f 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -1321,7 +1321,9 @@ const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContex
     const AttributeDomain domain = geometry_context->domain();
     const CustomDataType data_type = cpp_type_to_custom_data_type(*type_);
     GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type);
-    return scope.add(std::move(attribute));
+    if (attribute) {
+      return scope.add(std::move(attribute));
+    }
   }
   return nullptr;
 }
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index b2d3216b101..50dd9322c5c 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -191,6 +191,7 @@ void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot);
 void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot);
 void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot);
 void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot);
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(struct wmOperatorType *ot);
 
 /* object_gpencil_modifiers.c */
 void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 2a1a6696493..b9942bc563a 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -3242,3 +3242,54 @@ void OBJECT_OT_surfacedeform_bind(wmOperatorType *ot)
 }
 
 /** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Toggle Value or Attribute Operator
+ *
+ * \note This operator basically only exists to provide a better tooltip for the toggle button,
+ * since it is stored as an IDProperty. It also stops the button from being highlighted when
+ * "use_attribute" is on, which isn't expected.
+ * \{ */
+
+static int geometry_nodes_input_attribute_toggle_exec(bContext *C, wmOperator *op)
+{
+  Object *ob = ED_object_active_context(C);
+
+  char modifier_name[MAX_NAME];
+  RNA_string_get(op->ptr, "modifier_name", modifier_name);
+  NodesModifierData *nmd = (NodesModifierData *)BKE_modifiers_findby_name(ob, modifier_name);
+  if (nmd == NULL) {
+    return OPERATOR_CANCELLED;
+  }
+
+  char prop_path[MAX_NAME];
+  RNA_string_get(op->ptr, "prop_path", prop_path);
+
+  PointerRNA mod_ptr;
+  RNA_pointer_create(&ob->id, &RNA_Modifier, nmd, &mod_ptr);
+
+  const int old_value = RNA_int_get(&mod_ptr, prop_path);
+  const int new_value = !old_value;
+  RNA_int_set(&mod_ptr, prop_path, new_value);
+
+  DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+  WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+  return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_geometry_nodes_input_attribute_toggle(wmOperatorType *ot)
+{
+  ot->name = "Input Attribute Toggle";
+  ot->description =
+      "Switch between an attribute and a single value to define the data for every element";
+  ot->idname = "OBJECT_OT_geometry_nodes_input_attribute_toggle";
+
+  ot->exec = geometry_nodes_input_attribute_toggle_exec;
+
+  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+  RNA_def_string(ot->srna, "prop_path", NULL, 0, "Prop Path", "");
+  RNA_def_string(ot->srna, "modifier_name", NULL, MAX_NAME, "Modifier Name", "");
+}
+
+/** \} */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 4b8431be530..aa9ae082317 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -145,6 +145,7 @@ void ED_operatortypes_object(void)
   WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear);
   WM_operatortype_append(OBJECT_OT_skin_radii_equalize);
   WM_operatortype_append(OBJECT_OT_skin_armature_create);
+  WM_operatortype_append(OBJECT_OT_geometry_nodes_input_attribute_toggle);
 
   /* grease pencil modifiers */
   WM_operatortype_append(OBJECT_OT_gpencil_modifier_add);
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) {
+       

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list