SurfaceBuilder::TrackID

Enables primitive tracking using a structured surface and primitive ID scheme

To track primitives (such as triangles) through various operations, a tracking ID can be provided. Internally, each primitive has a 64 bit ID (with some upper bits reserved for flags). When enabled on a surface, all operations try to keep track of these IDs (even across variadic and iterated Booleans and multiple Operations). Resulting IDs can be obtained by using Operation::ExportToTrianglesF32WithID and Operation::ExportToIndexedTrianglesF32WithID instead of the versions without 'WithID'. When this contains primitives from untracked surfaces, then their IDs are binary all-one, i.e. uint64_t(-1).

The ID is structured as follows: [2bit flags][30bit surface ID][32bit primitive ID] represented as an uint64_t.

The flags are [1bit is-inverted][1bit is-subset]:

  • if is-inverted is true, the winding order of the primitive changed. For triangles, this means (v0,v1,v2) is emitted as (v0,v2,v1), i.e. last two vertices are swapped.
  • if is-subset is false, then the emitted primitive is input primitive either unchanged or order-swapped (if is-inverted is true).
  • if is-subset is true, then the emitted primitive is a proper subset of the input, e.g. due to cutting up faces during Booleans.

The primitives of a surface are contiguously numbered by default with a customizable start index.

For example, given two surfaces A and B with 1000 and 2000 faces each, you could track them as: A->TrackID(0) B->TrackID(1) which would result in A's faces being (0,0..999) and B's faces being (1,0..1999).

But you could also track them as: A->TrackID(0, 0) B->TrackID(0, 1000) which would result in A's faces being (0,0..999) and B's faces being (0,1000..2999).

This gives plenty of flexibility on how to track input primitives. Should these options not suffice, SurfaceBuilder::TrackIDRaw and SurfaceBuilder::TrackPrimitiveIDs allow additional flexibility.

Note:
when reconstructing output topology (i.e. Operation::ExportToIndexedTrianglesF32WithID), vertices are currently always converted to integer space and back. this implies that no resulting primitive is guaranteed to be bitwise equal to the input. thus, all outputs are marked as is-subset for now. if this affects your use case, please get in touch.

Signature

class SurfaceBuilder:
    // Enables primitive tracking using a structured surface and primitive ID scheme
    fun trackID(
        surfaceID: uint32_t,
        primitiveStartID: uint32_t = 0,
    )