Designing an Automatic Mesh Optimization Pipeline
Build a deterministic optimization service with preflight classification, candidate ladders, constraint profiles, visual gates, provenance, and review routing.
Automatic mesh optimization is a decision system, not a command applied to every file. It must determine what an asset contains, which operations are safe, how far reduction can proceed, whether the output still satisfies its role, and when a human must decide.
The most important output is not always a smaller GLB. Sometimes it is an explicit refusal: “animated morph targets are unsupported by this profile,” “the mesh cannot reach 15% without crossing the silhouette gate,” or “source topology must be repaired.” Silent damage is automation failure.
Define the service contract#
Specify inputs beyond a file path:
- target platform and viewer profile;
- maximum and typical screen size;
- closest camera distance and viewing envelope;
- physical scale and tolerance;
- static, skinned, morphing, or instanced role;
- protected components and material regions;
- transfer, memory, draw, triangle, and frame targets;
- required extensions and compatibility;
- quality tier or product class.
If callers provide only “make it 1 MB,” the service lacks enough information to value geometry versus texture, close detail versus background use, or broad compatibility versus codec size.
Return a typed result: passed output, passed-with-warnings output, review-required candidates, unsupported input, or processing failure. Include machine-readable reasons.
Preserve immutable source and provenance#
Every run starts from the original approved source or a named canonical intermediate. Never run the optimizer repeatedly on its last output. Lossy simplification, quantization, and image compression compound.
Assign:
- source content hash;
- source asset and revision ID;
- pipeline version;
- tool and dependency versions;
- profile name and version;
- normalized parameter set;
- run timestamp and environment;
- output hashes;
- report schema version.
The artifact name alone is not provenance. A file called chair_optimized_final.glb cannot explain whether it used 12-bit or 16-bit positions or which image quality threshold passed.
Keep the exact source, outputs, logs, metrics, and review decision together. A production database can reference immutable object storage by hash.
Preflight before mutation#
Parse and validate the GLB. Inventory:
- scenes, nodes, meshes, primitives, and materials;
- triangles, rendered vertices, and attributes;
- skins, animations, and morph targets;
- images, dimensions, formats, channels, and references;
- extension requirements;
- bounds, units, and transform anomalies;
- connected components and topology findings;
- UV sets, seams, overlaps, and tangent availability;
- opaque, masked, blended, and double-sided state.
Classify risks. A static manifold prop with one material can enter a standard path. A skinned face with 52 morph targets needs a profile that preserves and evaluates those attributes. A non-manifold scan can enter a repair/reconstruction path or require review.
Reject malformed binary ranges, invalid accessors, impossible counts, non-finite values, and unsupported required extensions. A robust service limits input bytes, dimensions, node count, and processing time to prevent resource exhaustion.
Normalize only what the profile authorizes#
Safe mechanical cleanup may include removing unreachable resources, exact duplicate accessors, zero-area faces, and unused material slots. Even these need reports.
Potentially destructive normalization includes:
- applying transforms;
- joining components;
- welding near positions;
- filling holes;
- recalculating normals;
- repacking UVs;
- converting materials;
- stripping animation channels.
Run such changes only under an asset-class policy. Applying negative scale changes winding. Welding 0.001 units means 1 millimeter in meter scale. Filling every boundary can close designed vents.
After each stage, validate invariants and record count deltas. If cleanup removes 40% of faces, route to review even if the result is structurally valid.
Use versioned profiles, not magic presets#
A profile might be “web-product-v3” and define:
- unrestricted horizontal orbit, elevation −10° to 60°;
- 1200-pixel maximum model height;
- required preservation of named material regions;
- candidate ratios 75%, 50%, 30%, 18%, 10%;
- position error ceiling 0.5 millimeters;
- contour p95 below 0.5 pixel;
- KHR_mesh_quantization and EXT_meshopt_compression allowed;
- KTX2 preferred with PNG/JPEG fallback policy;
- maximum 8 primitives and 6 initial images;
- animation unsupported.
The profile is code and data under review. Changing a threshold creates a new version. Old outputs remain reproducible.
Separate policy from tool syntax. A desired 0.5-millimeter error may map to different options in Blender, meshoptimizer, or CGAL. Adapter tests confirm equivalence.
Generate a candidate ladder#
One requested ratio gives no information about the quality cliff. Generate a coarse ladder, evaluate it, then refine near the last pass.
Example search:
- source baseline at 100%;
- candidates at 60%, 30%, 15%, and 7.5%;
- if 30% passes and 15% fails, try 24%, 21%, and 18%;
- retain the smallest passing geometry candidate;
- combine it with texture and codec candidates;
- choose the lowest-cost complete artifact that passes all gates.
Do not assume ratio ordering guarantees perceptual ordering if settings differ. Keep topology and attribute policies identical during the search.
Candidate generation can stop early when hard constraints saturate or error exceeds a monotonic-safe bound. Some image metrics are noisy, so retain enough neighbors for confirmation.
Optimize geometry and textures as separate axes#
A full cross product of 8 geometry levels, 6 texture profiles, and 3 codecs creates 144 candidates. Use the inventory to prune.
If images are 85% of transfer, test texture resolution and encoding early while holding geometry. If geometry dominates runtime, find the smallest passing mesh first. Then evaluate a small matrix of compatible complete outputs.
Keep quality attribution possible:
- geometry-only candidate with source images;
- texture-only candidate with source geometry;
- combined candidate;
- encoding-only candidate from the combined data.
This reveals whether an observed rough highlight came from normals, normal-map resizing, or codec quantization.
Enforce topology and attribute constraints during reduction#
Reject candidate operations or outputs that violate profile rules:
- non-manifold topology introduced;
- named boundary or hole lost;
- component count changed unexpectedly;
- triangle flips or degenerates;
- UV triangle flips or disallowed overlap;
- critical material region removed;
- skin or morph channel unsupported;
- normal deviation beyond threshold;
- position outside a geometric envelope.
Post-validation alone may find damage too late. Integrate constraints into simplification when the library supports it, then rerun structural checks on the output.
If the target cannot be reached, return the limiting constraints and best passing candidate. “Stopped at 22,418 triangles because 96% of remaining candidates touch locked boundaries” is actionable.
Visual validation must be deterministic#
Store camera matrices, viewport, environment, exposure, material overrides, pose samples, background, random seeds, and renderer version.
Render source and candidate passes:
- binary masks;
- depth;
- normals;
- UV checker;
- glossy diagnostic;
- production material;
- material IDs;
- animation or LOD transition frames.
Calculate contour, surface, normal, UV, and image metrics. Use hard gates for named features and local errors before global averages.
GPU rendering can vary by driver. Allow small numeric tolerance, but investigate systematic changes. A CPU reference raster for masks and simple attributes can stabilize some gates; production screenshots remain necessary.
Human review routing#
Automation should rank risk:
- candidates within 10% of a hard threshold;
- assets with thin components or many small material regions;
- topology cleanup above a count threshold;
- largest screen-space differences;
- unsupported or approximated material extensions;
- new asset classes without established profiles;
- nondeterministic output hashes;
- disagreement among metrics.
Generate a review package, not a folder of files. Include a synchronized source/candidate viewer, difference overlays, worst-camera shortcuts, metrics, and proposed decision.
Reviewer choices should be approve, choose a less aggressive candidate, edit constraints and rerun, repair source, or reject. Save identity, timestamp, comment, and exact hashes.
Determinism and idempotence#
Given the same source hash, profile, and tool versions, outputs should ideally have the same bytes. Sources of nondeterminism include unordered map iteration, equal-cost edge ties, parallel reduction order, random sampling, timestamps embedded in files, and image encoders.
Control random seeds and stable sorting. Strip irrelevant timestamps. If a library remains nondeterministic, define metric-level reproducibility and log that limitation.
Idempotence means the pipeline recognizes an already produced artifact and does not optimize it again accidentally. It should resolve provenance to the canonical source or reject derived input under a source-only endpoint.
Run the same job 5 times in CI and compare hashes or decoded content. Nondeterminism makes caching, diffs, and rollback harder.
Concurrency and resource control#
High-density assets can consume large memory and CPU. Isolate jobs and set limits:
- maximum input and expanded bytes;
- maximum image dimensions and pixel total;
- maximum vertices, faces, nodes, and animation samples;
- wall-clock and CPU timeout;
- process memory ceiling;
- bounded worker concurrency;
- temporary storage quota;
- cancellation and cleanup behavior.
Ten simultaneous 4096 image decodes can exhaust memory even when each job passes alone. Schedule by estimated weight, not only job count.
Use content-addressed caching for validated intermediate results. Do not share mutable temp paths between jobs. Treat untrusted model files as hostile input and sandbox parsers where practical.
Reports as a product surface#
Return a concise summary plus detailed data:
- initial and final bytes by component;
- initial and final geometry and scene counts;
- decoded-memory estimates;
- processing duration by stage;
- every warning and skipped operation;
- quality metrics and worst locations;
- compatibility extensions;
- toolchain and profile versions;
- accepted tradeoffs;
- direct references to source and candidate artifacts.
Avoid claiming “90% optimized.” State “transfer −68%, triangles −74%, texture estimate −50%, contour p95 0.32 pixels, passed web-product-v3.”
Reports feed analytics. Aggregate which gate blocks the most assets, which profiles produce review, and where processing fails. That evidence guides product improvements.
Store stage-level exit codes rather than one generic failure. A parser rejection, topology constraint stop, renderer timeout, and artifact-upload failure need different retries and owners. Retrying a deterministic unsupported asset wastes capacity; retrying a temporary storage error can succeed. Expose sanitized user-facing guidance while retaining internal diagnostics and correlation IDs. Any report derived from an untrusted filename or metadata field must be escaped before HTML rendering. Automation quality includes predictable failure behavior, not only the successful path.
Document those failure contracts for every supported profile.
Regression corpus#
Maintain representative and adversarial fixtures:
- clean manifold hard-surface prop;
- noisy photogrammetry scan;
- many UV islands;
- mirrored normal map;
- small material features;
- skinned character;
- morph-heavy face;
- multiple disconnected thin components;
- invalid and non-finite input;
- very large but allowed asset.
Store expected status and metric ranges, not just snapshots. A tool upgrade can improve bytes legitimately while changing exact output. Review any quality or compatibility movement.
Include previously failed production assets after sanitization. Real edge cases are more valuable than synthetic cubes alone.
Deployment and rollback#
Run new profiles in shadow mode against existing sources. Compare outputs without replacing production. Canary a small asset cohort, monitor load failures and visual reports, then expand.
Production pointers should reference immutable output versions. Rollback changes the pointer; it does not attempt to reverse lossy processing.
If the service feeds a database, update an asset only after artifact upload, validation, report persistence, and transaction checks succeed. Never leave metadata pointing to an incomplete object.
Pipeline checklist#
- Callers provide platform, camera, and quality intent.
- Canonical source and provenance are immutable.
- Preflight rejects unsafe and unsupported input explicitly.
- Every destructive cleanup operation is profile-authorized.
- Profiles are versioned independently of tool syntax.
- Candidate ladders search for the quality cliff.
- Geometry, texture, material, and codec effects remain attributable.
- Topology and attribute constraints apply during and after processing.
- Render fixtures and metric seeds are deterministic.
- Risk-ranked outputs route to a complete human review package.
- Jobs have memory, time, concurrency, and untrusted-input controls.
- Production artifacts are immutable and instantly rollbackable.
Sources and further reading#
- Khronos glTF Validator
- Khronos glTF Asset Auditor
- meshoptimizer repository
- glTF Transform documentation
- CGAL: surface mesh simplification
Automatic optimization is trustworthy when it can explain every mutation, prove each output against the asset's declared use, and decline work it cannot perform safely. The pipeline's job is controlled evidence, not merely smaller files.