fix(rendering): #47 — walk DIDDegrade for retail close-detail meshes

Humanoid bodies (Setup 0x02000001 + heritage variants) rendered visibly
flat / bulky vs retail because we drew the base GfxObj id from Setup /
AnimPartChange directly. Retail's CPhysicsPart::LoadGfxObjArray
(0x0050DCF0) treats that base id as the entry point to a DIDDegrade
table; close/player rendering uses Degrades[0].Id, which is the
higher-detail mesh that carries bicep / deltoid / shoulder geometry.

ACViewer also has this bug — it was the key signal it isn't acdream-
specific. Both clients drew the LOD-3 base mesh (e.g. 14 verts / 17
polys for Aluvian Male upper arm 0x01000055), missing the close-
detail variant (0x01001795: 32 verts / 60 polys).

Adds GfxObjDegradeResolver that walks the table with safe fallbacks
at every step. Wired in GameWindow after AnimPartChange application
and before texture-change resolution so texture overrides match the
resolved mesh's surfaces. Gated by ACDREAM_RETAIL_CLOSE_DEGRADES=1
and scoped to humanoid setups (34 parts with >=8 null-sentinel
attachment slots) while the fix bakes — the change is harmless on
non-humanoid setups (resolver falls back to base when no degrade
table) but we hold the broader sweep until LOD distance plumbing
lands.

User confirmed visually 2026-05-06: bicep, deltoid, and back-muscle
definition match retail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-06 16:46:23 +02:00
parent 8d7cad5b14
commit 0bd9b9693b
5 changed files with 648 additions and 2 deletions

View file

@ -1258,13 +1258,42 @@ If hypothesis (a) is correct, this issue effectively rolls into **#28** — the
---
## #47 — Humanoid Setup 0x02000001 renders bulky / lacks shape detail vs retail
## #47 [DONE 2026-05-06] Humanoid Setup 0x02000001 renders bulky / lacks shape detail vs retail
**Status:** OPEN
**Status:** DONE (commit pending)
**Closed:** 2026-05-06
**Severity:** MEDIUM (cosmetic — characters readable but visibly different from retail)
**Filed:** 2026-05-06
**Component:** rendering / mesh / character animation
**Resolution:** Root cause was that we drew the base GfxObj id from
Setup / `AnimPartChange` directly. Retail's `CPhysicsPart::LoadGfxObjArray`
(`0x0050DCF0`) treats that base id as an **entry point to the
`DIDDegrade` table**; for close/player rendering it draws
`Degrades[0].Id`, which is the higher-detail mesh that carries the
bicep / deltoid / shoulder geometry. ACViewer also has this bug —
that was the key signal it wasn't acdream-specific.
Concrete swaps the resolver now performs:
- Aluvian Male upper arm `0x01000055``0x01001795` (14/17 → 32/60 verts/polys)
- Aluvian Male lower arm `0x01000056``0x0100178F`
- Heritage variants: `0x010004BF → 0x010017A8`, `0x010004BD → 0x010017A7`,
`0x010004B7 → 0x0100179A`, etc.
Fix landed as `GfxObjDegradeResolver`, gated behind
`ACDREAM_RETAIL_CLOSE_DEGRADES=1` and scoped to humanoid setups
(34-part with ≥8 null-sentinel attachment slots). User confirmed
visually 2026-05-06.
Files: `src/AcDream.Core/Meshing/GfxObjDegradeResolver.cs`,
`src/AcDream.App/Rendering/GameWindow.cs` (wiring), 5 unit tests in
`tests/AcDream.Core.Tests/Meshing/GfxObjDegradeResolverTests.cs`.
Research note: `docs/research/2026-05-06-issue-47-close-degrade-pseudocode.md`.
---
### Original investigation (kept for reference)
**Description:** Every humanoid character using Setup `0x02000001`
(Aluvian Male) renders in acdream with a "bulky, less-defined" silhouette
compared to retail's view of the same character. Specifically: shoulders