Skip to content

Epic: UV — UV Map editing #458

Description

@fernandotonon

Overview

QtMeshEditor can read and write UV coordinates today (EditableMesh::setVertexUV/getVertexUV at src/EditableMesh.h:518, full UV0 round-trip through MeshImporterExporter, the FBX exporter, and the validator), but there is no way for a user to view or edit the UV layout in the editor. The only UV-related feature on the roadmap right now is auto-unwrap (#400, xatlas).

This epic plans a proper UV editor: a 2D panel where the user can see the UV islands of the active selection, select UV components, transform them (move/rotate/scale, with snapping and pinning), seam/sew along edges, project from view/camera/box/cylinder/sphere, pack islands, and switch between UV channels — fully integrated with the existing Edit Mode, undo system, and CLI/MCP surfaces.

This is a GUI-led epic (most value lives in the interactive panel), but each meaningful operation must also be exposed via CLI and MCP to match project conventions.

Why

  • Auto-unwrap (AI: xatlas auto-UV unwrap (qtmesh uv --unwrap) #400) gets users a starting layout, but real workflows need manual cleanup: rotating shells, scaling for texel density, fixing overlaps, marking seams, pinning verts before re-unwrap.
  • Mesh-aware texture generation (AI: Mesh-aware texture generation (depth-conditioned sd.cpp) #403) and PBR map synthesis (AI: PBR map synthesis from albedo (DeepBump-style, ONNX) #404) both depend on a clean UV layout. Without an editor, users have to round-trip through Blender — defeating the offline single-binary value prop of QtMeshEditor.
  • The infrastructure is mostly already there: EditableMesh exposes per-vertex UVs, HalfEdgeMesh provides adjacency, the EditModeController already manages Vertex/Edge/Face component selection, and the QML inspector + Tab-mode toggle are reference patterns. The missing piece is the 2D viewport and the UV-specific selection/transform layer.

Architecture

A new singleton, UVEditorController (mirrors EditModeController and PropertiesPanelController):

  • Owns the UV editor's selection state (UV-vertex / UV-edge / UV-face), independent from the 3D component selection but kept in sync when desired.
  • Reads/writes through EditableMesh::setVertexUV/getVertexUV. Source of truth remains EditableMesh.
  • Uses HalfEdgeMesh to detect UV islands, seams, and boundary loops.
  • Pushes a single UVEditCommand per operation onto the existing UndoManager (Ctrl+Z/Ctrl+Shift+Z).
  • Exposes the active UV channel (UV0/UV1) so existing MaterialEditorQML::setTexCoordSet integration is consistent.

The 2D panel is a new QML view, UVEditorPanel.qml, hosted as a dock (similar to the Animation Control dock pattern). Renders via Canvas2D or QQuickPaintedItem for v1 — no GL conflicts with Ogre, matching the ViewCube precedent. Optional GL renderer is a stretch goal.

UV-specific component selection should not collide with the 3D Edit Mode selection. When the UV panel has focus, 1/2/3 switch UV-vertex/UV-edge/UV-face; otherwise the 3D Edit Mode keeps current behavior.

Child Issues

Slices A–C are minimum viable; D–F bring the editor up to par with Blender/Maya UV workflows; G is polish.

Acceptance Criteria (epic-level)

  • User can open the UV editor panel from the View menu and a toolbar button.
  • User can see UV islands for the current selection with a clear 0–1 reference grid and (optionally) the active diffuse as background.
  • User can select UV vertices / edges / faces and translate, rotate, scale them with snapping.
  • User can mark and clear seams and re-unwrap selected faces respecting seams and pins.
  • All UV edits go through UndoManager and round-trip through Ctrl+Z without corruption.
  • MeshImporterExporter round-trip (load → edit UVs → save → load) preserves the edited layout for at least FBX and glTF.
  • No regression in 3D Edit Mode shortcuts when the UV panel is open but unfocused.
  • MaterialEditorQML's tex-coord-set selection stays in sync with the UV editor's active channel.
  • CLI and MCP cover at least uv_info, uv_pack, and uv_unwrap_selection.
  • Documentation in CLAUDE.md updated.

Dependencies & related issues

Out of scope

  • 3D-painting/UV-painting on the mesh (Substance-Painter style). Different epic.
  • UV1 light-map authoring tools beyond a channel picker. The plumbing is generic enough that UV1 editing works, but light-map-specific helpers (margin per atlas size, charting per Lightmass conventions) are out of scope here.
  • Per-face material splits in UV space. Already handled by sub-mesh splitting in 3D Edit Mode.

Notes for implementers

  • The 2D panel should use software/Canvas2D rendering for v1 to avoid GL conflicts with Ogre, the same constraint already applied to the QML inspector and ViewCube.
  • Reuse EditableMesh and HalfEdgeMesh rather than building a parallel data structure. Compute islands lazily and cache by EditableMesh revision.
  • A single UVEditCommand per operation, not one per vertex — follow the EditMeshTopologyCommand precedent.
  • Selection state is panel-local. Optional sync to 3D Edit Mode selection lives behind a toggle.
  • Keep all new shortcuts inside the panel scope so Unity-convention 3D shortcuts (Q/W/E/R/F/X) remain untouched globally.
  • Each slice should be a separate PR with screenshots, matching the slice-A→slice-G PR style already used in Phase 5.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions