EXT_meshopt_compression provides compression and fast decoding for geometry, morph targets, and animations.

NOTICE: Multi-vendor extensions (EXT_*) should be considered last-mile optimizations for an application known to support their use. Files using these extensions may not be widely portable in other software, and are not officially endorsed by the Khronos Group.

Meshopt compression (based on the meshoptimizer library) offers a lightweight decoder with very fast runtime decompression, and is appropriate for models of any size. Meshopt can reduce the transmission sizes of geometry, morph targets, animation, and other numeric data stored in buffer views. When textures are large, other complementary compression methods should be used as well.

For the full benefits of meshopt compression, apply gzip, brotli, or another lossless compression method to the resulting .glb, .gltf, or .bin files. Meshopt specifically pre-optimizes assets for this purpose — without this secondary compression, the size reduction is considerably less.

Be aware that decompression happens before uploading to the GPU. While Meshopt decoding is considerably faster than Draco decoding, neither compression method will improve runtime performance directly. To improve framerate, you'll need to simplify the geometry by reducing vertex count or draw calls — not just compress it. Finally, be aware that Meshopt compression is lossy: repeatedly compressing and decompressing a model in a pipeline will lose precision, so compression should generally be the last stage of an art workflow, and uncompressed original files should be kept.

The meshoptimizer library (github, npm) is a required dependency for reading or writing files, and must be provided by the application. Compression may alternatively be applied with the gltfpack tool.

Example

import { NodeIO } from '@gltf-transform/core';
import { MeshoptCompression } from '@gltf-transform/extensions';
import { MeshoptDecoder } from 'meshoptimizer';

await MeshoptDecoder.ready;

const io = new NodeIO()
    .registerExtensions([MeshoptCompression])
    .registerDependencies({
        'meshopt.decoder': MeshoptDecoder,
        'meshopt.encoder': MeshoptEncoder,
    });

// Read and decode.
const document = io.read('compressed.glb');

// Write and encode. (Medium, -c)
await document.transform(reorder(), quantize());
document.createExtension(MeshoptCompression)
    .setRequired(true)
    .setEncoderOptions({ method: MeshoptCompression.EncoderMethod.QUANTIZE });
io.write('compressed-medium.glb', document);

// Write and encode. (High, -cc)
await document.transform(
    reorder(),
    quantize({pattern: /^(POSITION|TEXCOORD|JOINTS|WEIGHTS)(_\d+)?$/}),
);
document.createExtension(MeshoptCompression)
    .setRequired(true)
    .setEncoderOptions({ method: MeshoptCompression.EncoderMethod.FILTER });
io.write('compressed-high.glb', document);

Hierarchy

  • Extension
    • MeshoptCompression

Properties

extensionName: "EXT_meshopt_compression" = ...
prereadTypes: PropertyType[] = ...
prewriteTypes: PropertyType[] = ...
readDependencies: string[] = ...

Methods

  • dispose(): void
  • Disables and removes the extension from the Document.

  • isRequired(): boolean
  • Indicates to the client whether it is OK to load the asset when this extension is not recognized. Optional extensions are generally preferred, if there is not a good reason to require a client to completely fail when an extension isn't known.

  • Configures Meshopt options for quality/compression tuning. The two methods rely on different pre-processing before compression, and should be compared on the basis of (a) quality/loss and (b) final asset size after also applying a lossless compression such as gzip or brotli.

    • QUANTIZE: Default. Pre-process with quantize() (lossy to specified precision) before applying lossless Meshopt compression. Offers a considerable compression ratio with or without further supercompression. Equivalent to gltfpack -c.
    • FILTER: Pre-process with lossy filters to improve compression, before applying lossless Meshopt compression. While output may initially be larger than with the QUANTIZE method, this method will benefit more from supercompression (e.g. gzip or brotli). Equivalent to gltfpack -cc.

    Output with the FILTER method will generally be smaller after supercompression (e.g. gzip or brotli) is applied, but may be larger than QUANTIZE output without it. Decoding is very fast with both methods.

    Example:

    doc.createExtension(MeshoptCompression)
        .setRequired(true)
        .setEncoderOptions({
            method: MeshoptCompression.EncoderMethod.QUANTIZE
        });
    
  • Indicates to the client whether it is OK to load the asset when this extension is not recognized. Optional extensions are generally preferred, if there is not a good reason to require a client to completely fail when an extension isn't known.

  • register(): void
  • Performs first-time setup for the extension. Must be idempotent.

Function symbol, f(📦) → 📦, where the argument and output are a box labeled 'glTF'.

Made by Don McCurdy TypeDoc documentation Copyright 2021 under MIT license