Skip to content

Read / Write attributes

If you've read the section on Graphite, we talked briefly about what we call attributes. Attributes are data that can be written to the primitives of a mesh. They are detached from the mesh itself, but can still be saved when the file is saved in geogram format.

The geogram format is specific to the Graphite viewer. The advantage of this format is that you can visualize mesh attributes in Graphite in the form of color maps. To find out more, please refer to the Graphite section.

We'll look at how to create different kinds of attributes and save them for viewing, then load them from a file.

Attribute types

Each primitive can be associated with one or more attributes. Each primitive type has a corresponding attribute type.

Primitive type Attribute type
Surface::Vertex PointAttribute<T>
Surface::Facet FacetAttribute<T>
Surface::Edge CornerAttribute<T>

The attributes classes are templated, so you can associate data of any type with any primitive. The most commonly used types are double, int, bool, vec2, vec3.

Warning

  • Only the geogram file format support attributes.
  • If you want to view attributes (in Graphite), only the primitive types listed above can be used.

Create and fill attributes

Example 1 - Point attribute

In this example, we'll create a point attribute for which for each vertex of the mesh we'll set the distance between origin and this vertex.

// Create a point attribute
PointAttribute<double> pa(m.points);

for (auto v : m.iter_vertices()) {
    // Compute manhattan distance (l1-norm) between origin and vertex
    auto d = vec3(0,0,0) - v.pos();
    pa[v] = std::abs(d.x) + std::abs(d.y) + std::abs(d.z);
}

Now, you just have to save attribute into the mesh file.

// Save mesh with previously created attribute
write_by_extension("catorus_manhattan.geogram", m, {{{"pa", pa.ptr}}, {}, {}});

Now, let's visualize this point attribute into Graphite. What you see is that the further away the vertices are from the origin, the whiter they are, and the closer they are, the darker they are.

Graphite view of manhattan catorus

Example 2 - Facet attribute

In this example, we'll create a facet attribute for which we'll set a random value between 0 and 99 for each facet of the mesh.

// Create a facet attribute
FacetAttribute<int> fa(m);

// For all facets in mesh, associate a random int value between [0-99]
for (auto f : m.iter_facets())
    fa[f] = rand() % 100;

Now, you just have to save attribute into the mesh file.

// Save mesh with previously created attribute
write_by_extension("catorus_fa.geogram", m, {{}, {{"fa", fa.ptr}}, {}});

If you visualise this attribute into Graphite, you will see a very funky cat !

Graphite view of funky catorus

Of course, the purpose of attributes is not to make pretty and colorful cats. We can use attributes to debug and visualize what we're doing on a mesh. You'll see better examples later.

Example 3 - Corner attribute

[Coming soon]

Save attributes

As you've seen, attributes can be saved directly in geogram files. Geogram files can then be read by graphite, which is able to display the attributes. You'll notice that attributes are stored in the file as key/value pairs: each attribute must have a name.

Note

When saving the model, you can specify several attributes, but these must be grouped and specified in the column corresponding to their type.

// Save mesh with attributes
write_by_extension("mesh.geogram", m, {
        {{"pa1", pa1.ptr}, ...}, // Point attributes
        {{"fa1", fa1.ptr}, ...}, // Facet attributes
        {{"ca1", ca1.ptr}, ...}  // Corner attributes
    }
);

For example we will save all previously created attributes into a geogram file:

// Save mesh with all previously created attributes
write_by_extension("catorus_attr.geogram", m, {{{"pa", pa.ptr}}, {{"fa", fa.ptr}}, {}});

Read attributes

Now it's time to learn how to read the attributes we've written in our geogram files:

// Load mesh and read attributes
Triangles m2;
SurfaceAttributes attributes = read_by_extension("catorus_attr.geogram", m2);
// Load "pa" attribute
PointAttribute<double> pa2("pa", attributes, m2);
// Load "fa" attribute
FacetAttribute<int> fa2("fa", attributes, m2);
// Load "ca" attribute
// TODO

std::cout 
    << "PointAttribute size: " << pa2.ptr.get()->data.size() 
    << ", FacetAttribute size: " << fa2.ptr.get()->data.size() 
    << std::endl;