docs(issues): file #48 — subset of tree species hover above terrain
A few specific scenery GfxObjs render with their trunk base ~0.5-1.5m above the terrain mesh while the vast majority sit flush. Per-GfxObj- id ⇒ deterministic across instances. Player Z snap is unaffected. Side-by-side with retail confirmed the same species place flush there. Filed with three competing hypotheses: per-GfxObj origin convention (some tree meshes authored with origin at bbox-center vs trunk-base), physics-vs-bilinear terrain Z mismatch on NE↔SW-cut cells, or the same DIDDegrade close-detail story as #47 applied to scenery. Detailed cut-and-paste handoff for the next agent at docs/research/2026-05-06-issue-48-handoff.md — covers the diagnostic dump that disambiguates the hypotheses with one log line per offending tree. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
50da2bb81d
commit
0d3b85dd69
2 changed files with 405 additions and 0 deletions
102
docs/ISSUES.md
102
docs/ISSUES.md
|
|
@ -46,6 +46,108 @@ Copy this block when adding a new issue:
|
|||
|
||||
# Active issues
|
||||
|
||||
## #48 — A few specific scenery trees hover above terrain (per-GfxObj Z misplacement)
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** LOW (cosmetic; ~3 trees per landblock, easy to ignore but obvious once spotted)
|
||||
**Filed:** 2026-05-06
|
||||
**Component:** rendering / scenery placement / terrain Z sampling
|
||||
|
||||
**Description:** In outdoor landblocks, a small subset of tree
|
||||
scenery instances render visibly **floating above the terrain**
|
||||
(trunk base ~0.5–1.5 m above the ground line). The vast majority
|
||||
of scenery (other tree species, bushes, rocks) sits flush. The bug
|
||||
is **per-GfxObj-id**: the same handful of species float wherever
|
||||
they spawn; other species at the same (x, y) cell sit correctly.
|
||||
Side-by-side with retail in the same area: retail places the same
|
||||
species flush. User-confirmed via screenshot pair 2026-05-06.
|
||||
|
||||
The user noted this is the only thing left wrong with terrain
|
||||
rendering (canopy density / shape were *not* the issue — those
|
||||
match retail when looked at carefully). The bug is purely vertical
|
||||
offset on a few species.
|
||||
|
||||
**Investigation 2026-05-06:**
|
||||
|
||||
[`SceneryGenerator.cs:204`](src/AcDream.Core/World/SceneryGenerator.cs:204)
|
||||
returns `LocalPosition.Z = obj.BaseLoc.Origin.Z` (just the
|
||||
ObjectDesc's BaseLoc Z offset, no terrain). [`GameWindow.cs:4642`](src/AcDream.App/Rendering/GameWindow.cs:4642)
|
||||
adds the terrain ground Z:
|
||||
|
||||
```csharp
|
||||
float groundZ = _physicsEngine.SampleTerrainZ(worldPx, worldPy)
|
||||
?? SampleTerrainZ(lb.Heightmap, _heightTable, localX, localY);
|
||||
float finalZ = groundZ + spawn.LocalPosition.Z;
|
||||
```
|
||||
|
||||
Both samplers claim to use the AC2D split-direction terrain mesh
|
||||
formula. Player feet land flush, so player Z sampling is correct;
|
||||
scenery for most species is also flush; only specific GfxObjs
|
||||
float.
|
||||
|
||||
**Three competing hypotheses (need one diagnostic to disambiguate):**
|
||||
|
||||
1. **Per-GfxObj origin convention.** Most AC tree GfxObjs are
|
||||
authored with local origin at the trunk base (mesh vertices
|
||||
have `Z >= 0` measured up from the origin). A few species
|
||||
may be authored with origin at bbox-center or visual top —
|
||||
for those, `finalZ = groundZ + BaseLoc.Z` plants the *center*
|
||||
at ground and the visible trunk floats by half its height.
|
||||
Per-GfxObj-id ⇒ deterministic across instances ⇒ fits the
|
||||
"same 3 species everywhere" pattern.
|
||||
|
||||
2. **Physics-sampler vs bilinear-fallback Z mismatch on
|
||||
NE↔SW-cut cells.** The physics path uses the AC2D
|
||||
split-direction formula. The bilinear-fallback at
|
||||
`GameWindow.cs:4643` uses naive bilinear over heightmap
|
||||
corners — wrong on cells whose visible triangle slopes
|
||||
the *other* way. If physics hasn't registered a landblock
|
||||
yet when scenery hydrates (timing race), affected scenery
|
||||
uses the bilinear sampler and lands on a different Z than
|
||||
the visible terrain. Player Z is fine because player movement
|
||||
always goes through the physics sampler.
|
||||
|
||||
3. **Same close-degrade story as #47, applied to scenery.** Some
|
||||
tree GfxObjs have `DIDDegrade` tables; slot 0 (close-detail)
|
||||
and the base-LOD-3 mesh may have different mesh-local origins.
|
||||
We currently draw the base GfxObj id directly for scenery (the
|
||||
close-degrade resolver is scoped to humanoid setups only).
|
||||
Retail draws slot 0 for nearby trees. If slot-0 has origin at
|
||||
trunk-base while base-LOD-3 has origin at bbox-center, those
|
||||
species float by exactly the offset between the two origins.
|
||||
|
||||
**Cheapest first move:** add a one-shot scenery placement dump
|
||||
gated by `ACDREAM_DUMP_SCENERY_Z=1` that logs, per spawn:
|
||||
|
||||
```
|
||||
[scenery-z] gfxObj=0xXXXXXXXX setupOrGfx=… worldPos=(x,y,z)
|
||||
BaseLoc.Z=… groundZ=… meshZRange=[zMin..zMax]
|
||||
hasDIDDegrade=true/false degrades[0]=0xXX
|
||||
```
|
||||
|
||||
User identifies one floating tree → grep that GfxObj id in the
|
||||
log → look at meshZRange and `hasDIDDegrade`. That tells us
|
||||
hypothesis 1 (zMin > 0 by the float amount), hypothesis 2 (matching
|
||||
species correctly placed elsewhere → timing race), or hypothesis 3
|
||||
(`hasDIDDegrade=true` and slot 0 mesh has different zMin). One log
|
||||
sample answers the question.
|
||||
|
||||
**Files:**
|
||||
|
||||
- [`src/AcDream.Core/World/SceneryGenerator.cs:204`](src/AcDream.Core/World/SceneryGenerator.cs:204) — BaseLoc.Z passthrough
|
||||
- [`src/AcDream.App/Rendering/GameWindow.cs:4632-4655`](src/AcDream.App/Rendering/GameWindow.cs:4632) — groundZ resolution + finalZ assembly
|
||||
- [`src/AcDream.Core/Physics/TerrainSurface.cs`](src/AcDream.Core/Physics/TerrainSurface.cs) — physics sampler (AC2D split-direction formula)
|
||||
- `SampleTerrainZ` (private, in GameWindow.cs) — bilinear fallback
|
||||
- [`src/AcDream.Core/Meshing/GfxObjDegradeResolver.cs`](src/AcDream.Core/Meshing/GfxObjDegradeResolver.cs) — close-degrade resolver if hypothesis 3 confirmed; would need scenery-scope expansion (drop the `IsIssue47HumanoidSetup` gate or add a scenery-aware variant)
|
||||
|
||||
**Acceptance:** All scenery species rest flush on the visible
|
||||
terrain mesh in side-by-side outdoor screenshots vs retail. No
|
||||
regression on the species that already render correctly.
|
||||
|
||||
**Handoff:** [docs/research/2026-05-06-issue-48-handoff.md](docs/research/2026-05-06-issue-48-handoff.md)
|
||||
|
||||
---
|
||||
|
||||
## #39 — Run↔Walk cycle transition not visible on observed player remotes (acdream-as-observer)
|
||||
|
||||
**Status:** OPEN
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue