# 池核模拟器 DeepSeek V4.1 Flash - DeepSeek Harness **Repository Path**: az13js/deepseek-test2 ## Basic Information - **Project Name**: 池核模拟器 DeepSeek V4.1 Flash - DeepSeek Harness - **Description**: 制作一个网页版3D Poolrooms(池核)模拟器,使用Three.js/WebGPU或Babylon.js。整体采用现代PBR材质,超真实光照与实时反射…… - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-10 - **Last Updated**: 2026-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # POOLROOMS · 池核 A web-based, infinitely extending first-person **Poolrooms** simulator built on Three.js / WebGL 2. No UI, no objectives — just liminal tiled halls, warm shallow water, deep pools and light falling through roof openings. Everything is generated at runtime: **no external textures, no HDRI files, no network access while running.** The only third-party code is a vendored copy of three.js. --- ## Run it ```bash node server.mjs # → http://127.0.0.1:5173/ ``` Any static file server works — there is **no build step**. The app is plain ES modules with an import map pointing at `vendor/three/`. > ES modules and `import` maps require HTTP; opening `index.html` from the > filesystem (`file://`) will not work. ### Controls | | | |---|---| | `W A S D` | walk / swim | | `SHIFT` | run (on land) · dive (in water) | | `SPACE` | jump · swim up | | mouse | look | | `ESC` | release the pointer | Two optional URL parameters trade quality for speed: `?msaa=0` disables the ×4 multisampling on the HDR target, and `?scale=0.7` starts at a lower internal render resolution. Click once to lock the pointer. That gate is the only element on screen and it fades away completely. --- ## What is actually being rendered ### Lighting — a Lumen stand-in * **Procedural interior HDRI.** A small analytic scene is rendered through `PMREMGenerator` to produce the image-based lighting probe. Crucially it describes *the room*, not an outdoor sky: dark plaster ceiling and a few very bright roof openings above, bright wet tiling and cyan water bounce below. That asymmetry is what a real global-illumination solve would produce, and it is why glossy floors reflect the ceiling instead of turning into white sheets. (Using an outdoor sky probe here was the single biggest visual bug during development.) * **Directional sun** with a texel-snapped 2048² shadow map that follows the player, plus a hemisphere fill approximating multi-bounce. * **SSAO + single-bounce GI** (`AO_FRAG`): a rotated hemisphere kernel at half resolution returns both an occlusion term and the *colour* arriving from the unoccluded directions. That colour is added back only where the surface is actually occluded, so open areas are not double-lit by indirect light that is already baked into the scene colour. ### Reflections — two systems, each where it is best * **Planar reflection** for the water: a genuine mirrored camera render, clipped to `y ≥ 0`, sampled projectively. Exact, not a screen-space guess — which is what makes the roof lights and columns read correctly in the pools. * **Screen-space reflections** (`SSR_FRAG`) for everything else: view-space ray march with thickness rejection and four bisection refinements, roughness driven step count and blur, dithered per pixel. An estimate of the IBL specular term is subtracted first so reflections are *replaced*, not doubled. ### Water Rendered in its own pass between the opaque scene and the image-space effects, composited by hand: * **Waves** — four analytic gravity waves with the correct deep-water dispersion relation (`ω = √(gk)`) so the normals match the vertex displacement, plus two scrolling capillary normal-map layers. * **Refraction** — the refracted ray is traced with Snell's law (`refract(-V, N, 1/1.333)`), projected to screen space, and the water column thickness is read back from the depth buffer. Two iterations converge on the correct landing point, so the distortion scales with depth the way a real pool does. * **Depth gradient** — Beer–Lambert transmittance `exp(-σ·d)` with in-scattering, so a 35 cm film is perfectly clear and a 3 m pool goes opaque blue-green. * **Caustics** — the classic layered warped-sine network, injected into every opaque material, weighted by the true sun shadow mask and by depth below the waterline, and clamped so a fold can never blow out a surface. * **Underwater** — Snell's window and total internal reflection when the camera is submerged; separate absorption, scattering and denser volumetric medium. ### Volumetric fog and light shafts Half-resolution ray march with a Henyey–Greenstein phase function and a per-sample shadow lookup against three's packed depth map. In-scattered sun radiance is strongly forward-peaked, so the shafts appear when you look towards the sun — and anything outside the shadow frustum is treated as *occluded*, since we are always indoors. Exponential height falloff plus a low evaporation band over the water. Depth-aware bilateral upsample in the composite. ### Materials Every surface is a `MeshStandardMaterial` patched through `onBeforeCompile`: * `vDshWorld` / `aWet` varyings; * a **wetness response** — soaked tiles drop to roughness ≈ 0.085 and darken, producing a convincing waterline; * the **caustics** term described above; * the scene colour's **alpha channel is used as a free roughness G-buffer** for the post chain. `1.0` marks an emitter (sky panels), `0.0` marks water; both are excluded from AO and SSR. No MRT needed. Textures are generated procedurally by `src/core/textures.js` as raw typed arrays (no canvas): periodic value/gradient noise, height fields differentiated into normal maps, true horizon-based AO, and physically differentiated roughness — glazed tile faces ≈ 0.10 against grout ≈ 0.69. Each kind declares its real-world footprint, and the UV projection is calibrated against it, so tiles are life-size everywhere in the world. ### Infinite world A 4 m cell grid, 32 m chunks, streamed with a per-frame build budget. Ten hand-authored layout templates (great hall, cross channels, stepped terraces, corridor grid, aqueduct, grand stair, shallow field, island platform, side channels, deep basin) are selected from a low-frequency field so neighbouring chunks share a character, then rotated/flipped per chunk. Floor levels are `+0.55 m` dry deck down to `−3.2 m` deep pool; **water is always at y = 0**, so shallow and deep water fall out of the level field for free. Every vertical step belongs to the chunk containing the **lower** cell and is emitted inside that cell's footprint, so each edge is generated exactly once and the world is watertight with no per-chunk seams. A drop becomes a staircase (real ≈20 cm risers) or a vertical tiled pool wall depending on its height. Above that sits a **walkability guarantee**: a flood fill over the surrounding 3×3 chunks finds any cell that cannot be reached, and the cheapest separating edge is promoted to a forced staircase. Deep pools are never sealed off, and the resulting staircases read as deliberate architecture. `tools/verify-world.mjs` proves this on demand. Dressing is procedural too: colonnades on the cell-corner lattice, barrel-vault arches spanning channels, luminous arched niches recessed into block walls, skylights with real openings (they cast the shadows that become light shafts), drain grates and coping nosings. --- ## Verification Everything below runs headless; no GPU required. ```bash node tools/verify-world.mjs 7 # geometry stats + proof of full connectivity node tools/texpreview/run.mjs # texture statistics, seam/determinism checks ``` `verify-world.mjs` reimplements the controller's step-up rule rather than approximating it, and it has a negative control: comment out the forced staircase pass and it starts failing. Two bugs were caught this way — a height field built with the wrong units (9×9 samples for a 32 m chunk, which silently turned every vertical pool wall into a gentle ramp the player could walk up) and a coordinate offset that made the check vacuous. Rendering is verified with a scripted Chromium harness (software WebGL 2 via SwiftShader — correct, but far too slow for frame-rate numbers): ```bash node server.mjs & node tools/shot.mjs http://127.0.0.1:5173/ shot.png w=1280 h=720 node tools/diag.mjs http://127.0.0.1:5173/ /tmp/dg steps.json ``` `steps.json` is an array of `{name, look:[yaw,pitch], at:[x,z], set:{...}}`. Physics is verified in the same session without rendering, so it is fast even under a software rasteriser: `__POOLROOMS_.physicsProbe()` drives the player at a real vertical pool wall and asserts they cannot climb it, and `physicsSoak(seeds, steps)` walks from many spawn points asserting the player never sinks through geometry. ```js // in the browser console, or via tools/diag.mjs __POOLROOMS_.physicsProbe() // → { allBlocked: true, results: [...] } __POOLROOMS_.physicsSoak(14, 900) ``` ### Live tuning hooks `window.__POOLROOMS_` exposes `status()`, `look()`, `teleport()`, `set()`, `setEnv()`, `setWater()`, `setVisible()`, `pick()` and `counts()`, plus intermediate-buffer debug views (`set({debugView:1, debugTarget:'ao'})`). These were how the water, occlusion and volumetric passes were diagnosed. --- ## Performance Measured draw calls and geometry: **~75–100 draw calls** and **30–45 k triangles** for a fully streamed 7×7 chunk neighbourhood (≈210 m across), 2–6 ms per chunk to generate. The geometry is very light; the cost is in the full-screen passes (SSR, AO, volumetric fog, bloom). To hold 60 fps the renderer keeps a rolling frame-time average and adjusts the internal render scale between 0.60 and 1.0, at most one step every 30–150 frames so it never oscillates. MSAA ×4 is applied on the HDR target; the fog and AO passes run at half resolution with depth-aware upsamples. If you need more headroom, the cheapest knobs are, in order: `pipeline.set({fogSteps: 20})`, `{ssr: 0.6}`, `{ao: 1.0}`, and lowering `renderer.setPixelRatio` in `src/main.js`. --- ## Layout ``` index.html import map + the pointer-lock gate server.mjs zero-dependency static server vendor/three/ vendored three.js r180 (no CDN, works offline) src/main.js boot sequence, frame loop, adaptive resolution src/core/rng.js hashes and tileable noise src/core/textures.js procedural PBR texture library (typed arrays only) src/core/env.js procedural interior HDRI, sun, shadow fitting src/world/layout.js dimensions, floor levels, chunk templates src/world/meshbuilder.js world-space triangle accumulator, height field src/world/generator.js chunk geometry + the walkability pass src/world/world.js chunk streaming, ground/collider queries src/render/materials.js PBR materials, wetness, caustics, G-buffer packing src/render/water.js water surface shader src/render/post.js the frame pipeline src/render/shaders/post.glsl.js AO/GI, SSR, fog, bloom, composite GLSL src/player/controller.js first-person controller and physics tools/ verification harnesses ```