diff options
author | Jacques Lucke <jacques@blender.org> | 2022-01-21 14:47:35 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-01-21 14:47:35 +0300 |
commit | f6888b530ac81abbe61755971449ad6b42b93c82 (patch) | |
tree | d5234ec992f73046f031e71d62cc47efe5cbcc64 /source/blender/editors | |
parent | 36c40760a5a38db733e20c948b2170ab78bb2607 (diff) |
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
Diffstat (limited to 'source/blender/editors')
4 files changed, 214 insertions, 1 deletions
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", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Which geometry element to move the attribute to"); + RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); + + RNA_def_enum( + ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", ""); +} + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index 14992476edd..30a2a1d6eb1 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -25,6 +25,11 @@ struct wmOperatorType; +namespace blender::ed::geometry { + /* *** geometry_attributes.cc *** */ void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot); +void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index ba8afe0e62f..8933b2a7f00 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -31,6 +31,9 @@ void ED_operatortypes_geometry(void) { + using namespace blender::ed::geometry; + WM_operatortype_append(GEOMETRY_OT_attribute_add); WM_operatortype_append(GEOMETRY_OT_attribute_remove); + WM_operatortype_append(GEOMETRY_OT_attribute_convert); } |