Measure the Full Web 3D Cost

In e-commerce and interactive web design, larger 3D payloads generally increase download and decode time, especially on slower mobile connections. The goal of an engineering-grade Web 3D pipeline is not merely to shrink file size on disk, but to optimize network download time, GPU texture VRAM footprint, and CPU mesh parsing latency concurrently.

1. The Anatomy of GLB File Bloat

When a raw 3D asset is exported directly from Blender, Maya, or 3ds Max without pipeline optimization, it can become tens of megabytes. An unoptimized .glb container suffers from three primary inefficiencies:

  • 32-Bit Float Geometry Redundancy: Vertex positions, normals, and UV coordinates are saved as uncompressed 32-bit floats (4 bytes per component), even when a lower-precision representation would meet the asset’s measured error tolerance.

  • Uncompressed / Duplicated Textures: Separate PNG textures for Ambient Occlusion, Roughness, and Metallic generate three redundant alpha/color channels and excessive HTTP decode overhead.

  • Geometry representation: Unindexed geometry can repeat attribute data instead of sharing it through indices. Some duplicated vertices are necessary at UV or normal discontinuities, so do not weld them indiscriminately.

2. Geometry Optimization: Quantization, Draco & Meshopt

To achieve high compression without degrading surface curvature or silhouette sharpness, professional pipelines apply a multi-tier geometry compression stack.

Full-precision and quantized mesh views that show a controlled geometry error budget.

Illustrative mesh and shaded views of a product; quantization and compression require an explicit error budget.

A. KHR_mesh_quantization (Use an Error Budget)

The Khronos glTF extension KHR_mesh_quantization permits additional lower-precision attribute representations. The exporter chooses component types, normalization, and dequantization transforms according to the attribute and extension rules. Depending on the chosen component types and source data, this can provide:

  • Position-buffer example: Three float32 components use 12 bytes per vertex. Three int16 components use 6 bytes. The file-level reduction depends on the rest of the asset.

  • Normal precision: Quantized normal attributes and a codec's internal filters are different representations. Core glTF normal accessors remain VEC3; do not describe an internal octahedral codec filter as an ordinary two-component glTF normal attribute.

  • Native WebGL Execution: Modern GPU vertex shaders unpack quantized attributes directly in hardware without a separate mesh-codec decode step.

B. Draco vs. Meshopt: Which Should You Use?

Draco and Meshopt make different tradeoffs between encoded size, decode speed, streaming behavior, and tooling support. Decode cost varies substantially with mesh structure, worker configuration, browser, and device, so benchmark both codecs with representative assets instead of choosing from a generic percentage.

Qualitative comparison of Draco, Meshopt, and quantized attributes with asset-specific checks for size, decode time, and visual error.

Codec choice depends on delivery size, decode cost, and the target asset.

3. PBR Texture Optimization: ORM Packing & KTX2

Textures are often the largest part of a product GLB, but the proportion varies by asset. Optimizing texture buffers requires a disciplined channel-packing strategy combined with next-generation GPU texture compression.

An ORM texture diagram mapping occlusion to red, roughness to green, and metallic data to blue.

An ORM image stores occlusion in red, roughness in green and metallic data in blue; glTF texture references select the required channels.

A. The Power of ORM Channel Packing

In standard PBR metallic-roughness workflows, Ambient Occlusion, Roughness, and Metallic maps are single-channel grayscale data. Packing them into one RGB image eliminates two whole image containers:

  • Red Channel: Ambient Occlusion (Cavity micro-shadowing)

  • Green Channel: Roughness (Surface micro-facet glossiness)

  • Blue Channel: Metallic (Conductive vs dielectric mask)

B. Format Comparison: WebP vs PNG vs KTX2

Converting PNG textures to WebP can shrink the .glb file on disk, but the renderer decodes the image before use. A 4096 x 4096 RGBA8 image contains 67.1 MB of decoded pixel data before mipmaps, regardless of a 1.5 MB encoded download. Browser and driver allocation can differ from that calculation.

KTX2 with Basis Universal can be transcoded into a GPU-supported compressed format. Runtime memory depends on that target, mip levels, and any fallback. It can reduce texture storage compared with RGBA8, but the complete scene still needs measurement.

4. Automate a reviewed operation, then verify the output

The following integration example illustrates glTF Transform with Meshopt. It assumes compatible installed versions of the listed packages and is not a benchmark or a claim that the resulting file is approved for production.

import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { dedup, meshopt } from '@gltf-transform/functions';
import { MeshoptEncoder, MeshoptDecoder } from 'meshoptimizer';

await MeshoptEncoder.ready;
await MeshoptDecoder.ready;

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

const document = await io.read('./raw-model.glb');
await document.transform(
  dedup(),
  meshopt({ encoder: MeshoptEncoder, level: 'medium' })
);
await io.write('./optimized-model.glb', document);

Check the pinned meshopt transform's documented behavior before adding separate reorder or quantize operations. Those stages may already be included by the high-level transform. Additional input extensions can require their own registered dependencies.

This example does not bake textures, create KTX2 images, repair product geometry, or establish runtime compatibility. Keep the original and validate the output. Inspect the required component identities and material result before accepting deduplication or any further pruning. Use the tool's inspect command and preserve an operation log with the measured candidate.

5. Illustrative Optimization Budget

The following example shows how a team might budget an industrial appliance asset with 18 parts, 320,000 polygons, and four 4K texture sets. It is an illustrative worksheet, not a published benchmark; replace the values with measurements from your asset and target network:

Illustrative GLB optimization budget showing file-size reductions across cleanup, packing, quantization, and compression stages.

Illustrative optimization budget. Validate every value with the actual asset, network, and target device.

Master Production Summary

Combining vertex quantization, Meshopt triangle reordering, ORM texture packing, and KTX2 can reduce delivery size substantially. The acceptable result is the smallest asset that stays within a documented visual-error budget and meets measured decode, upload, and frame-time targets.

Frequently Asked Questions

What is the difference between Draco and Meshopt compression for GLB files?

Draco and Meshopt trade encoded size, decode speed, streaming behavior, and tooling support differently. Benchmark both with representative assets, workers, browsers, and target devices before choosing.

How does KHR_mesh_quantization reduce 3D model size without visible loss?

KHR_mesh_quantization allows glTF attributes to use lower-precision component types. The authoring tool chooses the bit depth and transform, and the result should be checked against an asset-specific position, normal, and UV error budget.

What is ORM channel packing and why is it essential for glTF/GLB?

ORM packing stores occlusion, roughness, and metallic data in the red, green, and blue channels of one texture. It reduces three image resources to one, but GPU-memory savings depend on the original internal formats and channel support.

Can Three.js and Shopify load quantized Meshopt GLB files natively?

Three.js GLTFLoader documents quantization support and a Meshopt decoder integration. Configure the dependencies required by the actual asset and pinned runtime. For Shopify or another storefront receiver, check its current documented support and test the output rather than inferring compatibility from a separate Three.js preview.