Source/Objects/Attributes

= Attributes =

Attributes are used to store data that corresponds to geometry elements. Geometry element are items in one of the domains like points, curves, or faces (`eAttrDomain`). Attributes have generic data types like "Float" or "Integer" (`CD_PROP_*`), which means the type itself doesn’t convey how or when the attribute is used. User level documentation about attributes can be found in a dedicated page in the manual.

Attributes are meant to store original data. They aren’t used to cache data that can be recalculated from the geometry like “pointiness” or normals.

The benefits of the attribute system are:
 * Generic: Make geometry custom data implementations more generic, more consistent, and easier to use.
 * Common Interface: Attributes give a common abstraction for changing data on multiple geometry types, improving consistency and removing boilerplate.
 * Data Layout: The attribute system provides access to a high-performance struct-of-arrays layout.
 * Abstracted Storage Method: Using the virtual array system gives implementations flexibility on how data is stored, when that is necessary.
 * Const Correctness: With a `const` geometry, attributes cannot be modified; the `for_write` versions of the API are not available.

There are two APIs for retrieving attributes in Blender.
 * 1) `BKE_attribute.h`: The C API works on the `ID` structure. This approach is tied to the `CustomData` system commonly used to store attributes.
 * 2) `BKE_attribute.hh`: This C++ API is preferred, and is described below. Note that `BMesh` isn't supported yet.

Accessing Attributes
The `AttributeAccessor` and `MutableAttributeAccessor` are used to read or modify a geometry's attributes.

Attributes are accessed by name. However, they can also be accessed with anonymous attribute IDs (`AttributeIDRef`) in geometry nodes to be passed as node sockets.

Functions to access existing attributes start with `lookup`. To retrieve write access, the `for_write` API functions can be used. To add attributes, `lookup_or_add` or `add` can be used.


 * Domain Interpolation: When retrieving an attribute, a domain (`eAttrDomain`) can be provided. If the attribute is stored on a different domain and conversion is possible, the API will return an attribute with values converted to the specified domain. These conversions are implemented for each geometry type with `adapt_domain` methods.
 * Type Conversion: Attributes can be read with any type. Conversions are lazy; they only happen when the values are actually accessed.

The attribute API uses the virtual array system (`BLI_virtual_array.hh`) to make type conversion and domain interpolation more convenient and to provide efficient access to default values. However, if contiguous data is necessary that can be retrieved with `VArraySpan/GVArraySpan` (reading) or API methods with `span` in the name (for writing).

Attribute Storage
Attributes can be stored in any format, as long as it can be presented as a virtual array when reading and writing data. In practice this usually means contiguous arrays for all geometry elements, but it leaves open the possibility of different formats (i.e. for optimized storage of sparse data). For example, vertex groups can be read and written (though not created yet).

Attributes are often tied to `CustomData`. However, since `CustomData` was created before attributes, it combines the legacy style of task-specific attribute types like `CD_MLOOPUV` with generic types like "Float".

Naming Convention
Built-in attributes are given singular names, generally with full words. For example, `position` is used instead of `positions` and `handle_type_left` is used instead of `handle_type_l`, etc. Since these names are visible to users and in the Python API, consistency is important.

Names that start with a period, like `.hide_vert` signify internal data that isn't user-accessible in a procedural context since internal changes might break user expectations. These attributes are hidden from the UI by default.

Besides built-in attributes, users can choose whatever name they want.