acdream/src/AcDream.Core
Erik 43e3abed4d fix(render): correct foliage-wind classification, receiver/caster desync, and frame binding (Campaign VM VM6 review)
Opus dual-lens review of the three VM6 commits (0930c35d, 39e8408c,
6cc5e183) found two blockers and two should-fix issues; all landed here
along with the review's nits and documentation corrections.

Blockers:
- A1: the procedural-scenery classifier tested bit 31 alone instead of
  the full top nibble (0xF000_0000 == 0x8000_0000), so it also matched
  LandblockStaticEntityIdAllocator's 0xC... namespace (fences/gates/
  building shells with a cutout subset), the 0xDA11_D0xx paperdoll id,
  and the 0xFFFF_FF01 portal-tunnel id as procedural scenery — all
  three would have swayed. ProceduralSceneryIdAllocator.IsInNamespace
  now does the exact top-nibble test; FoliageWindClassification
  delegates to it.
- A2: GroupKey (the receiver's instance-batching key) did not carry
  FoliageFlags while the caster's dedup key already did, so a scenery
  instance and a non-scenery instance sharing a mesh subset coalesced
  into one receiver InstanceGroup whose flags were last-writer-wins —
  disagreeing with the correctly-keyed caster. GroupKey now carries
  FoliageFlags, computed before key construction and set exactly once
  at group creation; the imperative re-stamp is gone, and CachedBatch's
  now-redundant FoliageFlags field is removed.

Should-fix:
- A3: the world receiver pass bound UniformAtmosphericFrame only by
  accident (leftover from the caster pass, which runs first each
  frame, since Vulkan binding state isn't reset between passes).
  DirectionalShadowFrameBinding now carries the caster's exact
  AtmosphericFrameBufferBinding and BindDirectionalShadowReceiver binds
  it explicitly.
- A4: a Setup-composed tree's opaque trunk part never got the trunk
  flag because HasCutoutSubset is cached per GfxObj part, not per
  entity. FoliageWindClassification.ComputeEntityHasCutoutSubset now
  ORs HasCutoutSubset across an entity's resolved sibling parts once
  per entity, threaded into ClassifyBatches/AddDirectionalShadowBatches
  via a new optional override parameter.

Nits: A5 hashes the per-vertex flutter seed relative to the instance
origin instead of absolute world XY (fp32 sin() precision loss at far
landblock corners), mirrored in both foliage_wind.glsl and
FoliageWindModel; A7 documents the max(maxHeight, 0.5) divide-guard as
a deliberate pseudocode divergence; A8 switches FoliageWindExclusions'
construction to ToFrozenSet() and softens the "never stale" doc
comment to "no slower than one frame behind."

Tests added: top-nibble classification (0xFFFFFFFFu now correctly
false), GroupKey inequality across entity-driven scenery/landblock-
static classification, a caster-batch test proving the same pairing
never coalesces, ComputeEntityHasCutoutSubset unit + end-to-end
two-part-Setup tests, the caster→receiver AtmosphericFrame binding
carry-through, flutter-hash translation invariance relative to
instance origin, and a Storm-wind mid-height displacement floor
guarding against a "no motion" regression.

Docs: plan VM6 body corrected to the five-row WeatherKind table, "bits
1 and 2", "all four" caster shaders, and top-nibble wording throughout;
the owner gate checklist's Rain/Storm step; the stale v1-only shader-
interface compatibility entry; semantic-bindings-v1.md's v2 members
folded into the main 192-byte block; the IA-25 register row's top-
nibble wording; AtmosphericFrameInputs.cs's ABI size reference.

foliage_wind.glsl's A5 change recompiled exactly the five shaders that
include it (mesh_atmospheric.vert, the four directional_shadow_world_*
casters) plus the manifest; no other .spv changed.

Verify: Release build 0 warnings/0 errors. App hermetic-lane filter
6,041/0 failed (no environment-specific failures this run).
RenderPackValidator 30/30. Full hermetic-filtered solution: 15,269/0
failed across 15 projects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 01:54:36 +02:00
..
Audio feat(audio): Ctrl+M instant mute + inn-chatter investigation closed as server content 2026-08-09 14:09:24 +02:00
CharGen fix(chargen): Campaign CC gate round 1 closeout — Group 2: Skills page four-bucket model 2026-08-16 15:33:39 +02:00
Chat feat(chat): CT-B4 — @log, and the research block that was a wrong question 2026-08-21 11:28:20 +02:00
Combat feat(core): adopt the retail members the equipment and physics enums were missing 2026-07-29 01:27:57 +02:00
Content fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
Input feat(ui): Campaign OP slice OP8 — Configure Keyboard 2026-08-11 09:19:54 +02:00
Items feat(ui): inventory/shortcut/paperdoll item-name tooltips — UIElement_UIItem::UpdateTooltip port 2026-08-16 23:02:10 +02:00
Journal feat(journal): QJ1/QJ2 — the journal's pages and their file 2026-08-21 15:31:47 +02:00
Lighting fix(render): VM3 review fixes - pin the filmic decodes, re-derive vignette for linear, name the authored sun colour 2026-08-22 23:40:48 +02:00
Meshing fix(rendering): bound portal resource lifetime 2026-07-18 21:35:16 +02:00
Physics fix(world): honour SetOmega — the birds and butterflies fly again 2026-08-21 05:42:59 +02:00
Player fix(ui): restore retail vitals and window interactions 2026-08-20 13:26:35 +02:00
Plugins feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00
Properties feat(core): give AC's seven property tables names, verified against two oracles 2026-07-29 01:11:16 +02:00
Quests feat(journal): QJ3/QJ4/QJ5 — both remaining tabs are live 2026-08-21 15:42:05 +02:00
Rendering feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00
Selection feat(runtime): FA4 -- fellowship roster enumeration + Social selection source 2026-08-12 04:40:19 +02:00
Social refactor(runtime): expose canonical gameplay state 2026-07-26 09:12:30 +02:00
Spells fix(ui): restore retail vitals and window interactions 2026-08-20 13:26:35 +02:00
Terrain feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00
Textures fix(ui): Campaign LA gate round 2 — character-select screen media resolution 2026-08-15 09:12:10 +02:00
Ui feat(journal): QJ3/QJ4/QJ5 — both remaining tabs are live 2026-08-21 15:42:05 +02:00
Vfx fix(vfx): classify hardwareless particle emitters once 2026-07-27 00:03:44 +02:00
World fix(render): correct foliage-wind classification, receiver/caster desync, and frame binding (Campaign VM VM6 review) 2026-08-23 01:54:36 +02:00
AcDream.Core.csproj build: make release restore reproducible 2026-08-18 10:29:00 +02:00
packages.linux-x64.lock.json build: make release restore reproducible 2026-08-18 10:29:00 +02:00
packages.neutral.lock.json build: make release restore reproducible 2026-08-18 10:29:00 +02:00
packages.win-x64.lock.json build: make release restore reproducible 2026-08-18 10:29:00 +02:00