Two fixes for jump physics: - Skip ground-snap when velocity Z > 0 (prevents immediate re-landing at high framerates where per-frame Z delta < 0.05 snap threshold) - Guard apply_current_movement velocity write behind OnWalkable check (prevents MotionInterpreter.DoMotion from zeroing jump velocity on every frame while airborne) - Guard PlayerMovementController velocity replacement behind OnWalkable (preserves momentum during airborne flight) Jump works locally but server packet not yet sent (BUG-002). Facing direction mismatch logged as BUG-003. RunRate not verified as BUG-004. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98 lines
3.5 KiB
Markdown
98 lines
3.5 KiB
Markdown
# Rendering Rebuild from ACME — COMPLETE
|
||
|
||
Port ACME's rendering pipeline to acdream. Each step produces a
|
||
visually testable result. The animation system stays unchanged (ACME
|
||
has none — ours is ported from the decompiled client).
|
||
|
||
**Status:** All 5 steps shipped 2026-04-13.
|
||
|
||
## Step 1: Port StaticObject shader + instanced rendering
|
||
|
||
The biggest performance win. Replace per-entity DrawElements with
|
||
instanced rendering using a shared instance VBO.
|
||
|
||
**From ACME:**
|
||
- StaticObject.vert: aInstanceMatrix (mat4 at locations 3-6, divisor=1)
|
||
- StaticObject.frag: sampler2DArray + alpha cutout
|
||
- Instance buffer pattern: single float[] upload per frame
|
||
|
||
**Changes:**
|
||
- New shader: mesh_instanced.vert/frag (from ACME StaticObject.vert/frag)
|
||
- Rewrite StaticMeshRenderer to use instance buffer pattern
|
||
- Group entities by (GfxObjId, textureAtlas) → one DrawElementsInstanced per group
|
||
- Per-GfxObj TextureAtlasManager (grow-on-demand, starts at 32 slots)
|
||
- ushort indices (not uint32) for objects
|
||
|
||
**Test:** Same visual output, fewer draw calls (check perf overlay).
|
||
|
||
## Step 2: Port Landscape shader + terrain chunks
|
||
|
||
Replace per-landblock terrain draws with chunk batching.
|
||
|
||
**From ACME:**
|
||
- Landscape.vert/frag: 8 packed uvec4 attributes, sampler2DArray terrain + alpha
|
||
- TerrainChunk: N×N landblocks baked into one VBO/IBO
|
||
- TerrainGPUResourceManager: buffer creation + partial updates
|
||
|
||
**Changes:**
|
||
- New shader: terrain_acme.vert/frag (from ACME Landscape.vert/frag)
|
||
- New TerrainChunkRenderer (replaces TerrainRenderer)
|
||
- LandblockMesh.Build outputs VertexLandscape-compatible structs
|
||
- Single DrawElements per chunk (multiple landblocks)
|
||
|
||
**Test:** Same terrain appearance, one draw call per chunk.
|
||
|
||
## Step 3: Port AdjustPlanes lighting
|
||
|
||
Replace guessed sun direction with decompiled retail values.
|
||
|
||
**From decompiled:**
|
||
- FUN_00532440 (AdjustPlanes): face-normal accumulation + per-vertex lighting
|
||
- DAT constants: sun direction, ambient, diffuse
|
||
|
||
**Changes:**
|
||
- LandblockMesh: face-normal accumulation (replaces central differences)
|
||
- Shader uniforms: xLightDirection, xAmbient from decompiled constants
|
||
- Static objects: same lighting model
|
||
|
||
**Test:** Side-by-side with retail client shows matching lighting.
|
||
|
||
## Step 4: Port EnvCell portal visibility
|
||
|
||
Render only visible interior cells.
|
||
|
||
**From ACME:**
|
||
- EnvCellManager: portal visibility BFS from camera cell
|
||
- Portal occluder pass: depth-only draw of portal polygons
|
||
- Conditional depth clear when camera is inside a cell
|
||
|
||
**Changes:**
|
||
- New CellVisibility system (BFS through CellPortals)
|
||
- Portal occluder depth pass before EnvCell geometry
|
||
- Conditional depth clear in render order
|
||
|
||
**Test:** Enter a building — only visible rooms render.
|
||
|
||
## Step 5: Wire animation into instanced pipeline
|
||
|
||
The AnimationSequencer outputs per-part transforms. These need to flow
|
||
into the instance buffer alongside static transforms.
|
||
|
||
**Changes:**
|
||
- Animated entities write their per-part instance matrices into the
|
||
shared instance buffer every frame (same buffer as static objects)
|
||
- AnimationSequencer.Advance(dt) is called BEFORE the instance buffer
|
||
upload so the latest frame's transforms are included
|
||
|
||
**Test:** NPCs breathe, player walks — all through the instanced pipeline.
|
||
|
||
## Render Order (target)
|
||
|
||
```
|
||
1. Terrain (one DrawElements per chunk, PolygonOffset on)
|
||
2. Conditional depth clear (if camera inside EnvCell)
|
||
3. EnvCell geometry (DrawElementsInstanced, portal visibility culled)
|
||
4. Static objects opaque (DrawElementsInstanced, alpha cutout)
|
||
5. Static objects translucent (DrawElementsInstanced, blend on)
|
||
6. Particles (additive blend — future)
|
||
```
|