Texture displacement: per-layer bake, UV pane redesign, unwrap and layer view fixes

- Bake: each layer is sampled only on its own painted area; analytic
  projections used to stack every layer over every painted region, so the
  top layer's texture showed on all of them (colour sampler too)
- Auto resolution follows the texture's texel size and sharpness again
- Unwrap: charts cut by each face's own normal (a cube gives 6 islands, not
  12 triangles); non-disk charts (tubes, closed shells) are split until they
  flatten; connected nets test real triangle overlap, grow from the largest
  chart and are packed side by side
- UV edits are stored per unwrapped copy, so dragging a seam vertex no
  longer moves its copies in neighbouring islands
- UV pane: tool strip with unwrap settings moved in from the panel, sharp
  HiDPI icons, clearer island/edge/selection drawing with hover, texture
  picker from the thumbnail, texture no longer lost on reopen (GL state
  from the 3D view, background upload retries)
- Panel: whole-model select/erase as icons in the tools row; inactive
  layers' paint shown muted; colour textures shown in colour in the picker
- Built-in displacement texture library
- Tests for unwrap segmentation, connected nets, UV edits and per-layer
  sampling
This commit is contained in:
ExPikaPaka
2026-09-21 08:59:26 +02:00
parent b5ae632bd7
commit cef6527f9d
52 changed files with 2561 additions and 355 deletions
@@ -98,7 +98,7 @@ struct HeapEntry
DecimateResult decimate(const TriSoup &geometry, size_t target_triangles, bool harvest_flat,
double harvest_tol, const std::vector<uint8_t> &locked_faces,
const DecimateProgressFn &on_progress)
const DecimateProgressFn &on_progress, const std::vector<int> &face_color)
{
DecimateResult result;
const size_t n = geometry.pos.size();
@@ -211,8 +211,10 @@ DecimateResult decimate(const TriSoup &geometry, size_t target_triangles, bool h
faces[size_t(er.f0) * 3 + 2]);
const Vec3d n1 = face_normal_unit(pos, faces[size_t(er.f1) * 3], faces[size_t(er.f1) * 3 + 1],
faces[size_t(er.f1) * 3 + 2]);
if (n0.dot(n1) >= DECIMATE_CREASE_COS)
continue; // smooth enough to be no crease
const bool color_edge = face_color.size() > std::max(size_t(er.f0), size_t(er.f1)) &&
face_color[size_t(er.f0)] != face_color[size_t(er.f1)];
if (!color_edge && n0.dot(n1) >= DECIMATE_CREASE_COS)
continue; // smooth enough to be no crease, and no colour changes across it
const Vec3d e = pos[size_t(er.vb)] - pos[size_t(er.va)];
const double elen = e.norm();