Skip to content

SceneOps: Slice B — Move submesh between meshes #625

Description

@fernandotonon

Parent epic: #623

Goal

Move a submesh from mesh A to mesh B with material, vertex format, and bone-binding preservation. Drag-and-drop in the scene tree; right-click → "Move to mesh…" alternative.

Scope

  • New static helper SubMeshOps::moveSubMesh(srcMesh, srcSubIdx, targetMesh, *errorMsg) -> bool.
  • Vertex format reconciliation (the hard part):
    • If source and target share the exact vertex declaration: copy buffers directly.
    • If declarations differ: re-encode the source submesh into the target's declaration. Common cases:
      • Source has tangents, target doesn't → drop tangents.
      • Target has UV1, source doesn't → fill UV1 with zeros.
      • Vertex-colour mismatch → fill with white.
    • If source is skinned and target is static → reject with a clear error message; offer "convert to static" as a follow-up CLI.
    • If both are skinned but the skeletons differ → reject. (Skeleton retargeting belongs in Anim: Slice F — Animation retargeting between skeletons #523.)
    • If skeletons match by name → reuse bone handles directly.
  • Material: copies the source material name to the target's submesh. If the material isn't in the target's resource group, register it via the existing material resource path.
  • Mesh::SubMeshNameMap updated on both meshes.
  • Mesh reload: rebuild affected entities so the scene reflects the new submesh structure (Entity::_setMesh if available; otherwise destroy + recreate the entity preserving its scene node).
  • UI:
    • Drag a SubEntity row in qml/SceneTreeNode.qml, drop onto another Entity row → triggers move.
    • Visual feedback during drag: highlight valid drop targets in green, invalid in red. Tooltip on hover explains why a target is invalid.
    • Context menu "Move to mesh…" opens a small picker dialog listing every valid target entity.
  • Undo: MoveSubMeshCommand that captures the full source-mesh state pre-move (including the vertex data) so undo is byte-exact.
  • Multi-select: if multiple submeshes are dragged from the same mesh, move them all in one command.

Acceptance Criteria

  • Drag-and-drop moves a submesh between two compatible meshes.
  • Reconciliation handles tangent / UV1 / vertex-colour mismatches without crashing.
  • Skinned-source / static-target combination is rejected with a clear message.
  • Skinned move with matching skeleton preserves deformation correctly.
  • Material follows the submesh.
  • Both meshes' SubMeshNameMap are correct after the move.
  • Undo restores both meshes byte-exactly.
  • Multi-submesh drag moves all in one undo step.
  • glTF + FBX round-trip preserves the new submesh layout.
  • Sentry breadcrumb mesh.submesh.move with {srcMesh, dstMesh, subIndex}.
  • Headless-CI test on a 2-mesh fixture covering: equal-decl move, declaration mismatch, skinned move, reject cases.

Effort

~9 days. Vertex declaration reconciliation is the schedule risk.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestscene-treeScene tree, submeshes, hierarchy operations

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions