Skip to content

Epic: Mesh quality — meshoptimizer-backed scan rules + fix-pipeline upgrade #678

Description

@fernandotonon

Overview

Once meshoptimizer lands as a dependency (via the parent AI-Assist epic #397, first consumer in #398 LOD generation), it unlocks a whole class of mesh-quality rules that qtmesh scan and qtmesh fix can apply without any ML — using the same battle-tested algorithms that glTF tooling, Godot, and Unity rely on for asset-import validation.

Today's scan rules (max_texture_resolution, require_uv_channels, detect_zero_weight_bones, detect_overlapping_uvs_pct, detect_non_manifold_edges_pct, redundant-keyframe analysis) cover textures, UVs, skeletons, animations, and topology. Mesh-buffer quality is the missing dimension — that's what this epic adds.

Why a separate epic

#397 is about AI-assisted authoring features (the user opts in per-task: "give me a LOD", "auto-unwrap UVs"). This epic is about automated quality validation — silent rules the scan pipeline applies to every asset, with corresponding --fix paths that are safe by default.

Different consumer (CI / qtmesh scan users in a pre-commit pipeline) and different cadence (rules ship together as one config-driven feature set), so a separate epic keeps the design pressure clean.

Child Issues (proposed)

Scan rules

  • detect_acmr — average cache miss ratio threshold. meshoptimizer's analyzeVertexCache gives ACMR; >2.0 flags a vertex buffer that doesn't reuse cached transforms efficiently. Common in meshes that came out of a sculpting tool without an export-time reorder pass.
  • detect_overdrawanalyzeOverdraw ratio threshold. Triangles drawn in an order that maximizes pixel overdraw waste fragment shader work.
  • detect_vertex_fetchanalyzeVertexFetch ratio threshold. Bytes fetched per vertex × overhead; identifies meshes with bad spatial locality.
  • detect_redundant_verts — vertices whose position + normal + UV exactly matches another but aren't welded. Surfaced by a weldVertices-then-diff pass.
  • detect_degenerate_tris — triangles with zero area or duplicate indices. Already partially covered by qtmesh fix but currently uses Ogre's heuristic; meshoptimizer's analysis is more precise.
  • max_triangle_count_per_submesh — soft per-submesh tri budget; flags meshes that should be split or LOD'd.

Fix actions

  • --fix optimize-vertex-cache — run optimizeVertexCache + optimizeVertexFetch on every submesh, write back. Lossless.
  • --fix optimize-overdrawoptimizeOverdraw with a configurable threshold (default 1.05). Lossless reorder.
  • --fix weld-redundantgenerateVertexRemap + remapVertexBuffer + remapIndexBuffer. Lossless dedupe.
  • --fix simplify — opt-in destructive simplification with simplifyWithAttributes to a configured target tri count (simplify_target_tris per submesh). Same meshoptimizer code path as the AI: meshoptimizer-backed LOD generation #398 LOD generator.

Reports

  • Per-submesh ACMR / overdraw / vertex-fetch metrics in scan --json output, comparable across runs (CI gating, asset-budget tracking).
  • Per-fix breadcrumb (Sentry category scan.fix.*) so usage analytics show which fixes users actually apply.

Acceptance Criteria

  • Every new rule respects the existing qtmesh.yml config schema (opt-in via numeric threshold, 0 = disabled).
  • Every new fix action has a --dry-run preview that lists what would change without writing.
  • qtmesh scan ./assets --json shape extends to include the new metrics under a mesh_quality block.
  • Unit tests use the existing in-memory mesh harness (no fixture files for new rules).
  • Sentry breadcrumbs for every rule firing + every fix applied.
  • Docs page on the website covers each new rule with before/after numbers.

Dependencies

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions