Badr Abardazzou

Papers · Explainer

How heavy should a 3D model be?

A test plant, seven optimisation steps, one rule for the centimetre. From 11.9 MB to 57 KB with the same picture.

A 3D model in a report has one job: let people find an object and see its status. Every triangle that does not serve that job costs download time, memory and frame rate. This page measures where the weight sits in a GLB, what you can remove for free, and what you pay when you remove more.

The test plant: two tanks, twelve pumps, a pipe rack with lines, elbows and valves on a slab
The test plant. Generated for this page: 2 tanks, 12 identical pumps, 24 identical valves, a pipe rack with 12 lines, 75 objects, 164,284 triangles. Written the way a dense CAD export writes: 128 segments around a tank, 48 around a pipe.
11.9 MBas exported
0.6 MBafter 3 lossless steps
57 KB1 cm cap + Draco

01Where detail is decided

CAD and IFC can store a pipe as an exact cylinder. A GLB only stores flat triangles, so somewhere an export cuts every curve into straight segments. The gap between the true curve and the flat segment (the chord error) is the detail you keep or lose.

8 segments gap 11.4 mm on a 300 mm pipe
16 segments gap 2.9 mm on a 300 mm pipe
48 segments gap 0.32 mm on a 300 mm pipe
Chord error = r × (1 − cos(π / n)). Dashed: the exact pipe. Solid: what the GLB stores. 48 segments keep the surface within a third of a millimetre, far below what a screen can show.
RadiusSegments for 1 cmSegments for 1 mm
30 mm (2 in line)413
150 mm (12 in line)928
1 m (vessel)2371
8 m (tank)63199

One fixed segment count wastes triangles on small pipes and starves large tanks. A cap in millimetres treats every size the same way, which is why the steps below cap the error, not the count.

02Which format carries what

No format wins on everything. The richest formats are the hardest to draw; the format built for drawing carries the least data. The usual answer is to send the geometry as GLB and keep the data in a table beside it.

FormatOwnerGeometryPropertiesIn a browser
NWDAutodesk (Navisworks)TrianglesYes, richNo: Autodesk tools or a converter
IFCbuildingSMART, ISO 16739-1Exact solids, extrusions or trianglesYes, the richest (property sets, types, relations)Through a converter or an IFC web library
STEPISO 10303Exact curved surfaces (B-rep)LittleNo: tessellate first
FBXAutodeskTriangles, materials, animationLimitedThrough a converter
OBJOpen, plain textTriangles, groups, materialsNoYes, but large and slow
glTF / GLBKhronos GroupTriangles, scene tree, namesNames + extras JSON, or a separate tag tableYes: built for runtime delivery
3D TilesOGC community standardMany GLB tiles, streamed by viewPer-feature metadataYes, at city or site scale

03Seven steps, measured

The same plant, each step applied on top of the previous one. Green steps change nothing you can see. Amber steps remove detail you choose.

After the web server gzips the file, meshopt (45 KB) and Draco (48 KB) end up close. Both need their decoder in the viewer; a viewer without it shows nothing.

04The centimetre

Simplification merges triangles until a surface would move more than the cap. The cap is the only lossy choice that matters, so pick it on purpose: the same close-up at four caps.

Close-up of elbows and a valve handwheel, full detail
No cap · 164k triangles
Same close-up at a 1 cm cap
1 cm · 55k triangles
Same close-up at a 2 cm cap, elbows polygonal
2 cm · 30k triangles
Same close-up at a 5 cm cap, the handwheel is gone
5 cm · 20k · handwheel gone
CapTriangles drawnFileWhat you see
none
164,284
606 KB

Reference after the lossless steps.

1 mm
150,336
701 KB

8 % fewer triangles, file 16 % larger: the rewrite split shared buffers (27 to 35). Not worth it.

5 mm
87,264
504 KB

Close to the original.

1 cm
54,588
357 KB

Shapes kept. Elbows show facets close up.

2 cm
29,904
173 KB

Elbows turn polygonal close up. The 6 cm handwheel still there.

5 cm
19,808
104 KB

Handwheel and stem gone, elbows become cones. Overview only.

10 cm
16,360
79 KB

Same as 5 cm with rougher curves. Gains have flattened.

Cap below the smallest thing that must stay visible.Here a ring 6 cm thick survived 2 cm and vanished at 5 cm. Instruments, handwheels and small bore lines set the cap, not the tanks.
Cap in centimetres, not in percent.A relative error is a fraction of each mesh's size (meshoptimizer's default): 1 % of a 100 m slab is 1 m, 1 % of a valve is 5 mm. An absolute cap treats both the same.
Stop where the curve flattens.From 1 cm to 2 cm the file halves; from 5 cm to 10 cm it drops 24 % for a worse picture. For site overviews 2 cm, for equipment walk-downs 1 cm, on this plant.
Drop on purpose, not by accident.If tiny parts are not needed, remove them by size before simplifying and list what was removed. A part that collapses into a sliver looks like a modelling error.

05Before it goes into Power BI or a web app

  • The tag survives every step. Count the distinct element IDs before and after optimising. Welding, dedup and simplification rewrite buffers; the ID attribute must ride along (see how the click finds its row).
  • The viewer reads what you wrote. Instancing (EXT_mesh_gpu_instancing), meshopt and Draco are extensions. three.js reads all three when given the decoders; check yours before you ship.
  • Quantize knowingly. 16-bit positions split each mesh's bounding box into 65,535 steps: 1.5 mm on a 100 m mesh. Fine for a plant, not for a micrometre part.
  • Keep coordinates near zero. GLB positions are 32-bit floats: at 500 km from the origin the step is 3 cm. Subtract a site origin at export and store it once.
  • Size the tag table too. A Power BI visual receives data in windows of 30,000 rows and stops at 1,048,576 rows. One row per tagged object, not per triangle.
  • Keep the raw export. Every step here is a script. When the cap turns out wrong, re-run from the raw file, never from an already simplified one.
Method. The test plant was generated for this page (no real project data). Steps run with glTF-Transform 4.5.1 (weld, dedup, instance, quantize, meshopt, draco), simplification with meshoptimizer 1.2.0 using an absolute error cap, renders with three.js 0.170. Sizes are bytes on disk; gzip at level 9. Your ratios will differ with your model: run the same steps on it.
Sources. glTF 2.0, KHR_mesh_quantization, EXT_mesh_gpu_instancing, EXT_meshopt_compression, KHR_draco_mesh_compression, meshoptimizer, glTF-Transform, OGC 3D Tiles, IFC, Power BI fetchMoreData limits.