compressGeometry property
fmt-30n's own row: when true, this writer does two independent things
to the geometry on its way into the file.
Vertex/triangle order is optimized for a GPU's caches
(flutter3d_geometry's own optimizeVertexCache) before anything else
below reads the mesh: Tom Forsyth's greedy vertex-cache scoring reorders
triangles for the post-transform cache, then vertices are renumbered by
first use for the pre-transform ("fetch") one. The mesh this draws is
unchanged — same triangles, same winding — only which byte offset a
vertex or an index lands at moves, which is why compareModelDocuments
needs its own allowVertexReorder to keep proving that rather than
reading the move as data loss.
NORMAL/TANGENT/TEXCOORD_0/COLOR_0 are written as normalized
integers (KHR_mesh_quantization) instead of FLOAT, whenever an
attribute's own values actually fit the type losslessly enough to
normalize — a quarter to an eighth the bytes per component, real size on
a file whose vertex data is often more attribute bytes than position
bytes.
POSITION is not quantized. KHR_mesh_quantization's own normalized
integer only reaches [-1, 1]; recovering real coordinates from that
needs a per-mesh dequantization scale baked into the placement of every
node that draws the mesh — correct on its own, and exactly what
gltfpack and similar tools do. What blocks it here is ModelNode:
node.surfaces may list more than one surface (_writeScene's own
multi-primitive mesh), and those surfaces do not all share one
bounding box, so a compensating scale correct for one primitive would
silently misplace every vertex of another primitive sharing that node.
Doing this right needs the node/surface grouping computed before any
mesh is encoded, so a shared node can refuse the compensation rather
than apply the wrong one — real work EXT_meshopt_compression's own
scope note below already explains this row does not have room for
alongside a correct quantizer and a correct reordering pass. Every
attribute that is quantized here is one this package's own
GltfLoader already reads correctly as-is, because normalized-integer
decoding is already a property of GltfComponentType.readDouble, not
something new.
EXT_meshopt_compression is written through this package's own
vertex and index codecs (encodeMeshoptVertexBufferV0,
encodeMeshoptIndexBuffer — see _compressedVertexBufferView and
_compressedIndexBufferView below), and GltfLoader decodes what this
writes back. KHR_mesh_quantization is written alongside it, on the one
attribute the meshopt codec cannot reach (_quantizedOrFloatAccessor's
own doc comment says which and why); the two extensions cover different
attributes of the same primitive rather than one standing in for the
other.
Implementation
final bool compressGeometry;