3D Model Optimization

3D model optimization is the work of turning a file built for manufacturing or offline rendering into one a browser can download and draw quickly, without it looking like a different product. It covers geometry reduction, UV and material rework, texture compression, and the file format the result ships in — usually glTF or its binary form GLB.

It is the least glamorous part of 3D on the web and the part that decides whether the project works. A beautiful model that takes eleven seconds to appear has failed. Most of the time the fix is not "make it simpler" — it is a sequence of specific, measurable steps, and the model ends up looking the same while weighing a fifth as much. The chair in the demo above went from 4.13 MB to 776 KB that way.

Built by

Peter Csipkay

Creative frontend developer near Munich, and the person behind this site. I scope, build and ship the work myself.

Live demo

Real-time, running on your device

A demonstration built for this page rather than a shop — the product is a CC0 sample model. Nothing to press: it starts by itself, and costs about 780 KB of model, once.

Starting the demo…

Model: “Sheen Chair” © 2020 Wayfair, LLC, released under CC0 1.0. Optimised to 776 KB with meshopt geometry compression and WebP textures. Prices shown are illustrative.

What actually makes a model heavy

Almost everyone guesses polygons. Polygons are usually not the problem.

Textures are the problem. A single 2048×2048 texture uploaded as ordinary RGBA occupies about 16 MB of GPU memory, and about 22 MB once mipmaps exist. A product with base colour, normal, roughness and occlusion maps at that size is approaching 90 MB of GPU memory before anything else loads. Six such materials and a mid-range phone silently reloads the tab. The download size is the visible half of this; the memory footprint is the half that crashes things.

Draw calls are the second problem. A CAD export commonly arrives as hundreds or thousands of separate objects, because that is how it was assembled — every bolt is its own part. Each distinct object with a distinct material is a draw call, and the cost is per call rather than per triangle. Merging fifty parts that share a material into one mesh can matter more than halving the triangle count.

Geometry is the third problem, and it is usually the smallest. Yes, a CAD tessellation at manufacturing tolerance produces absurd triangle counts for a screen. But compressed geometry is remarkably cheap, and a 200,000-triangle mesh that renders in one draw call with one compressed texture set is entirely reasonable on the web.

The practical order of attack is therefore: textures first, draw calls second, triangles third. It is the reverse of what most briefs assume.

The pipeline, step by step

1. Audit before touching anything

Open the file and get the numbers: triangle count, mesh count, material count, texture dimensions and formats, extensions used, and total GPU memory. Optimising before measuring is how people spend a week halving a triangle count that was never the bottleneck. The GLB inspector on this site does the basic version of this for free.

2. Fix the geometry

Retopologise or decimate to a budget chosen from how large the object appears on screen, not from a general sense of "lighter". Weld duplicate vertices. Delete what is never visible — interior components inside a sealed housing are pure cost. Bake fine detail into a normal map rather than carrying it as triangles.

3. Fix the materials and draw calls

Merge meshes sharing a material. Atlas small textures together. Cut the material count, which usually means deciding that four subtly different greys are one grey. Keep parts separate only where something needs to address them individually — a configurator needs its options as distinct meshes, so optimisation and interactivity have to be planned together rather than in sequence.

4. Compress the textures

The biggest single win. Resize to what the screen actually needs, then encode:

  • KTX2 / Basis Universal stays compressed in GPU memory, roughly a quarter of the raw footprint. This is the correct answer for anything texture-heavy or mobile-facing. It needs a transcoder served alongside the model, which is a small one-off setup cost.
  • WebP decodes natively in every current browser and needs no transcoder, but expands to full RGBA in GPU memory once decoded. Fine when the texture budget is modest, wrong when it is not.

The distinction matters and is widely missed: WebP shrinks the download, KTX2 shrinks the download and what the GPU holds.

5. Compress the geometry

Draco compresses harder; Meshopt decodes faster and its decoder is tiny. On a page where time-to-first-frame matters more than bytes, Meshopt usually wins. Both are glTF extensions and both need their decoder wired into the loader — a step that silently breaks a model if it is missed, which is a common cause of "the file works in Blender but not on the site".

6. Verify against the original

Side by side, at the size it will actually be seen, on the devices it will actually be seen on. An optimisation that changes the product's appearance is a failure regardless of what it did to the file size.

A worked example: 4.13 MB to 776 KB

The chair in the demo at the top of this page is a public domain model from the Khronos glTF sample set. It arrived as a 4.13 MB GLB. It ships here at 776 KB, an 81% reduction, and it is the same chair.

What the pass did:

  • Textures resized to 1024 px and re-encoded as WebP.
  • Geometry quantised and compressed with EXT_meshopt_compression.
  • Duplicate data de-duplicated, unused data pruned.

What the pass deliberately preserved:

  • All four original meshes — fabric, wood, metal and the label — because the configurator addresses them individually. A naive "merge everything" pass would have produced a smaller file and a broken demo.
  • The KHR_materials_variants material variants, which is what the upholstery and frame options actually switch between.
  • KHR_materials_sheen, which is what makes the velvet read as velvet rather than as flat fabric.

The last three points are the reason this is skilled work rather than a command. The command is one line; knowing what must survive it is the job. Here WebP was the right texture choice over KTX2 given the modest texture budget and the value of not shipping a transcoder for a single demo model — on a catalogue of forty products the calculation goes the other way.

Full attribution and the exact command are recorded in the repository, and the model is CC0.

What it costs

Per model, cost tracks three things:

  1. What arrives. A clean glTF that needs compressing is a short job. A CAD assembly at manufacturing tolerance that needs retopologising, re-UVing and re-materialing is a modelling project. Native CAD formats often need a conversion step before anything else can happen.
  2. How much appearance may change. "Make it lighter" and "make it lighter with no visible difference at any zoom level" are different budgets. Agreeing the acceptable difference up front, on one model, saves arguing about it on forty.
  3. Whether it is one model or a pipeline. The first model is expensive because it establishes the budget, the settings and the verification method. The fortieth runs through an automated pipeline for a fraction of that. If a catalogue is the goal, say so at the start — retrofitting a pipeline after thirty hand-optimised models is the expensive route to the same place.

Worth saying plainly: for a single model with clean source files, this is often a small enough job that the honest advice is to do it yourself. The tools are free and open source, glTF-Transform chief among them, and the commands are documented. Where it is worth paying someone is a catalogue, a difficult source file, or a case where appearance is brand-critical.

How it fits what the model is for

Optimisation is not a separate stage bolted on at the end — the right settings depend on what the model has to do.

A model for a product configurator must keep its parts addressable and its material variants intact, which rules out aggressive merging. A model for a real-time product viewer can be merged hard, because nothing needs to be selected. A model destined for a WebXR session needs roughly twice the headroom, because everything renders once per eye at a higher frame rate. A model in a scroll-driven site needs to be small enough not to delay the first meaningful paint.

Same source file, four different correct answers. This is why "optimise this model" is not quite a complete brief, and why the first question I ask is what the model is for.

What goes wrong

Decimating first. Triangle count is the visible number, so it gets attacked first, and it is usually third in importance. Meanwhile the 4K texture set nobody looked at is what is actually crashing phones.

Optimising a model before knowing what it is for. A merged, atlased, beautifully compact mesh is useless to a configurator that needs to recolour the cushions.

Exporting from CAD with default settings. Manufacturing tolerance produces tessellation nobody needs on a screen, and the defaults are set for manufacturing.

Forgetting the decoder. A Draco or Meshopt file with no decoder wired into the loader fails at runtime with an error that does not obviously point at the cause. Similarly KTX2 without a transcoder path.

Compressing normal maps as if they were photographs. Aggressive lossy compression on a normal map produces visible banding in the lighting. Different maps want different treatment.

No before-and-after check on real devices. The file size went down, so it worked — except the roughness map is now blocky and the product looks cheap on a retina screen.

Treating it as one-off. New products arrive. If the pipeline is a person following remembered steps, quality drifts. Script it.

Budget

What it costs to work with me

Priced per model, and it drops sharply after the first: the first model buys the budget, the settings and the verification method, and the rest run through the pipeline that establishes. Send me one representative source file and I will tell you what it needs — and if the honest answer is that your team can do this in an afternoon with free tools, I will tell you that instead.

Schedule

How long it takes

  1. 01

    Audit

    1–2 days

    Real numbers from the real files: triangles, meshes, materials, texture dimensions, GPU memory, extensions. Plus what the model is for, which decides everything after this.

  2. 02

    One model, all the way

    3–5 days

    A representative model taken through the full pipeline and approved side by side with the original. This sets the budget and the acceptable difference for everything that follows.

  3. 03

    Pipeline

    1–2 weeks

    Scripting the agreed settings so the process is repeatable and new products do not depend on someone remembering the steps.

  4. 04

    Catalogue run

    Scales with volume

    The remaining models through the pipeline, with spot checks. Awkward source files get handled individually.

  5. 05

    Verification and handover

    2–3 days

    Load times and memory measured on mid-range hardware, before-and-after comparisons, and documentation so your team can run the pipeline without me.

Phases overlap in practice, and the ranges assume decisions arrive when they are needed. The one that slips most often is the first.

Proof

Work

The chair in the demo above

A 4.13 MB public domain GLB taken to 776 KB — an 81% reduction — with all four meshes, the material variants and the sheen extension intact, because the configurator addresses each part individually. A naive merge would have produced a smaller file and a broken demo. Full attribution and the exact command are recorded in the repository.

  • glTF-Transform
  • Meshopt
  • WebP
  • 81% smaller

Client projects I can show publicly are on the services page. Some work sits under NDA — ask on a call and I will say what I can.

F.A.Q

Frequently asked questions

How small does a 3D model need to be for a website?

For a single product on a page, somewhere between two and eight megabytes including textures is a reasonable target, and under a megabyte is achievable for simpler objects. But download size is only half of it: GPU memory is what actually crashes mobile tabs, and a texture set that downloads in 3 MB can occupy 90 MB once decoded. Budget both. The right target ultimately comes from what the page needs — a hero model that must appear immediately is a stricter budget than one behind a "launch" button.

Will optimizing make my product look worse?

It should not, and that is the standard worth holding a supplier to. Most of the reduction comes from textures sized for the screen rather than for print, geometry compressed rather than removed, and data that was never visible being deleted. Where appearance does change, it should be a decision made deliberately on one model and approved, not discovered across forty. Agreeing the acceptable difference at the start, side by side at real size, is the single thing that prevents this argument.

What is the difference between Draco and Meshopt?

Both compress glTF geometry. Draco generally produces smaller files; Meshopt decodes faster and its decoder is much smaller, which matters because the decoder is itself a download. If time-to-first-frame is the metric, Meshopt usually wins; if raw transfer size is the constraint, Draco often does. Either way the decoder must be wired into the loader, and forgetting that is a common cause of a model that opens fine in Blender and fails silently on the site.

KTX2 or WebP for textures?

WebP shrinks the download; KTX2 shrinks the download and what the GPU holds. WebP decodes natively everywhere and needs no extra setup, but expands to full RGBA in GPU memory once decoded, so it is fine for a modest texture budget and wrong for a heavy one. KTX2 with Basis Universal stays compressed on the GPU at roughly a quarter of the raw footprint, at the cost of serving a transcoder alongside the model. For anything texture-heavy or mobile-facing, KTX2 is the correct answer.

Do you need our CAD files, or can you work from an export?

Either, but the original source is usually faster to work from and produces a better result, because a lossy export has already thrown away the topology that makes retopologising straightforward. Native CAD generally needs a conversion step first. What matters most is knowing the tolerance the export was made at — manufacturing tolerance produces tessellation nobody needs on a screen, and re-exporting at a sensible tolerance sometimes solves most of the problem before any optimisation begins.

Can we do this ourselves?

For a single model with clean source files, quite possibly, and I would rather say so than sell you something you do not need. The tools are free and open source — glTF-Transform will do compression, resizing and pruning from the command line, and the GLB inspector on this site will show you what you are dealing with. Paying someone makes sense for a catalogue, for difficult source files, for CAD that needs real retopology, or where appearance is brand-critical and a visible degradation is not acceptable.

How many polygons is too many?

It is the wrong question more often than not. A 200,000-triangle mesh that renders in one draw call with compressed textures is entirely reasonable on the web, while a 20,000-triangle model split into 400 objects with 4K textures will struggle. Draw calls and texture memory are the limits that bite first. Attack textures, then draw calls, then triangle count — which is the reverse of the order most briefs assume.

Can you optimize a whole product catalogue?

Yes, and it should be approached as a pipeline rather than as many individual jobs. One representative model goes through by hand to establish the budget, the settings and the acceptable visual difference; that gets scripted; the rest run through it with spot checks and individual attention for awkward files. Say at the start that a catalogue is the goal, because building the pipeline after thirty hand-optimised models is the expensive way to arrive at the same place.

Send me the file that will not load

One representative model and a note on what it is for — a configurator, a product page, a headset — and I will tell you what it needs and roughly what that costs. If the answer is an afternoon with free tools, that is what you will hear.

Get In Touch

Let's talk about your project

Tell me what you're trying to build, big or small. I'll reply personally within 24 hours, usually same day.

I reply personally within 24 hours — usually same day.

Peter Csipkay

Peter Csipkay

Creative Frontend Developer

Let's connect

Three.js developer and creator of threejsresources.com. I scope, build, and ship the work myself — no middlemen, no handoffs.

Based in

Munich, Germany

Testimonials

What Clients Say

Don't just take my word for it — here's what people I've worked with have to say.

Peter is different from other front end developers. He understands design along with the tech stack. He successfully resolved bugs and optimized the webapp quickly. I appreciate his good work ethic. He is very logical and manages to capture ideas perfectly.
AhmedCEODubai, UAE
Amazing work with super fast turn around. I'm thrilled!
RobertFounder, 3D AgencyTampa, Florida
Peter is a great resource. I enjoyed working with him. I will definitely work with him again.
ThomasProduct LeadBerlin, Germany
Was a pleasure to work with. Very reliable and motivated to deliver great work. I can highly recommend him.
SarahMarketing ManagerLondon, UK

Keep reading

Related services

Free tools

Useful before you commission anything