diff options
author | Jacques Lucke <jacques@blender.org> | 2022-07-08 17:16:56 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-07-08 17:16:56 +0300 |
commit | b876ce2a4a4638142439a7cf265a0780491ae4cc (patch) | |
tree | 871d71eb6d1cf215869fc941c831c81bcacc6433 /source/blender/blenkernel/intern/geometry_component_mesh.cc | |
parent | f391e8f316bd29b700cef874a59cf3b64203d70c (diff) |
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_mesh.cc')
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_mesh.cc | 212 |
1 files changed, 117 insertions, 95 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 9e64acf218b..cb36b9b19f7 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -7,7 +7,6 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" -#include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" #include "BKE_deform.h" #include "BKE_geometry_fields.hh" @@ -151,7 +150,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, * array and copy the face normal for each of its corners. In this case using the mesh * component's generic domain interpolation is fine, the data will still be normalized, * since the face normal is just copied to every corner. */ - return mesh_component.attribute_try_adapt_domain( + return mesh_component.attributes()->adapt_domain( VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); @@ -169,26 +168,6 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, /** \name Attribute Access * \{ */ -int MeshComponent::attribute_domain_num(const eAttrDomain domain) const -{ - if (mesh_ == nullptr) { - return 0; - } - switch (domain) { - case ATTR_DOMAIN_CORNER: - return mesh_->totloop; - case ATTR_DOMAIN_POINT: - return mesh_->totvert; - case ATTR_DOMAIN_EDGE: - return mesh_->totedge; - case ATTR_DOMAIN_FACE: - return mesh_->totpoly; - default: - break; - } - return 0; -} - namespace blender::bke { template<typename T> @@ -747,9 +726,10 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v } // namespace blender::bke -blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::GVArray &varray, - const eAttrDomain from_domain, - const eAttrDomain to_domain) const +static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) { if (!varray) { return {}; @@ -765,11 +745,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_CORNER: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_point(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_face(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_corner_to_edge(mesh, varray); default: break; } @@ -778,11 +758,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_POINT: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_corner(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_face(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_point_to_edge(mesh, varray); default: break; } @@ -791,11 +771,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_FACE: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_point(mesh, varray); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_corner(mesh, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray); + return blender::bke::adapt_mesh_domain_face_to_edge(mesh, varray); default: break; } @@ -804,11 +784,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G case ATTR_DOMAIN_EDGE: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_corner(mesh, varray); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_point(mesh, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray); + return blender::bke::adapt_mesh_domain_edge_to_face(mesh, varray); default: break; } @@ -821,20 +801,6 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(const blender::G return {}; } -static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - return mesh_component.get_for_write(); -} - -static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) -{ - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - return mesh_component.get_for_read(); -} - namespace blender::bke { template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> @@ -864,9 +830,9 @@ static void set_vertex_position(MVert &vert, float3 position) copy_v3_v3(vert.co, position); } -static void tag_component_positions_changed(GeometryComponent &component) +static void tag_component_positions_changed(void *owner) { - Mesh *mesh = get_mesh_from_component_for_write(component); + Mesh *mesh = static_cast<Mesh *>(owner); if (mesh != nullptr) { BKE_mesh_tag_coords_changed(mesh); } @@ -1001,15 +967,13 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> { */ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { public: - ReadAttributeLookup try_get_for_read(const GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeReader try_get_for_read(const void *owner, + const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return {}; } - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast<const Mesh *>(owner); if (mesh == nullptr) { return {}; } @@ -1028,15 +992,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { ATTR_DOMAIN_POINT}; } - WriteAttributeLookup try_get_for_write(GeometryComponent &component, - const AttributeIDRef &attribute_id) const final + GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return {}; } - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - Mesh *mesh = mesh_component.get_for_write(); + Mesh *mesh = static_cast<Mesh *>(owner); if (mesh == nullptr) { return {}; } @@ -1060,14 +1021,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { ATTR_DOMAIN_POINT}; } - bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final + bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); if (!attribute_id.is_named()) { return false; } - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - Mesh *mesh = mesh_component.get_for_write(); + Mesh *mesh = static_cast<Mesh *>(owner); if (mesh == nullptr) { return true; } @@ -1101,12 +1060,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { return true; } - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final + bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final { - BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast<const Mesh *>(owner); if (mesh == nullptr) { return true; } @@ -1136,35 +1092,34 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - GVArray try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const void *owner) const final { - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); + const Mesh *mesh = static_cast<const Mesh *>(owner); if (mesh == nullptr || mesh->totpoly == 0) { return {}; } return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly}); } - WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final + GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final { return {}; } - bool try_delete(GeometryComponent &UNUSED(component)) const final + bool try_delete(void *UNUSED(owner)) const final { return false; } - bool try_create(GeometryComponent &UNUSED(component), - const AttributeInit &UNUSED(initializer)) const final + bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final { return false; } - bool exists(const GeometryComponent &component) const final + bool exists(const void *owner) const final { - return component.attribute_domain_num(ATTR_DOMAIN_FACE) != 0; + const Mesh *mesh = static_cast<const Mesh *>(owner); + return mesh->totpoly != 0; } }; @@ -1174,34 +1129,42 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { */ static ComponentAttributeProviders create_attribute_providers_for_mesh() { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - if (Mesh *mesh = get_mesh_from_component_for_write(component)) { - BKE_mesh_update_customdata_pointers(mesh, false); - } + static auto update_custom_data_pointers = [](void *owner) { + Mesh *mesh = static_cast<Mesh *>(owner); + BKE_mesh_update_customdata_pointers(mesh, false); }; #define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ - [](GeometryComponent &component) -> CustomData * { \ - Mesh *mesh = get_mesh_from_component_for_write(component); \ - return mesh ? &mesh->NAME : nullptr; \ + [](void *owner) -> CustomData * { \ + Mesh *mesh = static_cast<Mesh *>(owner); \ + return &mesh->NAME; \ } #define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ - [](const GeometryComponent &component) -> const CustomData * { \ - const Mesh *mesh = get_mesh_from_component_for_read(component); \ - return mesh ? &mesh->NAME : nullptr; \ + [](const void *owner) -> const CustomData * { \ + const Mesh *mesh = static_cast<const Mesh *>(owner); \ + return &mesh->NAME; \ + } +#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \ + [](const void *owner) -> int { \ + const Mesh *mesh = static_cast<const Mesh *>(owner); \ + return mesh->NAME; \ } static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), MAKE_CONST_CUSTOM_DATA_GETTER(ldata), + MAKE_GET_ELEMENT_NUM_GETTER(totloop), update_custom_data_pointers}; static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), MAKE_CONST_CUSTOM_DATA_GETTER(vdata), + MAKE_GET_ELEMENT_NUM_GETTER(totvert), update_custom_data_pointers}; static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), MAKE_CONST_CUSTOM_DATA_GETTER(edata), + MAKE_GET_ELEMENT_NUM_GETTER(totedge), update_custom_data_pointers}; static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), MAKE_CONST_CUSTOM_DATA_GETTER(pdata), + MAKE_GET_ELEMENT_NUM_GETTER(totpoly), update_custom_data_pointers}; #undef MAKE_CONST_CUSTOM_DATA_GETTER @@ -1297,13 +1260,72 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() &face_custom_data}); } +static AttributeAccessorFunctions get_mesh_accessor_functions() +{ + static const ComponentAttributeProviders providers = create_attribute_providers_for_mesh(); + AttributeAccessorFunctions fn = + attribute_accessor_functions::accessor_functions_for_providers<providers>(); + fn.domain_size = [](const void *owner, const eAttrDomain domain) { + if (owner == nullptr) { + return 0; + } + const Mesh &mesh = *static_cast<const Mesh *>(owner); + switch (domain) { + case ATTR_DOMAIN_POINT: + return mesh.totvert; + case ATTR_DOMAIN_EDGE: + return mesh.totedge; + case ATTR_DOMAIN_FACE: + return mesh.totpoly; + case ATTR_DOMAIN_CORNER: + return mesh.totloop; + default: + return 0; + } + }; + fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) { + return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); + }; + fn.adapt_domain = [](const void *owner, + const blender::GVArray &varray, + const eAttrDomain from_domain, + const eAttrDomain to_domain) -> blender::GVArray { + if (owner == nullptr) { + return {}; + } + const Mesh &mesh = *static_cast<const Mesh *>(owner); + return adapt_mesh_attribute_domain(mesh, varray, from_domain, to_domain); + }; + return fn; +} + +static const AttributeAccessorFunctions &get_mesh_accessor_functions_ref() +{ + static const AttributeAccessorFunctions fn = get_mesh_accessor_functions(); + return fn; +} + +AttributeAccessor mesh_attributes(const Mesh &mesh) +{ + return AttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); +} + +MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh) +{ + return MutableAttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); +} + } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const +std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const +{ + return blender::bke::AttributeAccessor(mesh_, blender::bke::get_mesh_accessor_functions_ref()); +} + +std::optional<blender::bke::MutableAttributeAccessor> MeshComponent::attributes_for_write() { - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_mesh(); - return &providers; + return blender::bke::MutableAttributeAccessor(mesh_, + blender::bke::get_mesh_accessor_functions_ref()); } /** \} */ |