From 33afce03ea0b856973ca34bde4afff019528746a Mon Sep 17 00:00:00 2001 From: Cameron Date: Sat, 26 Sep 2026 10:51:02 -0700 Subject: [PATCH] Lay the tide pool's drop ring along the slope under it and draw it over anything in front, soften the glow's widest reach so a brightly lit spot no longer blooms into a square, and keep the night light a little higher over rock. --- public/tide-pool.js | 29 ++++++++++++++++++++++------- src/components/tide-pool.tsx | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/public/tide-pool.js b/public/tide-pool.js index e95995e..fa83d30 100644 --- a/public/tide-pool.js +++ b/public/tide-pool.js @@ -107,11 +107,15 @@ async function initialize() { vertexShader: FULL, fragmentShader: ` uniform sampler2D tBright; uniform vec2 uTexel; uniform float uStrength; varying vec2 vUv; - // One halving, read through a small tent so its pixels don't show. + // One halving, read through a tent three of its pixels across, so its square pixels never show, however bright. vec3 level(float lod) { - vec2 d = uTexel * exp2(lod) * .5; - return (textureLod(tBright, vUv - d, lod) + textureLod(tBright, vUv + d, lod) + - textureLod(tBright, vUv + vec2(d.x, -d.y), lod) + textureLod(tBright, vUv + vec2(-d.x, d.y), lod)).rgb * .25; + vec2 d = uTexel * exp2(lod); + vec3 sum = textureLod(tBright, vUv, lod).rgb * 4.; + sum += (textureLod(tBright, vUv + vec2(d.x, 0.), lod) + textureLod(tBright, vUv - vec2(d.x, 0.), lod) + + textureLod(tBright, vUv + vec2(0., d.y), lod) + textureLod(tBright, vUv - vec2(0., d.y), lod)).rgb * 2.; + sum += (textureLod(tBright, vUv + d, lod) + textureLod(tBright, vUv - d, lod) + + textureLod(tBright, vUv + vec2(d.x, -d.y), lod) + textureLod(tBright, vUv + vec2(-d.x, d.y), lod)).rgb; + return sum / 16.; } void main() { // Near and far: these reach about 3, 12, 34, 100 and 200 pixels of the finished image. @@ -975,7 +979,7 @@ async function initialize() { lantern.y = lantern.lit ? lantern.y + (target - lantern.y) * Math.min(1, dt * 7) : target; hit = groundAt(lantern.cx, lantern.cy, lantern.y); const floor = hit && floorNear(hit.x, hit.z); - if (hit && lantern.y < floor + .22) { lantern.y = floor + .22; hit = groundAt(lantern.cx, lantern.cy, lantern.y); } + if (hit && lantern.y < floor + .35) { lantern.y = floor + .35; hit = groundAt(lantern.cx, lantern.cy, lantern.y); } } const lit = !!hit && onShelf(world, hit.x, hit.z); lantern.glow += ((lit ? night : 0) - lantern.glow) * Math.min(1, dt * 5); @@ -1124,6 +1128,11 @@ async function initialize() { new T.MeshBasicMaterial({ color: 0xffffff, transparent: true, blending: T.AdditiveBlending, depthWrite: false }), 260, { shadow: false, colored: true }), }; host(P.contact.mesh); + // The drop marker is a cursor, so it shows over whatever stands between it and the eye. + const cursorRing = part(new T.RingGeometry(.88, 1, 40).rotateX(-Math.PI / 2), + new T.MeshBasicMaterial({ color: 0xffffff, transparent: true, blending: T.AdditiveBlending, depthWrite: false, depthTest: false }), 1, { shadow: false, colored: true }); + cursorRing.mesh.renderOrder = 7; + host(cursorRing.mesh); const base = new T.Matrix4(), local = new T.Matrix4(); let cosA = 1, sinA = 0, bx = 0, by = 0, bz = 0; @@ -1624,8 +1633,14 @@ async function initialize() { const markerColor = new T.Color(0xe0c4eb); function drawMarker() { if (!marker.visible) return; - const y = Math.max(heightAt(world, cursor.x, cursor.z), surfaceAt(world, cursor.x, cursor.z)) + .02; - put(P.contact, m4.compose(v1.set(cursor.x, y, cursor.z), q.identity(), s3.set(.24, 1, .24)), markerColor); + // It lies along the slope under it, rock or water, and just clear of the highest point under its rim, so it never + // cuts into a bank. + const floor = (dx, dz) => Math.max(heightAt(world, cursor.x + dx, cursor.z + dz), surfaceAt(world, cursor.x + dx, cursor.z + dz)); + const R = .24, y0 = floor(0, 0), east = floor(R, 0), west = floor(-R, 0), south = floor(0, R), north = floor(0, -R); + const sx = (east - west) / (2 * R), sz = (south - north) / (2 * R); + const rise = Math.max(0, east - y0 - sx * R, west - y0 + sx * R, south - y0 - sz * R, north - y0 + sz * R); + q.setFromUnitVectors(v2.set(0, 1, 0), v3.set(-sx, 1, -sz).normalize()); + put(cursorRing, m4.compose(v1.set(cursor.x, y0 + rise + .05, cursor.z), q, s3.set(R, 1, R)), markerColor); } diff --git a/src/components/tide-pool.tsx b/src/components/tide-pool.tsx index 0cb36a6..e3dbec9 100644 --- a/src/components/tide-pool.tsx +++ b/src/components/tide-pool.tsx @@ -189,7 +189,7 @@ export function TidePoolContent() {

Rendered with Three.js. Software license.

- + ); } -- 2.51.2