compressGeometry property

bool compressGeometry
final

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;