docs(issues): file #47 (humanoid bulky-shape bug); land DUMP_CLOTHING diagnostics
Filed #47 in docs/ISSUES.md — humanoid characters using Setup 0x02000001
(players + Woodsman + other Aluvian NPCs) render visibly bulkier and less
shape-defined than retail's view. Drudges and other monster setups render
identically. Independent of equipment (naked +Je still shows it).
Investigation this session ruled out 0xF625 ObjDescEvent drops (real bug,
fixed in e471527, but doesn't explain shape), HiddenParts overlap,
ParentIndex walking (animation frames are setup-root coords already),
and player-specific data flow (NPCs using same setup affected too).
Diagnostic infrastructure landed alongside the issue (env-var-gated, no
runtime cost when off):
- ACDREAM_DUMP_CLOTHING=1 now also prints:
- setup.Parts.Count, flatten.Count, APC count on header
- ParentIndex[] and DefaultScale[] arrays
- IdleFrame per-part Origin + Orientation (first 17 parts)
- per-part EMIT line: gfx, subMeshes count, triangle count
- TOTAL triangle / meshRef counts per entity
This is what nailed down "all 34 parts emit" + "animation frames are
setup-root not parent-local" + "humans get setup-wide 180°-Z rotation
that drudges don't" — saved hours next session.
Open hypotheses for #47 next session: per-face vs smoothed vertex
normals (per-vertex normals from dat may be face-style for human
GfxObjs but smooth for monsters), low cell ambient leaving back faces
flat-shadowed, missing MSAA on the GL window.
This commit is contained in:
parent
e471527924
commit
e697a9ad1e
2 changed files with 125 additions and 0 deletions
|
|
@ -1258,6 +1258,104 @@ If hypothesis (a) is correct, this issue effectively rolls into **#28** — the
|
|||
|
||||
---
|
||||
|
||||
## #47 — Humanoid Setup 0x02000001 renders bulky / lacks shape detail vs retail
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM (cosmetic — characters readable but visibly different from retail)
|
||||
**Filed:** 2026-05-06
|
||||
**Component:** rendering / mesh / character animation
|
||||
|
||||
**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
|
||||
look smoother/rounder where retail has pointier shoulder pads; back has
|
||||
less contour; arms appear puffier. The effect is identical for player
|
||||
characters (`+Acdream`, `+Je`) and for humanoid NPCs using the same
|
||||
setup (e.g. Woodsman, Sedor Wystan the Blacksmith, Thelnoth Cort).
|
||||
Drudges and other monster setups (e.g. `0x020007DD`) render
|
||||
identically to retail, so this is *not* a pipeline-wide bug.
|
||||
|
||||
The bug is independent of equipment — `+Je` stripped naked still
|
||||
shows the same bulky silhouette.
|
||||
|
||||
**Investigation 2026-05-06 (~3 hr session, ruled out many hypotheses):**
|
||||
|
||||
What was ruled out:
|
||||
|
||||
- **0xF625 ObjDescEvent appearance updates being dropped.** Was a real
|
||||
bug for skin/hair colors; fixed in commit e471527. Does not affect
|
||||
the bulky-shape issue (which persists with the fix in place and
|
||||
with no equipment).
|
||||
- **Position-pop on equip toggle.** Caused by re-applying with cached
|
||||
spawn's stale position; fixed in same commit. Doesn't affect shape.
|
||||
- **Clothing/armor overlapping the base body** (HiddenParts hypothesis).
|
||||
User stripped naked; bulky shape persists.
|
||||
- **ParentIndex hierarchy not walked in `SetupMesh.Flatten`.** Setup
|
||||
`0x02000001` has a real hierarchy (`-1, -1, 1, 2, 3, -1, 5, 6, 7, 0,
|
||||
9, 10, 11, 12, 13, 14, 15, 0, ...`), but implementing parent-walk
|
||||
produced **no visible change** — confirming AC's idle animation
|
||||
frames are already in setup-root coordinates, not parent-local.
|
||||
- **Equipment / wielded items.** No equipment on `+Je` and bug persists.
|
||||
- **Player-specific data flow.** Humanoid NPCs using same setup
|
||||
(Woodsman) show same bug.
|
||||
|
||||
What was confirmed (data captured via `ACDREAM_DUMP_CLOTHING=1`):
|
||||
|
||||
- Setup `0x02000001`: `setup.Parts.Count = 34`, `flatten.Count = 34`,
|
||||
`APC = 34..38` depending on equipment.
|
||||
- All 34 parts emit triangles successfully (no silent GfxObj load
|
||||
failures). Total ~648-700 tris per character.
|
||||
- Idle animation frames place parts at sensible humanoid Z-heights
|
||||
(head Z=1.587, mid-body Z=0.5-1.0, ground Z=0.085).
|
||||
- Per-part orientations are nearly all 180° around -Z (W≈0,
|
||||
Z≈-1) — a setup-wide coordinate-flip convention. Drudges have
|
||||
varied per-part orientations.
|
||||
- `setup.DefaultScale.Count = 0` for both humans and drudges → all
|
||||
parts use Vector3.One scale.
|
||||
|
||||
**Working hypotheses (next session):**
|
||||
|
||||
1. **Per-vertex normal style.** AC dat may store per-face normals
|
||||
for human GfxObjs (one normal per polygon, copied to all 3
|
||||
vertices) but smooth normals for monster GfxObjs. acdream uses
|
||||
dat normals directly. Test by computing smooth normals from face
|
||||
adjacency and comparing render. User said "not shaders" but the
|
||||
screenshots clearly show smooth-vs-faceted lighting differences.
|
||||
2. **Lighting setup.** Cell ambient may be too low, leaving back-
|
||||
facing surfaces in flat shadow. Compare `uCellAmbient` value
|
||||
against retail's behaviour at the same time-of-day.
|
||||
3. **Anti-aliasing.** Retail may use MSAA; acdream window may not.
|
||||
Polygon edges in acdream would be visibly stair-stepped, reading
|
||||
as "more faceted" / blockier.
|
||||
4. **Surface flags interpretation.** Specific Surface.Type bits for
|
||||
character textures (skin, fabric) may need handling acdream
|
||||
doesn't yet do (e.g. `SmoothShade` flag, or a mip bias).
|
||||
|
||||
**Diagnostic infrastructure landed this session** (env-var-gated, no
|
||||
runtime cost when off):
|
||||
|
||||
- `ACDREAM_DUMP_CLOTHING=1` extended:
|
||||
- `setup.Parts.Count`, `flatten.Count`, `APC` count on header line
|
||||
- `ParentIndex[]` array dump
|
||||
- `DefaultScale[]` array dump
|
||||
- `IdleFrame.Frames[]` per-part Origin + Orientation (first 17 parts)
|
||||
- `EMIT part=NN gfx=0xXX subMeshes=N tris=N` per part
|
||||
- `TOTAL tris=N meshRefs=N` per entity
|
||||
|
||||
**Files (suspect surface area for next investigation):**
|
||||
|
||||
- `src/AcDream.Core/Meshing/SetupMesh.cs` — Flatten composition
|
||||
- `src/AcDream.Core/Meshing/GfxObjMesh.cs` — polygon emission +
|
||||
vertex normal handling (line 142)
|
||||
- `src/AcDream.App/Rendering/Shaders/mesh.frag` — lighting eq
|
||||
- `src/AcDream.App/Rendering/Shaders/mesh.vert` — normal transform
|
||||
|
||||
**Acceptance:** Side-by-side screenshots of `+Acdream` (or any humanoid
|
||||
NPC using `0x02000001`) viewed from the same angle in acdream and
|
||||
retail show matching silhouette and shape definition.
|
||||
|
||||
---
|
||||
|
||||
## #46 — Retail observer of acdream sees blippy / laggy movement
|
||||
|
||||
**Status:** OPEN
|
||||
|
|
|
|||
|
|
@ -1997,6 +1997,33 @@ public sealed class GameWindow : IDisposable
|
|||
if (dumpClothing)
|
||||
{
|
||||
Console.WriteLine($"\n=== DUMP_CLOTHING: guid=0x{spawn.Guid:X8} name='{spawn.Name}' setup=0x{setup.Id:X8} setup.Parts.Count={setup.Parts.Count} flatten.Count={flat.Count} APC={animPartChanges.Count} ===");
|
||||
// Dump the Setup's ParentIndex + DefaultScale arrays to verify hierarchy.
|
||||
var parentStr = string.Join(",", setup.ParentIndex.Take(Math.Min(34, setup.ParentIndex.Count)).Select(p => p == 0xFFFFFFFFu ? "-1" : p.ToString()));
|
||||
Console.WriteLine($" ParentIndex[{setup.ParentIndex.Count}]: {parentStr}");
|
||||
var scaleStr = string.Join(",", setup.DefaultScale.Take(Math.Min(34, setup.DefaultScale.Count)).Select(s => $"({s.X:F2},{s.Y:F2},{s.Z:F2})"));
|
||||
Console.WriteLine($" DefaultScale[{setup.DefaultScale.Count}]: {scaleStr}");
|
||||
// Dump the resolved idle frame's per-part Origin + Orientation.
|
||||
// If retail composes parent_world * animation_local but acdream
|
||||
// treats animation_local as world-relative, we'd see specific
|
||||
// patterns of non-zero per-part origins/rotations that should
|
||||
// be parent-relative. For setups whose idle has all parts at
|
||||
// (0,0,0)/identity, parent walking would be a no-op (which
|
||||
// matches my earlier "no change" experiment if that was the
|
||||
// human-idle case) — diagnostic confirms.
|
||||
if (idleFrame is not null)
|
||||
{
|
||||
Console.WriteLine($" IdleFrame.Frames[{idleFrame.Frames.Count}]:");
|
||||
int dumpCount = Math.Min(idleFrame.Frames.Count, 17); // first 17 (real body parts, not the 17-33 placeholders)
|
||||
for (int fi = 0; fi < dumpCount; fi++)
|
||||
{
|
||||
var f = idleFrame.Frames[fi];
|
||||
Console.WriteLine($" [{fi:D2}] Origin=({f.Origin.X:F3},{f.Origin.Y:F3},{f.Origin.Z:F3}) Orient=(W={f.Orientation.W:F3} X={f.Orientation.X:F3} Y={f.Orientation.Y:F3} Z={f.Orientation.Z:F3})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($" IdleFrame: NULL");
|
||||
}
|
||||
foreach (var c in animPartChanges)
|
||||
Console.WriteLine($" APC part={c.PartIndex:D2} -> gfx=0x{c.NewModelId:X8}");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue