Add debugging notes

This commit is contained in:
Jared Miller 2026-03-12 20:14:59 -04:00
parent 81526052f2
commit 6cef5a35b2
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -0,0 +1,161 @@
air cell corruption debug log
=============================
problem
-------
air cells (materialId=0) in the world render target get corrupted to
materialId=255 after ~10 simulation frames. this causes air to render
as BLACK instead of any intended color, because the material color
lookup texture has no entry at index 255 (returns all zeros).
the original request was to change air from black to light blue.
the shader change is trivial but has no effect because the materialId
is wrong — the shader's `materialId == MAT_AIR` branch never fires.
what we confirmed
-----------------
1. init data is correct: air cells = [0,0,0,0], sand cells = [1,0,0,0]
(sync readback immediately after generateSideViewWorld + copyTextureToTexture)
2. frame 0 is clean: every render pass in the pipeline produces [0,0,0,0]
for an air cell at top-center (px=512, py=1023). checked after each:
- sandPhysicsRT: [0,0,0,0]
- worldBlurredRT: [0,0,0,0]
- antsDiscreteRT: [0,0,0,0]
- worldRT OUTPUT: [0,0,0,0]
3. by frame 10, worldRT INPUT (read before sandPhysics) = [255,0,0,0]
meaning the corruption enters between frame 9's worldCompute output
(which passed the check) and frame 10's sandPhysics input
4. renderToScreen runs between those frames (the sim loop does ~1 step
per rAF, then calls renderToScreen). so the corruption window is
during renderToScreen or between renderToScreen and the next sim step.
5. the screen shader IS being used for the full viewport (confirmed by
outputting solid blue — entire screen turned blue)
6. MAT_AIR define is correctly 0 (logged from ScreenScene constructor)
7. the shader source reaching the material IS the correct file
(first 200 chars logged and verified)
what we ruled out
-----------------
- shader not loading: confirmed via all-blue test and console.debug of source
- material color lookup texture: registry has correct values, texture
generation code (generateColorData) is straightforward
- texture filtering: all render targets use NearestFilter
- sand physics: passes through materialId unchanged for non-swapping cells
- worldBlur: outputs s0.x (material ID) unchanged
- worldCompute (world.frag): preserves materialId from input, only changes
it for deposits (depositMatId > 0) or cell clears (discreteAnts.z == 1)
- draw.frag: preserves materialId unless actively painting (drawMode >= 0)
- vite HMR: shaders load as raw strings at construction, HMR doesn't
reconstruct ShaderMaterial. confirmed shader changes take effect after
full dev server restart
- copyFramebufferToTexture: disabled it, corruption still happened at
frame 10. the copy was suspected because it writes to worldRT.texture
while that texture may still be bound from DrawScene's tWorld uniform.
BUT disabling it did not fix the issue. (this call still needs a proper
fix — either use a render pass copy or unbind the texture first)
what we have NOT tested
-----------------------
- whether the corruption happens without renderToScreen at all (skip it
entirely — won't see anything on screen but could log worldRT state)
- whether ColonyStats.update (readRenderTargetPixels on antTarget) has
side effects that corrupt worldRT. it changes the bound render target.
- whether the draw scene render itself corrupts worldRT via some WebGL
state leak (even though it writes to worldRenderTargetCopy, maybe
binding worldRT.texture as tWorld uniform causes a side effect)
- a minimal repro: disable ALL passes except sandPhysics + worldBlur +
worldCompute and see if corruption still happens (isolate whether
ant passes or screen passes introduce it)
- reading worldRT between renderToScreen and the next renderSimulation
(requires readback in the rAF callback, after renderToScreen returns)
- whether THREE.js 0.173 has known issues with Float32 render targets
and copyFramebufferToTexture / readRenderTargetPixels
render pipeline (per frame)
---------------------------
in renderSimulation():
1. sandPhysics: reads worldRT -> writes sandPhysicsRT
2. worldBlur: reads sandPhysicsRT -> writes worldBlurredRT
3. antsPresence: cleared
4. antsCompute: reads worldBlurredRT + antsPresenceRT -> writes antsComputeTarget (MRT)
5. antsDiscretize: reads antsComputeTarget -> writes antsDiscreteRT (NOT cleared per frame!)
6. worldCompute: reads worldBlurredRT + antsDiscreteRT -> writes worldRT
7. ColonyStats.update: readRenderTargetPixels on antsComputeTarget (CPU readback)
in renderToScreen():
8. drawScene: reads worldRT (tWorld) -> writes worldRenderTargetCopy
9. copyFramebufferToTexture: copies worldRenderTargetCopy framebuffer -> worldRT.texture
(CURRENTLY DISABLED in local changes)
10. screenScene: reads worldRenderTargetCopy (map) -> writes to canvas (null target)
worldRT is the persistent world state. it feeds back into itself:
worldRT -> sandPhysics -> worldBlur -> worldCompute -> worldRT
current local changes (uncommitted)
------------------------------------
1. src/shaders/screenWorld.frag:
- air background color changed from white vec3(1,1,1) to light blue vec3(0.53, 0.81, 0.92)
- this change works correctly IF materialId is 0 for air cells
- also: the committed version has stale debug grayscale code from a previous session
that needs to be cleaned up
2. src/Renderer.ts:
- copyFramebufferToTexture disabled (replaced with comment)
- minor whitespace change
- both should be reverted when the real fix is found
3. src/scenes/ScreenScene.ts:
- groundDefines extracted to variable (cosmetic, from debug session)
4. src/materials/registry.ts:
- air color changed from [0,0,0,0] to [0.53,0.81,0.92,1.0]
- this was an early attempt that doesn't matter since the shader
hardcodes the air branch (doesn't use the lookup for air)
key file locations
------------------
- world init: src/WorldInit.ts (generateSideViewWorld)
- render pipeline: src/Renderer.ts (renderSimulation + renderToScreen)
- world texture format: RGBA Float32, R=materialId, G=scentToHome, B=scentToFood, A=repellent
- screen shader: src/shaders/screenWorld.frag
- world compute: src/shaders/world.frag
- sand physics: src/shaders/sandPhysics.frag
- pheromone blur: src/shaders/worldBlur.frag
- draw shader: src/shaders/draw.frag
- material constants: src/constants.ts (MAT_AIR=0 through MAT_HOME=5)
- material registry: src/materials/registry.ts
- color lookup texture gen: src/materials/lookupTexture.ts
suggested next steps
--------------------
1. try disabling renderToScreen entirely and adding a single
console.debug readback of worldRT after 20 frames. if worldRT stays
[0,0,0,0] for air, the corruption is caused by renderToScreen or
something it triggers.
2. if step 1 still shows corruption, try disabling the ant passes
(antsCompute, antsDiscretize, antsPresence clear) and see if the
corruption disappears. the world pipeline without ants is just
sandPhysics -> worldBlur -> worldCompute, which should be a no-op
for air cells.
3. if step 2 still shows corruption, the issue might be in sandPhysics
(Margolus block CA) or worldCompute. try disabling each individually.
4. check THREE.js 0.173 changelog/issues for Float32 render target bugs.
5. consider adding a "sanitizer" pass that clamps materialId to [0,5]
at the start of each frame as a workaround while debugging.