The connectivity section says which vertices make up each triangle. It follows the
header and metadata, and the header’s
encoder_method picks one of two forms: sequential, a plain or lightly
compressed list of indices, or Edgebreaker, which describes the mesh as a walk from
triangle to triangle and is much smaller. Number formats such as varUI32
are explained on the header page.
Sequential connectivity
| Field | Type | Meaning |
|---|---|---|
num_faces | varUI32 | Number of triangles |
num_points | varUI32 | Number of points (vertices) |
connectivity_method | UI8 | 0 SEQUENTIAL_COMPRESSED_INDICES, 1 SEQUENTIAL_UNCOMPRESSED_INDICES |
| Indices | See below | Three vertex numbers for each face |
Uncompressed indices are written face by face, three per face, in the smallest width that holds every point number:
num_points | Each index |
|---|---|
| Less than 256 | UI8 |
| Less than 65,536 | UI16 |
| Less than 2,097,152 (221) | varUI32 |
| Otherwise | UI32 |
Compressed indices are num_faces × 3 symbols decoded with the
symbol decoder. Each symbol is the
difference from the previous index (the first from 0), with the sign in the lowest
bit: the magnitude is symbol >> 1, negated when
symbol & 1 is set.
Edgebreaker connectivity
Edgebreaker visits the triangles one by one and records, for each, a symbol saying how it joins the part already visited. Vertices get their numbers in the order the walk first meets them, so the faces need no explicit indices. The section has five parts:
| Part | Contents |
|---|---|
| 1. Header | Traversal type and counts |
| 2. Topology splits | Where the walk splits around holes and handles |
| 3. Symbols | One symbol per triangle (standard traversal only) |
| 4. Start faces | How each connected part of the mesh begins |
| 5. Attribute seams | Edges where an attribute such as texture coordinates is discontinuous |
The valence traversal adds the valence context data after part 5, in place of part 3.
Edgebreaker header
| Field | Type | Meaning |
|---|---|---|
edgebreaker_traversal_type | UI8 | 0 standard, 1 predictive (deprecated, not in the specification), 2 valence |
num_encoded_vertices | varUI32 | Number of vertices |
num_faces | varUI32 | Number of triangles |
num_attribute_data | UI8 | Number of attributes with their own seams (part 5) |
num_encoded_symbols | varUI32 | Number of Edgebreaker symbols, one per triangle |
num_encoded_split_symbols | varUI32 | Number of split symbols; the decoder sets aside this many extra vertex slots |
Topology splits
| Field | Type | Meaning |
|---|---|---|
num_topology_splits | varUI32 | Number of split events |
| For each split event: | ||
source_id_delta | varUI32 | The symbol at which the split is resolved, as a difference from the previous event’s |
split_id_delta | varUI32 | How many symbols earlier the split began |
| Then, for each split event: | ||
source_edge_bit | f[1] | 0 LEFT_FACE_EDGE, 1 RIGHT_FACE_EDGE: which edge of the face the split joins |
The bits are read most significant first, and reading then moves on to the next
whole byte. The decoder turns the deltas into absolute ids:
source_symbol_id = source_id_delta + previous source_symbol_id and
split_symbol_id = source_symbol_id − split_id_delta.
Symbols
In the standard traversal the symbols come as one buffer:
eb_symbol_buffer_size (varUI64) then that many bytes, read as a bit
stream. Each symbol starts with one bit; 0 is C, and anything else is followed by
two more bits:
| Symbol | Bits in the stream | Value | What the decoder does |
|---|---|---|---|
| C | 0 | 0 | Builds the face from three vertices it already has, closing a gap between the current corner and its neighbour |
| S | 1 00 | 1 | Builds the face where two parts of the decoded surface meet, and merges their shared vertex |
| L | 1 01 | 3 | Builds the face with one new vertex, joined along one edge to the current corner |
| R | 1 10 | 5 | Likewise, joined along the other edge |
| E | 1 11 | 7 | Builds a separate face with three new vertices, starting a new part of the surface |
The value is the first bit plus the two further bits shifted left by one. The decoder rebuilds the faces as it reads, symbol i making face i, with corners 3i, 3i + 1 and 3i + 2. The specification gives the exact corner bookkeeping for each symbol.
Start faces and attribute seams
| Field | Type | Meaning |
|---|---|---|
eb_start_face_buffer_prob_zero | UI8 | Probability of a 0 bit, out of 256, for the binary decoder |
eb_start_face_buffer_size | varUI32 | Size of the buffer |
eb_start_face_buffer | UI8[size] | One bit, decoded with rABS, for each part of the surface left open after the symbols: 1 means one more face closes it, built from the three vertices around the opening |
Then, for each of num_attribute_data attributes: | ||
attribute_connectivity_decoders_prob_zero | UI8 | Probability of a 0 bit, out of 256 |
attribute_connectivity_decoders_size | varUI32 | Size of the buffer |
attribute_connectivity_decoders_buffer | UI8[size] | One rABS bit per interior edge, visited face by face: 1 when the edge is a seam for that attribute |
Boundary edges of the mesh always count as seams. Seams let an attribute have several values at one vertex, such as two texture coordinates where a texture is cut.
Valence traversal
The valence traversal (type 2) has no symbol buffer. It predicts each symbol from the
valence, the number of edges, of the vertex the walk is at. After the start faces and
seams come six context streams, for valences 2 to 7
(MIN_VALENCE 2, MAX_VALENCE 7,
NUM_UNIQUE_VALENCES 6):
| Field | Type | Meaning |
|---|---|---|
ebv_context_counters[i] | varUI32 | Number of symbols in context i |
ebv_context_symbols[i] | Symbols | Present when the counter is above 0; each symbol is 0 C, 1 S, 2 L, 3 R or 4 E |
The first symbol is always E. After each symbol the decoder updates the vertex valences and picks the next context from the valence, limited to the range 2 to 7; symbols are taken from the end of each context’s list.