[Bf-blender-cvs] [f6888b530ac] master: Attributes: add operator to convert generic attributes to other types

Jacques Lucke noreply at git.blender.org
Fri Jan 21 12:47:43 CET 2022


Commit: f6888b530ac81abbe61755971449ad6b42b93c82
Author: Jacques Lucke
Date:   Fri Jan 21 12:47:35 2022 +0100
Branches: master
https://developer.blender.org/rBf6888b530ac81abbe61755971449ad6b42b93c82

Attributes: add operator to convert generic attributes to other types

Editing of generic attributes on the original objects in edit modes is
still very limited. However, when applying a geometry nodes modifier
that generates new attributes. These attributes will show up in the
Attributes panel.

Currently, our exporters are not capable of exporting generic attributes.
Therefore, for the time being, a work around is to apply geometry nodes
and then convert a generic attribute to a task specific attribute like a
uv map, vertex group or vertex color layer. Once more parts of Blender
support generic attributes, this will become less important.

Currently, only meshes are supported by the operator. However, it would
be relatively easy to extend it to other geometry types.

Differential Revision: https://developer.blender.org/D13838

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

M	release/scripts/startup/bl_ui/properties_data_mesh.py
M	source/blender/editors/geometry/CMakeLists.txt
M	source/blender/editors/geometry/geometry_attributes.cc
M	source/blender/editors/geometry/geometry_intern.hh
M	source/blender/editors/geometry/geometry_ops.cc
M	source/blender/makesrna/RNA_enum_types.h
M	source/blender/makesrna/intern/rna_attribute.c

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

diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 49f196640d8..11e2cd84903 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -82,6 +82,14 @@ class MESH_MT_shape_key_context_menu(Menu):
         layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
         layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
 
+class MESH_MT_attribute_context_menu(Menu):
+    bl_label = "Attribute Specials"
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.operator("geometry.attribute_convert")
+
 
 class MESH_UL_vgroups(UIList):
     def draw_item(self, _context, layout, _data, item, icon, _active_data_, _active_propname, _index):
@@ -615,6 +623,10 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
         col.operator("geometry.attribute_add", icon='ADD', text="")
         col.operator("geometry.attribute_remove", icon='REMOVE', text="")
 
+        col.separator()
+
+        col.menu("MESH_MT_attribute_context_menu", icon='DOWNARROW_HLT', text="")
+
         self.draw_attribute_warnings(context, layout)
 
     def draw_attribute_warnings(self, context, layout):
@@ -652,6 +664,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
 classes = (
     MESH_MT_vertex_group_context_menu,
     MESH_MT_shape_key_context_menu,
+    MESH_MT_attribute_context_menu,
     MESH_UL_vgroups,
     MESH_UL_fmaps,
     MESH_UL_shape_keys,
diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt
index 65b9633da98..8c920915937 100644
--- a/source/blender/editors/geometry/CMakeLists.txt
+++ b/source/blender/editors/geometry/CMakeLists.txt
@@ -20,9 +20,11 @@ set(INC
   ../../blenkernel
   ../../blenlib
   ../../depsgraph
+  ../../functions
   ../../makesdna
   ../../makesrna
   ../../windowmanager
+  ../../../../intern/guardedalloc
 )
 
 set(INC_SYS
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 9c0f6728701..56ecd108bba 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -21,8 +21,18 @@
  * \ingroup edgeometry
  */
 
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
 #include "BKE_attribute.h"
 #include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
@@ -33,10 +43,19 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "UI_interface.h"
+#include "UI_resources.h"
+
 #include "ED_object.h"
 
 #include "geometry_intern.hh"
 
+namespace blender::ed::geometry {
+
+using fn::CPPType;
+using fn::GArray;
+using fn::GVArray;
+
 /*********************** Attribute Operators ************************/
 
 static bool geometry_attributes_poll(bContext *C)
@@ -76,7 +95,7 @@ static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
     return DummyRNA_NULL_items;
   }
 
-  return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), r_free);
+  return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free);
 }
 
 static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
@@ -180,3 +199,187 @@ void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
   /* flags */
   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+enum class ConvertAttributeMode {
+  Generic,
+  UVMap,
+  VertexGroup,
+  VertexColor,
+};
+
+static bool geometry_attribute_convert_poll(bContext *C)
+{
+  if (!geometry_attributes_poll(C)) {
+    return false;
+  }
+
+  Object *ob = ED_object_context(C);
+  ID *data = static_cast<ID *>(ob->data);
+  if (GS(data->name) != ID_ME) {
+    return false;
+  }
+  CustomDataLayer *layer = BKE_id_attributes_active_get(data);
+  if (layer == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
+{
+  Object *ob = ED_object_context(C);
+  ID *ob_data = static_cast<ID *>(ob->data);
+  CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
+  const std::string name = layer->name;
+
+  const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+      RNA_enum_get(op->ptr, "mode"));
+
+  Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
+  MeshComponent mesh_component;
+  mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+
+  /* General conversion steps are always the same:
+   * 1. Convert old data to right domain and data type.
+   * 2. Copy the data into a new array so that it does not depend on the old attribute anymore.
+   * 3. Delete the old attribute.
+   * 4. Create a new attribute based on the previously copied data. */
+  switch (mode) {
+    case ConvertAttributeMode::Generic: {
+      const AttributeDomain dst_domain = static_cast<AttributeDomain>(
+          RNA_enum_get(op->ptr, "domain"));
+      const CustomDataType dst_type = static_cast<CustomDataType>(
+          RNA_enum_get(op->ptr, "data_type"));
+
+      if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) {
+        BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
+        return OPERATOR_CANCELLED;
+      }
+
+      GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+      const CPPType &cpp_type = src_varray.type();
+      void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
+      src_varray.materialize_to_uninitialized(new_data);
+      mesh_component.attribute_try_delete(name);
+      mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+      break;
+    }
+    case ConvertAttributeMode::UVMap: {
+      MLoopUV *dst_uvs = static_cast<MLoopUV *>(
+          MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
+      VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+          name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
+      for (const int i : IndexRange(mesh->totloop)) {
+        copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
+      }
+      mesh_component.attribute_try_delete(name);
+      CustomData_add_layer_named(
+          &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
+      break;
+    }
+    case ConvertAttributeMode::VertexColor: {
+      MLoopCol *dst_colors = static_cast<MLoopCol *>(
+          MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__));
+      VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>(
+          name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f});
+      for (const int i : IndexRange(mesh->totloop)) {
+        ColorGeometry4b encoded_color = src_varray[i].encode();
+        copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r);
+      }
+      mesh_component.attribute_try_delete(name);
+      CustomData_add_layer_named(
+          &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str());
+      break;
+    }
+    case ConvertAttributeMode::VertexGroup: {
+      Array<float> src_weights(mesh->totvert);
+      VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+          name, ATTR_DOMAIN_POINT, 0.0f);
+      src_varray.materialize(src_weights);
+      mesh_component.attribute_try_delete(name);
+
+      bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
+      const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
+      MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id);
+      for (const int i : IndexRange(mesh->totvert)) {
+        const float weight = src_weights[i];
+        if (weight > 0.0f) {
+          BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight);
+        }
+      }
+      break;
+    }
+  }
+
+  int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+  if (*active_index > 0) {
+    *active_index -= 1;
+  }
+
+  DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
+  WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
+
+  return OPERATOR_FINISHED;
+}
+
+static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
+{
+  uiLayout *layout = op->layout;
+
+  uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE);
+
+  const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+      RNA_enum_get(op->ptr, "mode"));
+
+  if (mode == ConvertAttributeMode::Generic) {
+    uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE);
+    uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE);
+  }
+}
+
+static int geometry_attribute_convert_invoke(bContext *C,
+                                             wmOperator *op,
+                                             const wmEvent *UNUSED(event))
+{
+  return WM_operator_props_dialog_popup(C, op, 300);
+}
+
+void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
+{
+  ot->name = "Convert Attribute";
+  ot->description = "Change how the attribute is stored";
+  ot->idname = "GEOMETRY_OT_attribute_convert";
+
+  ot->invoke = geometry_attribute_convert_invoke;
+  ot->exec = geometry_attribute_convert_exec;
+  ot->poll = geometry_attribute_convert_poll;
+  ot->ui = geometry_attribute_convert_ui;
+
+  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+  static EnumPropertyItem mode_items[] = {
+      {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
+      {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
+      {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
+      {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""},
+      {0, nullptr, 0, nullptr, nullptr},
+  };
+
+  PropertyRNA *prop;
+
+  RNA_def_enum(
+      ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", "");
+
+  prop = RNA_def_enum(ot->srna,
+                      "domain",
+             

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list