tower / commit
fix(exterior): draw the seas behind the cap windows
decisions.md | 7 +++++++ src/views/exterior.ts | 9 ++++++--- src/views/interior-model.ts | 12 ++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/decisions.md b/decisions.md index 990372c..e5c7f11 100644 --- a/decisions.md +++ b/decisions.md @@ -2185,6 +2185,13 @@ readers get too, as §5.4 planned — keyed so a new build never reads an old wo compiles once, hands every shot the warm cache, caps each page at two workers, and reports any shot that compiled anyway. It takes about 100 s and averages about 3.4 cores. +**A regression this caused, fixed 2026-09-27.** Giving water render order 1 put it after +the cap windows, which kept the default 0. From outside, a window is transparent and in +front of the seas: drawn first, it wrote its depth, and the water behind it failed the +depth test — so looking in at the sun cap showed the Sunward Sea's bed, brown, instead of +the sea. See-through windows now draw at 2.5, after the water and the falls and before the +beam, and the exterior's rays share that order so they still sort against the glass. + --- ## D-067 — Tower's weather is a published plan, and ships read it diff --git a/src/views/exterior.ts b/src/views/exterior.ts index acd5307..e76a9bd 100644 --- a/src/views/exterior.ts +++ b/src/views/exterior.ts @@ -21,7 +21,7 @@ import { } from '../canon/constants.js' import { type SurfacePoint, mapThetaOrigin, normalizeTheta } from '../canon/geometry.js' import { terrain } from '../terrain/service.js' -import { InteriorModel, STAR_GLSL } from './interior-model.js' +import { InteriorModel, STAR_GLSL, WINDOW_RENDER_ORDER } from './interior-model.js' const KM = 1000 const R = RADIUS_M / KM @@ -447,10 +447,13 @@ export class ExteriorView { const beam = new BufferGeometry() beam.setAttribute('position', new Float32BufferAttribute(verts, 3)) beam.setAttribute('color', new Float32BufferAttribute(cols, 4)) - this.scene.add(new LineSegments(beam, new LineBasicMaterial({ + const rays = new LineSegments(beam, new LineBasicMaterial({ vertexColors: true, transparent: true, blending: AdditiveBlending, depthWrite: false, - }))) + })) + // The same order as the windows, so the rays still sort against the glass they end at. + rays.renderOrder = WINDOW_RENDER_ORDER + this.scene.add(rays) } /** diff --git a/src/views/interior-model.ts b/src/views/interior-model.ts index 630e44b..caefab9 100644 --- a/src/views/interior-model.ts +++ b/src/views/interior-model.ts @@ -1280,6 +1280,9 @@ export interface InteriorModelOptions { seeThrough: boolean } +/** Where the see-through windows draw among the transparent things (see `buildCaps`). */ +export const WINDOW_RENDER_ORDER = 2.5 + export class InteriorModel { /** Every material here, so a caller can set a shared uniform in one loop. */ readonly materials: ShaderMaterial[] = [] @@ -1583,6 +1586,15 @@ export class InteriorModel { side: BackSide, uniforms: { uTint: { value: new Color(0x9aa0aa) } }, })) reveal.name = 'bore' + /** + * From outside, a window is drawn after the water (1) and the falls (2) behind it. + * Left at 0 it went first, wrote its depth, and every sea behind the glass failed the + * depth test — so looking in at the sun cap showed the Sunward Sea's bed, brown, where + * the sea should have been. It still goes before the beam (3), which is therefore + * hidden behind the glass as it always has been. The exterior's own transparent things + * share this order (exterior.ts), so they still sort against the glass by distance. + */ + if (this.opts.seeThrough) sun.renderOrder = far.renderOrder = WINDOW_RENDER_ORDER return [sun, far, reveal] }