Mesh Data Structures¶
Blender uses two main data structures for meshes:
Mesh: The main data structure associated with the
ID_MEdata-block type. Focuses on performance with many elements. The rest of this document mainly describes this data structure.
BMesh: Edit mode data structure that prioritizes implementation of small topology-changing operations (mainly documented here).
Meshes use data structures oriented around a struct of arrays paradigm. One idea behind that design is to decrease the amount of memory accessed in hot loops that generally only deal with a few data elements at a time. It also allows using generic algorithms that aren't necessarily only designed for mesh. For more background on the SoA paradigm in meshes, see the development design task.
Meshes support all generic attribute types.
In order to defer calculation of some runtime data until it's actually needed without duplicating work, there are a few lazily calculated caches stored on meshes. Some examples are:
- Bounds: (
BKE_mesh_minmax) The min and max position of the mesh
- Vertex Normals: (
Mesh.vert_normals()) The normal of every vertex. The same as the surrounding face normals mixed together, weighted by the corner angle.
- Face Normals: (
Mesh.poly_normals()) The normal direction of each face according to its winding direction.
- Loose Edges: (
Mesh.loose_edges()) Whether each edge is loose, and the total number of loose edges.
When a mesh is changed, these caches need to be removed or tagged dirty.
Generally this is possible with functions like
BKE_mesh_tag_positions_changed. Because the caches are stored with
BLI_shared_cache.hh), they are shared between
meshes. If they aren't invalidated, calculating the cache on one mesh
can make the result available on another too.
At the core of
Mesh there are a few arrays of basic integer data
types that store the relationships between mesh elements in a single
"top-down" direction. Faces reference face corners, and face corners
reference vertices and edges. It's important to distinguish this
topology mapping, the core "first principle" data that everything else
is based off of from maps like "which face is this corner a part of?"
that can always be recreated from the basic data.
- Vertices: At the lowest level of the mesh "topology hierarchy", vertices are used to store various attributes like position. Conceptually though, a Vertex is all the attributes, it's just an index into all of the vertex domain attribute arrays.
- Edges: Edges store the index of the two vertices they connect.
Edges are more complex, since they have a tautological relationship
with the references that each face corner has to the next edge in the
face. Though storing edges explicitly is the only way to encode loose
edges not connected to any faces, edges and corner edge indices
must match the edges described implicitly by corner vertex
references. Edges are often generated from scratch from these corner
vertex indices (see
Faces: Also known as "polygons", they are the highest level element in the core mesh topology. Given a specific face, it's easy to know which corners, vertices, and edges it's made out of. Faces are only stored as a range of corner indices. Because faces and face corners share the same order, each face can be stored as a single integer using
OffsetIndicesis a general abstraction for splitting a larger array into many contiguous groups. Every group is represented by a single integer-- the first index of the elements in the group. The end of the group is simply the next integer in the offsets array. For example, the face offsets
[0,3,4,7,11]encode a triangle, a quad, a triangle, and a quad, in that order. - Face Corners: Corners are how faces reference edges and vertices. They aren't shared between faces, unlike edges and vertices. In the mesh arrays, each face corner knows the indices of the vertex it's attached to, and the index of the next edge clockwise around the face. In order to retrieve the next or previous corner, the face must be known, since the corners for each face loop around at the beginning/end.
Mesh data arrays are usually retrieved and passed
as arguments in the order below.
Patterns and Naming¶
Vertices in a Face
Edges in a Face
Corners in a Face
blender::bke::mesh namespace is meant for common lower-level
operations on mesh data. Public functions in that namespace shouldn't
Mesh as an argument, but rather raw data, in array form or just
single elements. This functional style is meant to make it clear what
data algorithms use and output, and help to guide APIs into a more
understandable design. The purpose is similar to that of