Skip to content

Texturing: make the keep-existing-UVs path reachable (and non-crashing once it is) - #173

Open
xocialize wants to merge 1 commit into
microsoft:mainfrom
xocialize:fix/texturing-uv-preserve
Open

Texturing: make the keep-existing-UVs path reachable (and non-crashing once it is)#173
xocialize wants to merge 1 commit into
microsoft:mainfrom
xocialize:fix/texturing-uv-preserve

Conversation

@xocialize

Copy link
Copy Markdown

Problem

Trellis2TexturingPipeline.postprocess_mesh implements a keep-existing-UVs branch, but it is unreachable via run(): preprocess_mesh rebuilds the mesh as trimesh.Trimesh(vertices=vertices, faces=mesh.faces, process=False) and drops mesh.visual, so by the time postprocess_mesh checks mesh.visual.uv, the UVs are always gone and every input falls into the uv-unwrap branch. The shipped "texture an existing mesh preserving its UVs" capability silently never engages.

Fix

  1. preprocess_mesh: pass visual=mesh.visual through the rebuilt Trimesh. The rebuild doesn't change vertex order (only positions), so per-vertex UVs remain valid.
  2. postprocess_mesh: copy vertices/faces/normals with np.array() up front. mesh.vertex_normals is a read-only trimesh cache, and the glTF axis swap at the end writes it in place (normals[:, 1], normals[:, 2] = ...). Today only the uv-unwrap branch runs, and it happens to replace normals with a fresh indexed array — so this second bug is latent until fix (1) makes the UV-preserve branch reachable, at which point it crashes. The two fixes belong in the same PR.

Evidence

With these changes, re-texturing an existing UV-mapped mesh preserves its UVs bit-identically — we measured max UV delta 0.0 between input and output in production use (Apple Silicon port work, https://github.com/xocialize/trellis2-apple).

🤖 Generated with Claude Code

- preprocess_mesh: carry mesh.visual through the rebuilt Trimesh. run()
  normalizes the mesh before postprocess_mesh ever sees it, so dropping
  the visual made the keep-existing-UVs branch unreachable via the
  public API. Vertex order is unchanged, so per-vertex UVs stay valid.
- postprocess_mesh: copy vertices/faces/normals up front. trimesh's
  vertex_normals cache is read-only and the glTF axis swap writes in
  place; only the uv-unwrap branch happened to replace these with fresh
  arrays.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant