acdream/src/AcDream.Core/Meshing
Erik 7b88fde52d fix(sky): drive wrap mode from mesh UV range — fixes Bug B (stars-as-square)
Bug B in docs/research/2026-04-26-sky-investigation-handoff.md: stars
rendered as a small square in one corner of the sky instead of stretching
across the dome.

Root cause: the wrap-mode heuristic at SkyRenderer.cs:234-237 was
"GL_CLAMP_TO_EDGE unless TexVelocity != 0". That heuristic was tuned to
fix a separate symptom (the outer dome 0x010015EE/F0/F1/F2 shows
wall-seam bleed under GL_REPEAT because of bilinear-filter sampling at
texel boundaries). But it misclassified any *static* sky object whose
mesh UVs are deliberately authored outside [0,1] to tile the texture
across the geometry.

The smoking gun: GfxObj 0x010015EF is OI-1 in EVERY DayGroup (always
loaded), has TexVelocity = 0 (no scrolling), and authors UVs in
[0.398, 4.602] (texture tiles ~4× across each face). Under
CLAMP_TO_EDGE the bulk of the inner dome sampled the texture's edge
texels; only the small region where UVs happened to fall in [0,1]
showed actual texture content. Hence "a square in one corner".

Fix:

* GfxObjMesh.Build() now scans the resulting per-vertex UVs and sets
  GfxObjSubMesh.NeedsUvRepeat true when any component lies outside
  [0,1]. Mesh-time scan, not draw-time guess.
* SubMeshGpu carries the flag through to draw time.
* SkyRenderer uses `sub.NeedsUvRepeat || obj.TexVelocity != 0` to
  decide REPEAT vs CLAMP_TO_EDGE. The dome (UVs in [0,1]) keeps
  CLAMP — no seam regression. The inner star/sky layer 0x010015EF
  (UVs outside [0,1]) gets REPEAT — texture tiles across the dome.
  Cloud meshes (UVs outside [0,1] AND non-zero TexVelocity) keep
  REPEAT via either branch.

Probe-driven: tools/StarsProbe (committed in 991fb9a) dumps every
SkyObject's geometry + UVs and flags meshes whose UV range exceeds
[0,1]. Run `dotnet run --project tools/StarsProbe -c Release` to
re-derive.

Verified visually by user against the live ACE server in Holtburg —
stars now stretch across the night sky instead of appearing as a
square in one corner. Build green, dotnet test 1222 pass.

Note: this is functionally retail-equivalent for the reported bug but
not the exact retail mechanism. Retail's GameSky::Draw at 0x00506ff0
relies on D3D's global default D3DTADDRESS_WRAP (i.e. REPEAT
everywhere). True retail-faithfulness would require investigating why
our pipeline shows seams on the dome under REPEAT (likely a bilinear
filter / non-seamless texture detail). The data-driven approach taken
here preserves working dome behavior while fixing the broken star
behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 22:55:24 +02:00
..
CellMesh.cs feat(net): Phase 6.6 — parse UpdateMotion (0xF74C) into MotionUpdated event 2026-04-11 20:33:26 +02:00
GfxObjMesh.cs fix(sky): drive wrap mode from mesh UV range — fixes Bug B (stars-as-square) 2026-04-26 22:55:24 +02:00
GfxObjSubMesh.cs fix(sky): drive wrap mode from mesh UV range — fixes Bug B (stars-as-square) 2026-04-26 22:55:24 +02:00
MotionResolver.cs fix(core+app): Phase 6.8 — keep NPCs animated when post-spawn motion update is unmappable 2026-04-12 00:05:23 +02:00
SetupMesh.cs fix(core): ACME cross-check fixes — normals, placement, scenery 2026-04-12 22:52:08 +02:00
TranslucencyKind.cs feat(net): Phase 6.6 — parse UpdateMotion (0xF74C) into MotionUpdated event 2026-04-11 20:33:26 +02:00