@babylonjs/lite 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.js +326 -326
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +72 -6
  5. package/lib/camera/arc-rotate.js +2 -20
  6. package/lib/camera/arc-rotate.js.map +1 -1
  7. package/lib/camera/camera.js +21 -4
  8. package/lib/camera/camera.js.map +1 -1
  9. package/lib/camera/free-camera.js +2 -19
  10. package/lib/camera/free-camera.js.map +1 -1
  11. package/lib/camera/geospatial-camera.js +2 -19
  12. package/lib/camera/geospatial-camera.js.map +1 -1
  13. package/lib/camera/orthographic.js +70 -0
  14. package/lib/camera/orthographic.js.map +1 -0
  15. package/lib/engine/engine.js +1 -1
  16. package/lib/frame-graph/render-task.js +2 -2
  17. package/lib/frame-graph/render-task.js.map +1 -1
  18. package/lib/index.js +4 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/light/clustered.js +19 -6
  21. package/lib/light/clustered.js.map +1 -1
  22. package/lib/material/shader/shader-renderable.js +2 -2
  23. package/lib/material/shader/shader-renderable.js.map +1 -1
  24. package/lib/material/standard/enable-standard-mesh-features.js.map +1 -1
  25. package/lib/math/index.js +1 -0
  26. package/lib/math/index.js.map +1 -1
  27. package/lib/math/mat4-look-at-world-lh.js +55 -0
  28. package/lib/math/mat4-look-at-world-lh.js.map +1 -0
  29. package/lib/math/mat4-ortho-lh-to-ref.js +22 -0
  30. package/lib/math/mat4-ortho-lh-to-ref.js.map +1 -0
  31. package/lib/math/mat4.js +1 -0
  32. package/lib/math/mat4.js.map +1 -1
  33. package/lib/navigation/index.js +1 -1
  34. package/lib/navigation/navigation.js +12 -1
  35. package/lib/navigation/navigation.js.map +1 -1
  36. package/lib/post-process/taa.js +2 -1
  37. package/lib/post-process/taa.js.map +1 -1
  38. package/lib/shadow/csm-shadow-task-hooks.js +13 -6
  39. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  40. package/lib/shadow/shadow-base.js +3 -2
  41. package/lib/shadow/shadow-base.js.map +1 -1
  42. package/lib/text/text-renderable.js +2 -2
  43. package/lib/text/text-renderable.js.map +1 -1
  44. package/package.json +3 -11
  45. package/material/standard/enable-standard-mesh-features.d.ts +0 -4
  46. package/material/standard/enable-standard-vertex-colors.d.ts +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"csm-shadow-task-hooks.js","sources":["../../../src/shadow/csm-shadow-task-hooks.ts"],"sourcesContent":["/** Internal CSM (cascaded shadow map) task hooks owned by CSM shadow generators.\n *\n * Mirrors `pcf-shadow-task-hooks.ts`, but renders N cascade layers of a depth\n * `texture_2d_array` and computes per-cascade frustum-split + orthographic-fit\n * matrices from the active camera. All CSM-only math (frustum-corner fit,\n * ortho-off-center, texel snap) lives here so plain ESM/PCF scenes never bundle\n * it. The light view matrix + 4×4 multiply are shared helpers (already used by\n * ESM/PCF) so reusing them adds zero bytes.\n */\n\nimport type { Camera } from \"../camera/camera.js\";\nimport type { DirectionalLight } from \"../light/directional-light.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Material, MaterialView } from \"../material/material.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport { createRenderTask, removeMeshFromTask, type RenderTask } from \"../frame-graph/render-task.js\";\nimport { getViewProjectionMatrix } from \"../camera/camera.js\";\nimport { mat4Invert } from \"../math/mat4-invert.js\";\nimport { buildLightViewMatrix, casterVersionSum, createShadowCamera, multiply4x4, updateShadowCameraBase } from \"./shadow-base.js\";\nimport { getNoColorView, preloadPcfShadowTaskState } from \"./pcf-shadow-task-hooks.js\";\nimport type { ShadowGenerator, ShadowTaskInternalState } from \"./shadow-generator.js\";\nimport { retireGpuResources } from \"../engine/gpu-resource-retirement.js\";\n\n/** Generation of the material that ACTUALLY casts this caster mesh's shadow — the explicit\n * `_shadowCasterMaterial` override when set, else the mesh's own material. Lets the caster-set diff detect a\n * rebuild of the override caster material (which would otherwise be invisible to a check on the receive material). */\nfunction effectiveCasterGen(material: Material): number {\n const eff = material._shadowCasterMaterial ?? material;\n return (eff as { _csmGen?: number })._csmGen ?? 0;\n}\n\n/** CSM configuration captured by the generator and consumed by these hooks. */\nexport interface CsmConfig {\n /** @internal */\n _numCascades: number;\n /** @internal */\n _lambda: number;\n /** @internal */\n _cascadeBlendPercentage: number;\n /** @internal */\n _stabilizeCascades: boolean;\n /** @internal */\n _depthClamp: boolean;\n /** @internal */\n _shadowMaxZ: number | null;\n /** @internal */\n _bias: number;\n /** @internal */\n _worldSpaceBias: number | null;\n /** @internal */\n _darkness: number;\n /** @internal */\n _frustumEdgeFalloff: number;\n /** @internal */\n _mapSize: number;\n /** @internal */\n _forceRefreshEveryFrame: boolean;\n}\n\nexport interface CsmTaskState extends ShadowTaskInternalState {\n /** @internal */\n _tasks: RenderTask[];\n /** @internal */\n _cameras: Camera[];\n /** @internal */\n _scene: SceneContext;\n /** @internal */\n _cameraVersion: number;\n /** @internal */\n _lastCasterVersion: number;\n /** @internal */\n _lastLightVersion: number;\n /** @internal */\n _lastCamVersion: number;\n /** @internal */\n _uboData: Float32Array;\n /** @internal */\n _casterMeshes: readonly Mesh[];\n /** @internal Scene renderable version the cascade material views were built against. A material\n * swap (plugin/receiver variant change) rebuilds the swapped mesh's renderable + UBOs but leaves\n * this task's cached no-color material views pointing at the now-destroyed UBOs, so we rebuild when\n * the MATERIAL EPOCH changes — not on every renderable-version bump (a geometry resize bumps the\n * renderable version without touching materials, and is handled by a cheap re-record instead). */\n _renderableVersion: number;\n /** @internal Scene material epoch the cascade material views were built against (see `_renderableVersion`). */\n _materialEpoch: number;\n /** @internal Cached per-material no-color depth views, reused when a caster is added incrementally so a pure\n * caster-set change updates the existing cascade tasks instead of rebuilding and re-resolving every caster\n * (which leaked ~casters×cascades UBO handles each time the caster list was re-supplied). */\n _materialViews: Map<Material, MaterialView>;\n /** @internal Per-caster-material generation (`_csmGen`) snapshot at build. The incremental path is taken only\n * while every current caster's material gen is unchanged — i.e. no CASTER material was rebuilt (which would\n * leave its cached no-color view dangling). This is precise, unlike the global `_materialEpoch` which also\n * bumps for swaps of unrelated (non-caster) materials. */\n _casterMatGens: Map<Material, number>;\n /** @internal Per-caster cascade-cap snapshot used to update task membership incrementally. */\n _casterMaxCascades: Map<Mesh, number | undefined>;\n}\n\nexport const preloadCsmShadowTaskState = preloadPcfShadowTaskState;\n\n/** Build (or reuse) the CSM task state: N per-layer depth render targets + cameras + tasks. */\nexport function ensureCsmShadowTaskState(\n engine: EngineContext,\n scene: SceneContext,\n sg: ShadowGenerator,\n cfg: CsmConfig,\n casterMeshes: readonly Mesh[],\n existingState: ShadowTaskInternalState | null\n): CsmTaskState {\n const existing = existingState as CsmTaskState | null;\n if (existing) {\n if (existing._casterMeshes === casterMeshes && existing._renderableVersion === scene._renderableVersion) {\n return existing;\n }\n // The caster set is unchanged and NO material was rebuilt/swapped since these tasks were built (the\n // material epoch matches): the only thing that changed is geometry (e.g. resizeMeshGeometry reallocated\n // a caster's GPU buffers, bumping the renderable version). The cascade tasks' cached no-color material\n // views are still valid — only the bundles need refreshing to pick up the new buffer handles, which the\n // shadow scheduler's execute() already does (it re-records when the renderable version moves). So adopt\n // the new state markers and REUSE the existing tasks instead of recreating them — recreating tasks every\n // geometry edit re-compiles pipelines + churns bind-groups/bundles for the whole caster set (multi-MB,\n // never returned by the GPU allocator). Only a real material change (epoch bump) needs a full rebuild,\n // because that destroys the caster UBOs the cached views point at.\n if (existing._casterMeshes === casterMeshes && existing._materialEpoch === scene._materialEpoch) {\n existing._renderableVersion = scene._renderableVersion;\n return existing;\n }\n // The caster SET changed (different array). Decide INCREMENTAL vs full rebuild by whether any CURRENT\n // caster's OWN material was rebuilt since we built (its cached no-color view would dangle) — tracked via\n // a precise per-material gen, NOT the global `_materialEpoch` (which also bumps when an UNRELATED, non-\n // caster material is swapped, e.g. a lit scene mesh added near a caster set re-supply). If NO caster\n // material changed, update the cascade tasks IN PLACE: keep the unchanged casters' resolved depth packets\n // (so nothing is destroyed — no \"buffer used in submit while destroyed\" — and nothing leaks — the old\n // code re-resolved EVERY caster into fresh per-cascade UBO packets and never freed the prior ones,\n // leaking ~casters×cascades handles every time the caster list was re-supplied, which a consumer may do\n // per frame). Only add the new casters / drop departed ones (a regenerated caster's old packet is freed\n // by removeFromScene when its mesh is disposed; a persistent caster simply keeps its packet).\n let casterMatChanged = false;\n for (const m of casterMeshes) {\n const mat = m.material;\n if (!mat) {\n continue;\n }\n const stored = existing._casterMatGens.get(mat);\n if (stored !== undefined && stored !== effectiveCasterGen(mat)) {\n casterMatChanged = true;\n break;\n }\n }\n if (!casterMatChanged) {\n const nextSet = new Set(casterMeshes);\n const views = existing._materialViews;\n const gens = existing._casterMatGens;\n const caps = existing._casterMaxCascades;\n const tasks = existing._tasks;\n for (const m of existing._casterMeshes) {\n if (!nextSet.has(m) || m._shadowMaxCascade !== caps.get(m)) {\n caps.delete(m);\n for (const t of tasks) {\n removeMeshFromTask(t, m);\n }\n }\n }\n for (const m of casterMeshes) {\n const maxCascade = m._shadowMaxCascade;\n if (!caps.has(m) && m.material) {\n const view = getNoColorView(m.material, views);\n for (let c = 0; c < tasks.length; c++) {\n if (c <= (maxCascade ?? c)) {\n tasks[c]!.addMesh(m, { material: view });\n }\n }\n gens.set(m.material, effectiveCasterGen(m.material));\n }\n caps.set(m, maxCascade);\n }\n // Force each cascade to re-resolve its newly-added pending casters + re-bucket its binding lists.\n for (const t of tasks) {\n t._lastVersion = -1;\n }\n existing._casterMeshes = casterMeshes;\n existing._renderableVersion = scene._renderableVersion;\n return existing;\n }\n // A CASTER material was actually rebuilt (a material swap rebuilds its renderable + UBOs but\n // leaves our cached no-color material views dangling at the destroyed UBOs — the\n // \"Buffer used in submit while destroyed\" flood seen when a caster's material swaps variant on first\n // render). Rebuild the cascade tasks below with the casters' CURRENT materials and return the NEW\n // state — the caller swaps to it, so the OLD task is never recorded again. Its GPU buffers may still\n // be referenced by the next frame command buffer, especially during async pre-first-frame construction,\n // so retire it only after that frame has submitted and drained. Mirrors resizeMeshGeometry.\n retireGpuResources(engine, existing._task.dispose);\n }\n\n const materialViews = new Map<Material, MaterialView>();\n const n = cfg._numCascades;\n const tasks: RenderTask[] = [];\n const cameras: Camera[] = [];\n for (let i = 0; i < n; i++) {\n const layerView = sg._depthTexture.createView({ dimension: \"2d\", baseArrayLayer: i, arrayLayerCount: 1 });\n const rt: RenderTarget = {\n _descriptor: {\n size: { width: cfg._mapSize, height: cfg._mapSize },\n dFormat: \"depth32float\",\n _depthClearValue: 1,\n _depthCompare: \"less-equal\",\n samples: 1,\n },\n _colorTexture: null,\n _colorView: null,\n _depthTexture: sg._depthTexture,\n _depthView: layerView,\n _width: cfg._mapSize,\n _height: cfg._mapSize,\n _eager: true,\n _ownsDepthTexture: false, // borrowed: the shared CSM depth array is owned by the generator\n };\n const camera = createShadowCamera(sg);\n const task = createRenderTask({ name: `csm${i}`, rt, clr: true, cam: camera, _skipClusteredLights: true }, engine, scene);\n for (const mesh of casterMeshes) {\n const material = mesh.material;\n // Per-caster cascade cap: a capped caster renders only into layers 0..maxCascade (its far-layer\n // shadow is sub-texel anyway), saving the excluded layers' draws + pipeline switches.\n if (material && i <= (mesh._shadowMaxCascade ?? i)) {\n task.addMesh(mesh, { material: getNoColorView(material, materialViews) });\n }\n }\n tasks.push(task);\n cameras.push(camera);\n }\n\n const compositeTask = {\n record(): void {\n for (const t of tasks) {\n t.record();\n }\n },\n execute(): number {\n let draws = 0;\n for (const t of tasks) {\n draws += t.execute?.() ?? 0;\n }\n return draws;\n },\n dispose(): void {\n for (const t of tasks) {\n t.dispose();\n }\n },\n };\n\n // Snapshot each caster material's gen so the next caster-set change can tell whether a CASTER material was\n // rebuilt (→ full rebuild) or only the set changed (→ incremental, keeping unchanged casters' packets).\n const casterMatGens = new Map<Material, number>();\n const casterMaxCascades = new Map<Mesh, number | undefined>();\n for (const m of casterMeshes) {\n casterMaxCascades.set(m, m._shadowMaxCascade);\n if (m.material) {\n casterMatGens.set(m.material, effectiveCasterGen(m.material));\n }\n }\n return {\n _task: compositeTask,\n _tasks: tasks,\n _cameras: cameras,\n _scene: scene,\n _cameraVersion: 0,\n _lastCasterVersion: -1,\n _lastLightVersion: -1,\n _lastCamVersion: -1,\n _uboData: new Float32Array(80),\n _casterMeshes: casterMeshes,\n _renderableVersion: scene._renderableVersion,\n _materialEpoch: scene._materialEpoch,\n _materialViews: materialViews,\n _casterMatGens: casterMatGens,\n _casterMaxCascades: casterMaxCascades,\n };\n}\n\n/** Render every cascade layer for this frame, recomputing splits/matrices from the active camera. */\nexport function renderCsmShadowMap(engine: EngineContext, sg: ShadowGenerator, state: CsmTaskState, cfg: CsmConfig): number {\n const casterMeshes = state._casterMeshes;\n const camera = state._scene.camera;\n if (!camera) {\n return 0;\n }\n const casterVersion = casterVersionSum(casterMeshes);\n const lightVersion = sg._light.worldMatrixVersion;\n const camVersion = camera.worldMatrixVersion;\n if (!cfg._forceRefreshEveryFrame && casterVersion === state._lastCasterVersion && lightVersion === state._lastLightVersion && camVersion === state._lastCamVersion) {\n return 0;\n }\n\n const cascades = _computeCsmCascades(engine, camera, sg._light as DirectionalLight, cfg, casterMeshes);\n\n _writeCsmUbo(state._uboData, cascades, cfg);\n sg._version++;\n engine._device.queue.writeBuffer(sg._shadowUBO, 0, state._uboData as Float32Array<ArrayBuffer>);\n\n // Notify custom receivers (e.g. a ShaderMaterial that mirrors the cascade transforms into\n // its own uniforms) with this frame's freshly-computed receiver UBO. This fires inside the\n // shadow task — after the transforms are finalized but before the shadow map and main pass\n // render — so such receivers stay in lock-step with the depth map. Syncing from a\n // `onBeforeRender` callback instead would read the previous frame's transforms (a one-frame\n // lag that makes those shadows swim while the camera moves). The built-in standard/PBR/node\n // receivers don't need this: they bind `sg._shadowUBO` directly.\n const receiverCbs = sg._onReceiverData;\n if (receiverCbs) {\n for (let i = 0; i < receiverCbs.length; i++) {\n receiverCbs[i]!(state._uboData);\n }\n }\n\n state._cameraVersion++;\n for (let i = 0; i < cascades._transforms.length; i++) {\n const cam = state._cameras[i]!;\n cam.fov = 1;\n const clipBias = cfg._worldSpaceBias === null ? cfg._bias * 0.5 : csmWorldBiasClipOffset(cfg._worldSpaceBias, cascades._near[i]!, cascades._far[i]!);\n updateShadowCameraBase(cam, state._cameraVersion, cascades._near[i]!, cascades._far[i]!, cascades._views[i]!, _biasViewProjection(cascades._biased[i]!, clipBias));\n }\n\n state._lastCasterVersion = casterVersion;\n state._lastLightVersion = lightVersion;\n state._lastCamVersion = camVersion;\n return state._task.execute?.() ?? 0;\n}\n\n// ─── CSM math (isolated to this module) ─────────────────────────────\n\ninterface CsmCascades {\n /** @internal Unbiased receiver transform per cascade (col-major). */\n _transforms: Float32Array[];\n /** @internal Same as _transforms, used for the caster camera before bias. */\n _biased: Float32Array[];\n /** @internal Cascade light view matrix per cascade (col-major). */\n _views: Float32Array[];\n /** @internal Ortho near per cascade. */\n _near: number[];\n /** @internal Ortho far per cascade. */\n _far: number[];\n /** @internal Camera-view-space split distance per cascade. */\n _viewFrustumZ: number[];\n /** @internal Slice length per cascade. */\n _frustumLengths: number[];\n}\n\n/** Lite reverse-Z NDC frustum corners (near z=1, far z=0); xy each -1 or +1. */\nconst FRUSTUM_NDC: ReadonlyArray<readonly [number, number, number]> = [\n [-1, 1, 1],\n [1, 1, 1],\n [1, -1, 1],\n [-1, -1, 1],\n [-1, 1, 0],\n [1, 1, 0],\n [1, -1, 0],\n [-1, -1, 0],\n];\n\nfunction transformCoord(m: ArrayLike<number>, x: number, y: number, z: number): [number, number, number] {\n const X = m[0]! * x + m[4]! * y + m[8]! * z + m[12]!;\n const Y = m[1]! * x + m[5]! * y + m[9]! * z + m[13]!;\n const Z = m[2]! * x + m[6]! * y + m[10]! * z + m[14]!;\n const W = m[3]! * x + m[7]! * y + m[11]! * z + m[15]!;\n return [X / W, Y / W, Z / W];\n}\n\n/** Column-major OrthoOffCenterLH with half-z NDC (z: near→0, far→1). */\nfunction orthoOffCenterLH(l: number, r: number, b: number, t: number, n: number, f: number): Float32Array {\n const m = new Float32Array(16);\n m[0] = 2 / (r - l);\n m[5] = 2 / (t - b);\n m[10] = 1 / (f - n);\n m[12] = -(r + l) / (r - l);\n m[13] = -(t + b) / (t - b);\n m[14] = -n / (f - n);\n m[15] = 1;\n return m;\n}\n\nfunction _computeCsmCascades(engine: EngineContext, camera: Camera, light: DirectionalLight, cfg: CsmConfig, casterMeshes: readonly Mesh[]): CsmCascades {\n const near = camera.nearPlane;\n const far = camera.farPlane;\n const cameraRange = far - near;\n const shadowMaxZ = cfg._shadowMaxZ ?? far;\n const maxDistance = shadowMaxZ < far && shadowMaxZ >= near ? Math.min((shadowMaxZ - near) / (far - near), 1) : 1;\n const minDistance = 0;\n const minZ = near + minDistance * cameraRange;\n const maxZ = near + maxDistance * cameraRange;\n const range = maxZ - minZ;\n const ratio = maxZ / minZ;\n const n = cfg._numCascades;\n\n const breakDist: number[] = [];\n const viewFrustumZ: number[] = [];\n const frustumLengths: number[] = [];\n for (let i = 0; i < n; i++) {\n const p = (i + 1) / n;\n const log = minZ * ratio ** p;\n const uniform = minZ + range * p;\n const d = cfg._lambda * (log - uniform) + uniform;\n const prevBreak = i === 0 ? minDistance : breakDist[i - 1]!;\n breakDist[i] = (d - near) / cameraRange;\n viewFrustumZ[i] = d;\n frustumLengths[i] = (breakDist[i]! - prevBreak) * cameraRange;\n }\n\n // Light direction (normalized), avoiding a perfectly vertical degenerate case.\n let dx = light.direction.x;\n let dy = light.direction.y;\n let dz = light.direction.z;\n const dl = Math.hypot(dx, dy, dz) || 1;\n dx /= dl;\n dy /= dl;\n dz /= dl;\n if (Math.abs(dy) >= 1) {\n dz = 1e-13;\n }\n\n const aspect = engine.canvas.width / engine.canvas.height;\n const vp = getViewProjectionMatrix(camera, aspect) as unknown as ArrayLike<number>;\n const inv = mat4Invert(vp as never);\n const invViewProj: ArrayLike<number> = (inv as unknown as ArrayLike<number>) ?? vp;\n\n const aabb = _castersWorldAabb(casterMeshes);\n\n const transforms: Float32Array[] = [];\n const views: Float32Array[] = [];\n const nearOut: number[] = [];\n const farOut: number[] = [];\n\n for (let c = 0; c < n; c++) {\n const prevSplit = c === 0 ? 0 : breakDist[c - 1]!;\n const split = breakDist[c]!;\n\n // World-space frustum corners of this slice.\n const corners: [number, number, number][] = [];\n for (let k = 0; k < 8; k++) {\n const ndc = FRUSTUM_NDC[k]!;\n corners.push(transformCoord(invViewProj, ndc[0], ndc[1], ndc[2]));\n }\n for (let k = 0; k < 4; k++) {\n const nearC = corners[k]!;\n const farC = corners[k + 4]!;\n const rx = farC[0] - nearC[0];\n const ry = farC[1] - nearC[1];\n const rz = farC[2] - nearC[2];\n corners[k + 4] = [nearC[0] + rx * split, nearC[1] + ry * split, nearC[2] + rz * split];\n corners[k] = [nearC[0] + rx * prevSplit, nearC[1] + ry * prevSplit, nearC[2] + rz * prevSplit];\n }\n\n // Centroid.\n let cx = 0,\n cy = 0,\n cz = 0;\n for (const p of corners) {\n cx += p[0];\n cy += p[1];\n cz += p[2];\n }\n cx /= 8;\n cy /= 8;\n cz /= 8;\n\n let minX: number, maxX: number, minY: number, maxY: number, minEz: number, maxEz: number;\n let stableRadius = 0;\n if (cfg._stabilizeCascades) {\n let radius = 0;\n for (const p of corners) {\n radius = Math.max(radius, Math.hypot(p[0] - cx, p[1] - cy, p[2] - cz));\n }\n radius = Math.ceil(radius * 16) / 16;\n stableRadius = radius;\n minX = minY = minEz = -radius;\n maxX = maxY = maxEz = radius;\n } else {\n // Temp light view centred on the centroid to fit a tight AABB.\n const tmpView = buildLightViewMatrix(dx, dy, dz, cx, cy, cz);\n minX = minY = minEz = Infinity;\n maxX = maxY = maxEz = -Infinity;\n for (const p of corners) {\n const lp = transformCoord(tmpView, p[0], p[1], p[2]);\n minX = Math.min(minX, lp[0]);\n maxX = Math.max(maxX, lp[0]);\n minY = Math.min(minY, lp[1]);\n maxY = Math.max(maxY, lp[1]);\n minEz = Math.min(minEz, lp[2]);\n maxEz = Math.max(maxEz, lp[2]);\n }\n }\n\n // Shadow camera sits behind the slice along the light direction.\n const eyeX = cx + dx * minEz;\n const eyeY = cy + dy * minEz;\n const eyeZ = cz + dz * minEz;\n const view = buildLightViewMatrix(dx, dy, dz, eyeX, eyeY, eyeZ);\n\n let viewMinZ = 0;\n let viewMaxZ = maxEz - minEz;\n\n // Tighten Z to the caster bounding box in cascade view space (depthClamp = false behaviour:\n // keep all casters inside the frustum so no GPU depth-clip feature is required).\n if (aabb) {\n let cMinZ = Infinity;\n let cMaxZ = -Infinity;\n for (let k = 0; k < 8; k++) {\n const wx = k & 1 ? aabb._max[0] : aabb._min[0];\n const wy = k & 2 ? aabb._max[1] : aabb._min[1];\n const wz = k & 4 ? aabb._max[2] : aabb._min[2];\n const lz = view[2]! * wx + view[6]! * wy + view[10]! * wz + view[14]!;\n cMinZ = Math.min(cMinZ, lz);\n cMaxZ = Math.max(cMaxZ, lz);\n }\n if (cMinZ <= viewMaxZ) {\n viewMinZ = Math.min(viewMinZ, cMinZ);\n viewMaxZ = Math.min(viewMaxZ, cMaxZ);\n }\n\n // Z is intentionally NOT quantized here. The caster-AABB fit (cMinZ/cMaxZ) is C0-continuous in the\n // light direction — each is a min/max of linear functions of the light vector, so it has kinks but no\n // jumps — meaning the near/far drift SMOOTHLY as the light rotates. A constant NDC depth bias maps to a\n // WORLD bias of bias·(far−near), and the stored depths are likewise normalised by (far−near); the old\n // `zq = max(0.5, radius/128)` floor/ceil snapped that range to a grid, so both the effective bias AND\n // the stored depth STEPPED at each quantum boundary as the light direction changed — appearing as\n // self-shadow acne that VIBRATES. Removing the quantize makes those steps a sub-millimetre, imperceptible\n // drift, and still covers the moving-caster case it was added for (the range drifts, it never pops).\n }\n\n // The caster matrix adds the world-space bias toward clip Z=1. Reserve the same distance at the far plane\n // so geometry on the tightly fitted caster bound remains inside the clip volume after that offset.\n if (cfg._worldSpaceBias) {\n viewMaxZ += cfg._worldSpaceBias;\n }\n\n const proj0 = orthoOffCenterLH(minX, maxX, minY, maxY, viewMinZ, viewMaxZ);\n let transform = multiply4x4(proj0, view);\n\n // Texel-snap: lock the shadow grid to world space so it does not crawl as the camera moves, by rounding a\n // fixed WORLD anchor onto the shadow-map texel grid. BJS anchors the WORLD ORIGIN. With a STILL camera and\n // a slowly ROTATING light that is the cause of the visible \"vibration\": the eye is recentred on the cascade\n // centre every frame, so the snap residual is the anchor's offset from the centre measured along the light\n // axes — and the world origin's offset from the centre is large (≈ the cascade's distance from origin), so\n // its projection sweeps many texels per degree of light rotation and Math.round trips a full-texel correction\n // again and again → the whole map pops/boils. We instead anchor the world-grid point NEAREST the cascade\n // centre (cell = one texel in world units): it is still a fixed world point (a translating camera only ever\n // sees whole-cell anchor switches, ≤ a sub-texel grid wiggle that PCF hides), but its offset from the centre\n // is < 1 texel, so a full light rotation sweeps it < 1 texel → effectively no rotation pop. Non-stabilized\n // path keeps the origin anchor (no stableRadius → no texel-world size to build the world grid from).\n let aClipX = transform[12]!;\n let aClipY = transform[13]!;\n if (cfg._stabilizeCascades && stableRadius > 0) {\n const texelWorld = (2 * stableRadius) / cfg._mapSize;\n // Align the world anchor grid to the LIGHT's right/up axes (R,U), not world x/y/z. A translating camera then\n // switches cells by exactly ONE texel along R/U -> an integer texel shift in clip space (no crawl). The old\n // world-axis grid jumped texelWorld along a world axis, which projects to a NON-integer texel count (R,U are\n // not the world axes) -> the sub-texel wiggle that crawled during translation. R,U = view rows 0,1.\n const rX = view[0]!,\n rY = view[4]!,\n rZ = view[8]!;\n const uX = view[1]!,\n uY = view[5]!,\n uZ = view[9]!;\n // Project the centre onto R,U, round to the texel grid, rebuild the world anchor in the R-U plane (the\n // light-dir component only affects clip Z, so dropping it leaves clip X/Y, which depend on R,U, exact).\n const sr = Math.round((rX * cx + rY * cy + rZ * cz) / texelWorld) * texelWorld;\n const tr = Math.round((uX * cx + uY * cy + uZ * cz) / texelWorld) * texelWorld;\n const ax = sr * rX + tr * uX;\n const ay = sr * rY + tr * uY;\n const az = sr * rZ + tr * uZ;\n aClipX = transform[0]! * ax + transform[4]! * ay + transform[8]! * az + transform[12]!;\n aClipY = transform[1]! * ax + transform[5]! * ay + transform[9]! * az + transform[13]!;\n }\n const ox = aClipX * (cfg._mapSize / 2);\n const oy = aClipY * (cfg._mapSize / 2);\n const offX = (Math.round(ox) - ox) * (2 / cfg._mapSize);\n const offY = (Math.round(oy) - oy) * (2 / cfg._mapSize);\n const snap = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, offX, offY, 0, 1]);\n const proj = multiply4x4(snap, proj0);\n transform = multiply4x4(proj, view);\n\n transforms.push(transform);\n views.push(view);\n nearOut.push(viewMinZ);\n farOut.push(viewMaxZ);\n }\n\n return {\n _transforms: transforms,\n _biased: transforms.map((t) => new Float32Array(t)),\n _views: views,\n _near: nearOut,\n _far: farOut,\n _viewFrustumZ: viewFrustumZ,\n _frustumLengths: frustumLengths,\n };\n}\n\nfunction _castersWorldAabb(casterMeshes: readonly Mesh[]): { _min: [number, number, number]; _max: [number, number, number] } | null {\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity,\n maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (const mesh of casterMeshes) {\n // Thin-instanced casters are drawn at `finalWorld = mesh.world * instanceMatrix` (see\n // thin-instance-fragment.ts), so a single `mesh.worldMatrix × boundMin/Max` box ignores the per-instance\n // spread entirely — one prototype-sized box wrecks the cascade Z-fit (an off-world herd collapsed every\n // shadow). Bound the caster by the union of every drawn instance instead, using the SAME composition the\n // shader uses.\n const ti = mesh.thinInstances;\n if (ti && ti.count > 0 && ti.matrices) {\n const a = _thinInstanceWorldAabb(mesh, ti);\n if (a) {\n minX = Math.min(minX, a._min[0]);\n maxX = Math.max(maxX, a._max[0]);\n minY = Math.min(minY, a._min[1]);\n maxY = Math.max(maxY, a._max[1]);\n minZ = Math.min(minZ, a._min[2]);\n maxZ = Math.max(maxZ, a._max[2]);\n }\n continue;\n }\n const world = mesh.worldMatrix;\n const bmin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const bmax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n for (let k = 0; k < 8; k++) {\n const lx = k & 1 ? bmax[0]! : bmin[0]!;\n const ly = k & 2 ? bmax[1]! : bmin[1]!;\n const lz = k & 4 ? bmax[2]! : bmin[2]!;\n const wx = world[0]! * lx + world[4]! * ly + world[8]! * lz + world[12]!;\n const wy = world[1]! * lx + world[5]! * ly + world[9]! * lz + world[13]!;\n const wz = world[2]! * lx + world[6]! * ly + world[10]! * lz + world[14]!;\n minX = Math.min(minX, wx);\n maxX = Math.max(maxX, wx);\n minY = Math.min(minY, wy);\n maxY = Math.max(maxY, wy);\n minZ = Math.min(minZ, wz);\n maxZ = Math.max(maxZ, wz);\n }\n }\n if (!Number.isFinite(minX)) {\n return null;\n }\n return { _min: [minX, minY, minZ], _max: [maxX, maxY, maxZ] };\n}\n\ninterface ThinCasterAabb {\n _min: [number, number, number];\n _max: [number, number, number];\n}\n\n/** Per-mesh cache of a thin-instanced caster's world AABB. It keys on instance data, prototype\n * transform, and the shared non-transform caster epoch.\n * Lazily allocated so this module keeps zero import-time side effects and stays tree-shakable. */\nlet _thinCasterAabbCache: WeakMap<Mesh, { _version: number; _worldVersion: number; _aabb: ThinCasterAabb | null }> | null = null;\nfunction _getThinCasterAabbCache(): WeakMap<Mesh, { _version: number; _worldVersion: number; _aabb: ThinCasterAabb | null }> {\n if (!_thinCasterAabbCache) {\n _thinCasterAabbCache = new WeakMap();\n }\n return _thinCasterAabbCache;\n}\n\n/** World AABB of a thin-instanced caster. Matches the shader's `finalWorld = mesh.world * instanceMatrix`\n * exactly: each local bound corner is transformed by the per-instance matrix, then by the prototype mesh\n * world matrix. Parked/degenerate instances (zero linear part — drawn as zero-area, used to hide an unused\n * tail) are skipped so a tail parked far off-world can't balloon the box. */\nfunction _thinInstanceWorldAabb(mesh: Mesh, ti: NonNullable<Mesh[\"thinInstances\"]>): ThinCasterAabb | null {\n const cache = _getThinCasterAabbCache();\n const worldVersion = mesh.worldMatrixVersion;\n const cached = cache.get(mesh);\n if (cached && cached._version === ti._version && cached._worldVersion === worldVersion) {\n return cached._aabb;\n }\n // Hoist the prototype world matrix once (worldMatrix is a getter) — it is constant across all instances.\n const world = mesh.worldMatrix;\n const bmin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const bmax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n const mats = ti.matrices;\n const count = Math.min(ti.count, (mats.length / 16) | 0);\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity,\n maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let i = 0; i < count; i++) {\n const o = i * 16;\n // Skip parked instances (zero 3×3 linear part → zero-area triangles that rasterize to nothing).\n const lin =\n Math.abs(mats[o]!) +\n Math.abs(mats[o + 1]!) +\n Math.abs(mats[o + 2]!) +\n Math.abs(mats[o + 4]!) +\n Math.abs(mats[o + 5]!) +\n Math.abs(mats[o + 6]!) +\n Math.abs(mats[o + 8]!) +\n Math.abs(mats[o + 9]!) +\n Math.abs(mats[o + 10]!);\n if (lin < 1e-9) {\n continue;\n }\n for (let k = 0; k < 8; k++) {\n const lx = k & 1 ? bmax[0]! : bmin[0]!;\n const ly = k & 2 ? bmax[1]! : bmin[1]!;\n const lz = k & 4 ? bmax[2]! : bmin[2]!;\n // 1) instance-local: ip = instanceMatrix * localCorner\n const ix = mats[o]! * lx + mats[o + 4]! * ly + mats[o + 8]! * lz + mats[o + 12]!;\n const iy = mats[o + 1]! * lx + mats[o + 5]! * ly + mats[o + 9]! * lz + mats[o + 13]!;\n const iz = mats[o + 2]! * lx + mats[o + 6]! * ly + mats[o + 10]! * lz + mats[o + 14]!;\n // 2) world: wp = mesh.world * ip (matches finalWorld = mesh.world * instanceMatrix)\n const wx = world[0]! * ix + world[4]! * iy + world[8]! * iz + world[12]!;\n const wy = world[1]! * ix + world[5]! * iy + world[9]! * iz + world[13]!;\n const wz = world[2]! * ix + world[6]! * iy + world[10]! * iz + world[14]!;\n if (wx < minX) {\n minX = wx;\n }\n if (wx > maxX) {\n maxX = wx;\n }\n if (wy < minY) {\n minY = wy;\n }\n if (wy > maxY) {\n maxY = wy;\n }\n if (wz < minZ) {\n minZ = wz;\n }\n if (wz > maxZ) {\n maxZ = wz;\n }\n }\n }\n const aabb: ThinCasterAabb | null = Number.isFinite(minX) ? { _min: [minX, minY, minZ], _max: [maxX, maxY, maxZ] } : null;\n cache.set(mesh, { _version: ti._version, _worldVersion: worldVersion, _aabb: aabb });\n return aabb;\n}\n\nfunction _writeCsmUbo(out: Float32Array, cascades: CsmCascades, cfg: CsmConfig): void {\n out.fill(0);\n const n = cascades._transforms.length;\n for (let i = 0; i < n; i++) {\n out.set(cascades._transforms[i]!, i * 16);\n }\n for (let i = 0; i < n; i++) {\n out[64 + i] = cascades._viewFrustumZ[i]!;\n out[68 + i] = cascades._frustumLengths[i]!;\n }\n out[72] = cfg._darkness;\n out[73] = cfg._mapSize;\n out[74] = 1 / cfg._mapSize;\n out[75] = cfg._frustumEdgeFalloff;\n out[76] = n;\n out[77] = cfg._cascadeBlendPercentage === 0 ? 10000 : 1 / cfg._cascadeBlendPercentage;\n}\n\n/** @internal Convert a physical caster offset to the clip-space Z offset for one orthographic cascade. */\nexport function csmWorldBiasClipOffset(worldSpaceBias: number, near: number, far: number): number {\n const range = far - near;\n if (!Number.isFinite(worldSpaceBias) || worldSpaceBias <= 0 || !Number.isFinite(range) || range <= 0) {\n return 0;\n }\n return worldSpaceBias / range;\n}\n\nfunction _biasViewProjection(viewProj: Float32Array, clipOffset: number): Float32Array {\n const biased = new Float32Array(viewProj);\n for (let col = 0; col < 4; col++) {\n const z = 2 + col * 4;\n const w = 3 + col * 4;\n biased[z] = biased[z]! + clipOffset * biased[w]!;\n }\n return biased;\n}\n"],"names":["tasks"],"mappings":"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"}
1
+ {"version":3,"file":"csm-shadow-task-hooks.js","sources":["../../../src/shadow/csm-shadow-task-hooks.ts"],"sourcesContent":["/** Internal CSM (cascaded shadow map) task hooks owned by CSM shadow generators.\n *\n * Mirrors `pcf-shadow-task-hooks.ts`, but renders N cascade layers of a depth\n * `texture_2d_array` and computes per-cascade frustum-split + orthographic-fit\n * matrices from the active camera. All CSM-only math (frustum-corner fit,\n * ortho-off-center, texel snap) lives here so plain ESM/PCF scenes never bundle\n * it. The light view matrix + 4×4 multiply are shared helpers (already used by\n * ESM/PCF) so reusing them adds zero bytes.\n */\n\nimport type { Camera } from \"../camera/camera.js\";\nimport type { DirectionalLight } from \"../light/directional-light.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Material, MaterialView } from \"../material/material.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport { createRenderTask, removeMeshFromTask, type RenderTask } from \"../frame-graph/render-task.js\";\nimport { getViewProjectionMatrix, getEffectiveAspectRatio, _cameraChangeKey } from \"../camera/camera.js\";\nimport { mat4Invert } from \"../math/mat4-invert.js\";\nimport { buildLightViewMatrix, casterVersionSum, createShadowCamera, multiply4x4, updateShadowCameraBase } from \"./shadow-base.js\";\nimport { getNoColorView, preloadPcfShadowTaskState } from \"./pcf-shadow-task-hooks.js\";\nimport type { ShadowGenerator, ShadowTaskInternalState } from \"./shadow-generator.js\";\nimport { retireGpuResources } from \"../engine/gpu-resource-retirement.js\";\n\n/** Generation of the material that ACTUALLY casts this caster mesh's shadow — the explicit\n * `_shadowCasterMaterial` override when set, else the mesh's own material. Lets the caster-set diff detect a\n * rebuild of the override caster material (which would otherwise be invisible to a check on the receive material). */\nfunction effectiveCasterGen(material: Material): number {\n const eff = material._shadowCasterMaterial ?? material;\n return (eff as { _csmGen?: number })._csmGen ?? 0;\n}\n\n/** CSM configuration captured by the generator and consumed by these hooks. */\nexport interface CsmConfig {\n /** @internal */\n _numCascades: number;\n /** @internal */\n _lambda: number;\n /** @internal */\n _cascadeBlendPercentage: number;\n /** @internal */\n _stabilizeCascades: boolean;\n /** @internal */\n _depthClamp: boolean;\n /** @internal */\n _shadowMaxZ: number | null;\n /** @internal */\n _bias: number;\n /** @internal */\n _worldSpaceBias: number | null;\n /** @internal */\n _darkness: number;\n /** @internal */\n _frustumEdgeFalloff: number;\n /** @internal */\n _mapSize: number;\n /** @internal */\n _forceRefreshEveryFrame: boolean;\n}\n\nexport interface CsmTaskState extends ShadowTaskInternalState {\n /** @internal */\n _tasks: RenderTask[];\n /** @internal */\n _cameras: Camera[];\n /** @internal */\n _scene: SceneContext;\n /** @internal */\n _cameraVersion: number;\n /** @internal */\n _lastCasterVersion: number;\n /** @internal */\n _lastLightVersion: number;\n /** @internal */\n _lastCamVersion: number;\n /** @internal Effective aspect ratio the cascades were last fit against. */\n _lastCamAspect: number;\n /** @internal */\n _uboData: Float32Array;\n /** @internal */\n _casterMeshes: readonly Mesh[];\n /** @internal Scene renderable version the cascade material views were built against. A material\n * swap (plugin/receiver variant change) rebuilds the swapped mesh's renderable + UBOs but leaves\n * this task's cached no-color material views pointing at the now-destroyed UBOs, so we rebuild when\n * the MATERIAL EPOCH changes — not on every renderable-version bump (a geometry resize bumps the\n * renderable version without touching materials, and is handled by a cheap re-record instead). */\n _renderableVersion: number;\n /** @internal Scene material epoch the cascade material views were built against (see `_renderableVersion`). */\n _materialEpoch: number;\n /** @internal Cached per-material no-color depth views, reused when a caster is added incrementally so a pure\n * caster-set change updates the existing cascade tasks instead of rebuilding and re-resolving every caster\n * (which leaked ~casters×cascades UBO handles each time the caster list was re-supplied). */\n _materialViews: Map<Material, MaterialView>;\n /** @internal Per-caster-material generation (`_csmGen`) snapshot at build. The incremental path is taken only\n * while every current caster's material gen is unchanged — i.e. no CASTER material was rebuilt (which would\n * leave its cached no-color view dangling). This is precise, unlike the global `_materialEpoch` which also\n * bumps for swaps of unrelated (non-caster) materials. */\n _casterMatGens: Map<Material, number>;\n /** @internal Per-caster cascade-cap snapshot used to update task membership incrementally. */\n _casterMaxCascades: Map<Mesh, number | undefined>;\n}\n\nexport const preloadCsmShadowTaskState = preloadPcfShadowTaskState;\n\n/** Build (or reuse) the CSM task state: N per-layer depth render targets + cameras + tasks. */\nexport function ensureCsmShadowTaskState(\n engine: EngineContext,\n scene: SceneContext,\n sg: ShadowGenerator,\n cfg: CsmConfig,\n casterMeshes: readonly Mesh[],\n existingState: ShadowTaskInternalState | null\n): CsmTaskState {\n const existing = existingState as CsmTaskState | null;\n if (existing) {\n if (existing._casterMeshes === casterMeshes && existing._renderableVersion === scene._renderableVersion) {\n return existing;\n }\n // The caster set is unchanged and NO material was rebuilt/swapped since these tasks were built (the\n // material epoch matches): the only thing that changed is geometry (e.g. resizeMeshGeometry reallocated\n // a caster's GPU buffers, bumping the renderable version). The cascade tasks' cached no-color material\n // views are still valid — only the bundles need refreshing to pick up the new buffer handles, which the\n // shadow scheduler's execute() already does (it re-records when the renderable version moves). So adopt\n // the new state markers and REUSE the existing tasks instead of recreating them — recreating tasks every\n // geometry edit re-compiles pipelines + churns bind-groups/bundles for the whole caster set (multi-MB,\n // never returned by the GPU allocator). Only a real material change (epoch bump) needs a full rebuild,\n // because that destroys the caster UBOs the cached views point at.\n if (existing._casterMeshes === casterMeshes && existing._materialEpoch === scene._materialEpoch) {\n existing._renderableVersion = scene._renderableVersion;\n return existing;\n }\n // The caster SET changed (different array). Decide INCREMENTAL vs full rebuild by whether any CURRENT\n // caster's OWN material was rebuilt since we built (its cached no-color view would dangle) — tracked via\n // a precise per-material gen, NOT the global `_materialEpoch` (which also bumps when an UNRELATED, non-\n // caster material is swapped, e.g. a lit scene mesh added near a caster set re-supply). If NO caster\n // material changed, update the cascade tasks IN PLACE: keep the unchanged casters' resolved depth packets\n // (so nothing is destroyed — no \"buffer used in submit while destroyed\" — and nothing leaks — the old\n // code re-resolved EVERY caster into fresh per-cascade UBO packets and never freed the prior ones,\n // leaking ~casters×cascades handles every time the caster list was re-supplied, which a consumer may do\n // per frame). Only add the new casters / drop departed ones (a regenerated caster's old packet is freed\n // by removeFromScene when its mesh is disposed; a persistent caster simply keeps its packet).\n let casterMatChanged = false;\n for (const m of casterMeshes) {\n const mat = m.material;\n if (!mat) {\n continue;\n }\n const stored = existing._casterMatGens.get(mat);\n if (stored !== undefined && stored !== effectiveCasterGen(mat)) {\n casterMatChanged = true;\n break;\n }\n }\n if (!casterMatChanged) {\n const nextSet = new Set(casterMeshes);\n const views = existing._materialViews;\n const gens = existing._casterMatGens;\n const caps = existing._casterMaxCascades;\n const tasks = existing._tasks;\n for (const m of existing._casterMeshes) {\n if (!nextSet.has(m) || m._shadowMaxCascade !== caps.get(m)) {\n caps.delete(m);\n for (const t of tasks) {\n removeMeshFromTask(t, m);\n }\n }\n }\n for (const m of casterMeshes) {\n const maxCascade = m._shadowMaxCascade;\n if (!caps.has(m) && m.material) {\n const view = getNoColorView(m.material, views);\n for (let c = 0; c < tasks.length; c++) {\n if (c <= (maxCascade ?? c)) {\n tasks[c]!.addMesh(m, { material: view });\n }\n }\n gens.set(m.material, effectiveCasterGen(m.material));\n }\n caps.set(m, maxCascade);\n }\n // Force each cascade to re-resolve its newly-added pending casters + re-bucket its binding lists.\n for (const t of tasks) {\n t._lastVersion = -1;\n }\n existing._casterMeshes = casterMeshes;\n existing._renderableVersion = scene._renderableVersion;\n return existing;\n }\n // A CASTER material was actually rebuilt (a material swap rebuilds its renderable + UBOs but\n // leaves our cached no-color material views dangling at the destroyed UBOs — the\n // \"Buffer used in submit while destroyed\" flood seen when a caster's material swaps variant on first\n // render). Rebuild the cascade tasks below with the casters' CURRENT materials and return the NEW\n // state — the caller swaps to it, so the OLD task is never recorded again. Its GPU buffers may still\n // be referenced by the next frame command buffer, especially during async pre-first-frame construction,\n // so retire it only after that frame has submitted and drained. Mirrors resizeMeshGeometry.\n retireGpuResources(engine, existing._task.dispose);\n }\n\n const materialViews = new Map<Material, MaterialView>();\n const n = cfg._numCascades;\n const tasks: RenderTask[] = [];\n const cameras: Camera[] = [];\n for (let i = 0; i < n; i++) {\n const layerView = sg._depthTexture.createView({ dimension: \"2d\", baseArrayLayer: i, arrayLayerCount: 1 });\n const rt: RenderTarget = {\n _descriptor: {\n size: { width: cfg._mapSize, height: cfg._mapSize },\n dFormat: \"depth32float\",\n _depthClearValue: 1,\n _depthCompare: \"less-equal\",\n samples: 1,\n },\n _colorTexture: null,\n _colorView: null,\n _depthTexture: sg._depthTexture,\n _depthView: layerView,\n _width: cfg._mapSize,\n _height: cfg._mapSize,\n _eager: true,\n _ownsDepthTexture: false, // borrowed: the shared CSM depth array is owned by the generator\n };\n const camera = createShadowCamera(sg);\n const task = createRenderTask({ name: `csm${i}`, rt, clr: true, cam: camera, _skipClusteredLights: true }, engine, scene);\n for (const mesh of casterMeshes) {\n const material = mesh.material;\n // Per-caster cascade cap: a capped caster renders only into layers 0..maxCascade (its far-layer\n // shadow is sub-texel anyway), saving the excluded layers' draws + pipeline switches.\n if (material && i <= (mesh._shadowMaxCascade ?? i)) {\n task.addMesh(mesh, { material: getNoColorView(material, materialViews) });\n }\n }\n tasks.push(task);\n cameras.push(camera);\n }\n\n const compositeTask = {\n record(): void {\n for (const t of tasks) {\n t.record();\n }\n },\n execute(): number {\n let draws = 0;\n for (const t of tasks) {\n draws += t.execute?.() ?? 0;\n }\n return draws;\n },\n dispose(): void {\n for (const t of tasks) {\n t.dispose();\n }\n },\n };\n\n // Snapshot each caster material's gen so the next caster-set change can tell whether a CASTER material was\n // rebuilt (→ full rebuild) or only the set changed (→ incremental, keeping unchanged casters' packets).\n const casterMatGens = new Map<Material, number>();\n const casterMaxCascades = new Map<Mesh, number | undefined>();\n for (const m of casterMeshes) {\n casterMaxCascades.set(m, m._shadowMaxCascade);\n if (m.material) {\n casterMatGens.set(m.material, effectiveCasterGen(m.material));\n }\n }\n return {\n _task: compositeTask,\n _tasks: tasks,\n _cameras: cameras,\n _scene: scene,\n _cameraVersion: 0,\n _lastCasterVersion: -1,\n _lastLightVersion: -1,\n _lastCamVersion: -1,\n _lastCamAspect: -1,\n _uboData: new Float32Array(80),\n _casterMeshes: casterMeshes,\n _renderableVersion: scene._renderableVersion,\n _materialEpoch: scene._materialEpoch,\n _materialViews: materialViews,\n _casterMatGens: casterMatGens,\n _casterMaxCascades: casterMaxCascades,\n };\n}\n\n/** Render every cascade layer for this frame, recomputing splits/matrices from the active camera. */\nexport function renderCsmShadowMap(engine: EngineContext, sg: ShadowGenerator, state: CsmTaskState, cfg: CsmConfig): number {\n const casterMeshes = state._casterMeshes;\n const camera = state._scene.camera;\n if (!camera) {\n return 0;\n }\n const casterVersion = casterVersionSum(casterMeshes);\n const lightVersion = sg._light.worldMatrixVersion;\n const camVersion = _cameraChangeKey(camera);\n // Effective aspect is part of the key: a viewport or surface resize changes the camera\n // frustum the cascades are fit to while every version above stays put.\n const camAspect = csmCameraAspect(state._scene, camera);\n if (\n !cfg._forceRefreshEveryFrame &&\n casterVersion === state._lastCasterVersion &&\n lightVersion === state._lastLightVersion &&\n camVersion === state._lastCamVersion &&\n camAspect === state._lastCamAspect\n ) {\n return 0;\n }\n\n const cascades = _computeCsmCascades(state._scene, camera, sg._light as DirectionalLight, cfg, casterMeshes);\n\n _writeCsmUbo(state._uboData, cascades, cfg);\n sg._version++;\n engine._device.queue.writeBuffer(sg._shadowUBO, 0, state._uboData as Float32Array<ArrayBuffer>);\n\n // Notify custom receivers (e.g. a ShaderMaterial that mirrors the cascade transforms into\n // its own uniforms) with this frame's freshly-computed receiver UBO. This fires inside the\n // shadow task — after the transforms are finalized but before the shadow map and main pass\n // render — so such receivers stay in lock-step with the depth map. Syncing from a\n // `onBeforeRender` callback instead would read the previous frame's transforms (a one-frame\n // lag that makes those shadows swim while the camera moves). The built-in standard/PBR/node\n // receivers don't need this: they bind `sg._shadowUBO` directly.\n const receiverCbs = sg._onReceiverData;\n if (receiverCbs) {\n for (let i = 0; i < receiverCbs.length; i++) {\n receiverCbs[i]!(state._uboData);\n }\n }\n\n state._cameraVersion++;\n for (let i = 0; i < cascades._transforms.length; i++) {\n const cam = state._cameras[i]!;\n cam.fov = 1;\n const clipBias = cfg._worldSpaceBias === null ? cfg._bias * 0.5 : csmWorldBiasClipOffset(cfg._worldSpaceBias, cascades._near[i]!, cascades._far[i]!);\n updateShadowCameraBase(cam, state._cameraVersion, cascades._near[i]!, cascades._far[i]!, cascades._views[i]!, _biasViewProjection(cascades._biased[i]!, clipBias));\n }\n\n state._lastCasterVersion = casterVersion;\n state._lastLightVersion = lightVersion;\n state._lastCamVersion = camVersion;\n state._lastCamAspect = camAspect;\n return state._task.execute?.() ?? 0;\n}\n\n// ─── CSM math (isolated to this module) ─────────────────────────────\n\ninterface CsmCascades {\n /** @internal Unbiased receiver transform per cascade (col-major). */\n _transforms: Float32Array[];\n /** @internal Same as _transforms, used for the caster camera before bias. */\n _biased: Float32Array[];\n /** @internal Cascade light view matrix per cascade (col-major). */\n _views: Float32Array[];\n /** @internal Ortho near per cascade. */\n _near: number[];\n /** @internal Ortho far per cascade. */\n _far: number[];\n /** @internal Camera-view-space split distance per cascade. */\n _viewFrustumZ: number[];\n /** @internal Slice length per cascade. */\n _frustumLengths: number[];\n}\n\n/** Lite reverse-Z NDC frustum corners (near z=1, far z=0); xy each -1 or +1. */\nconst FRUSTUM_NDC: ReadonlyArray<readonly [number, number, number]> = [\n [-1, 1, 1],\n [1, 1, 1],\n [1, -1, 1],\n [-1, -1, 1],\n [-1, 1, 0],\n [1, 1, 0],\n [1, -1, 0],\n [-1, -1, 0],\n];\n\nfunction transformCoord(m: ArrayLike<number>, x: number, y: number, z: number): [number, number, number] {\n const X = m[0]! * x + m[4]! * y + m[8]! * z + m[12]!;\n const Y = m[1]! * x + m[5]! * y + m[9]! * z + m[13]!;\n const Z = m[2]! * x + m[6]! * y + m[10]! * z + m[14]!;\n const W = m[3]! * x + m[7]! * y + m[11]! * z + m[15]!;\n return [X / W, Y / W, Z / W];\n}\n\n/** Column-major OrthoOffCenterLH with half-z NDC (z: near→0, far→1). */\nfunction orthoOffCenterLH(l: number, r: number, b: number, t: number, n: number, f: number): Float32Array {\n const m = new Float32Array(16);\n m[0] = 2 / (r - l);\n m[5] = 2 / (t - b);\n m[10] = 1 / (f - n);\n m[12] = -(r + l) / (r - l);\n m[13] = -(t + b) / (t - b);\n m[14] = -n / (f - n);\n m[15] = 1;\n return m;\n}\n\n/** Effective aspect of the surface the scene actually renders into.\n *\n * Not `engine.canvas`: a scene is bound to `scene.surface` (an `EngineContext` is itself a\n * `SurfaceContext`, so that is the canvas for the common single-surface case, but an\n * auxiliary surface created via `createSurface` has its own swapchain size). Fitting\n * cascades to the canvas would use a frustum the scene never draws. `getEffectiveAspectRatio`\n * additionally folds in the camera's normalized viewport, matching `_writePassSceneUBO`. */\nfunction csmCameraAspect(scene: SceneContext, camera: Camera): number {\n const rt = scene.surface.scRT;\n return getEffectiveAspectRatio(camera, rt._width, rt._height);\n}\n\nfunction _computeCsmCascades(scene: SceneContext, camera: Camera, light: DirectionalLight, cfg: CsmConfig, casterMeshes: readonly Mesh[]): CsmCascades {\n const near = camera.nearPlane;\n const far = camera.farPlane;\n const cameraRange = far - near;\n const shadowMaxZ = cfg._shadowMaxZ ?? far;\n const maxDistance = shadowMaxZ < far && shadowMaxZ >= near ? Math.min((shadowMaxZ - near) / (far - near), 1) : 1;\n const minDistance = 0;\n const minZ = near + minDistance * cameraRange;\n const maxZ = near + maxDistance * cameraRange;\n const range = maxZ - minZ;\n const ratio = maxZ / minZ;\n const n = cfg._numCascades;\n\n const breakDist: number[] = [];\n const viewFrustumZ: number[] = [];\n const frustumLengths: number[] = [];\n for (let i = 0; i < n; i++) {\n const p = (i + 1) / n;\n const log = minZ * ratio ** p;\n const uniform = minZ + range * p;\n const d = cfg._lambda * (log - uniform) + uniform;\n const prevBreak = i === 0 ? minDistance : breakDist[i - 1]!;\n breakDist[i] = (d - near) / cameraRange;\n viewFrustumZ[i] = d;\n frustumLengths[i] = (breakDist[i]! - prevBreak) * cameraRange;\n }\n\n // Light direction (normalized), avoiding a perfectly vertical degenerate case.\n let dx = light.direction.x;\n let dy = light.direction.y;\n let dz = light.direction.z;\n const dl = Math.hypot(dx, dy, dz) || 1;\n dx /= dl;\n dy /= dl;\n dz /= dl;\n if (Math.abs(dy) >= 1) {\n dz = 1e-13;\n }\n\n // Effective aspect, not the raw canvas ratio: a camera with a normalized viewport renders\n const aspect = csmCameraAspect(scene, camera);\n const vp = getViewProjectionMatrix(camera, aspect) as unknown as ArrayLike<number>;\n const inv = mat4Invert(vp as never);\n const invViewProj: ArrayLike<number> = (inv as unknown as ArrayLike<number>) ?? vp;\n\n const aabb = _castersWorldAabb(casterMeshes);\n\n const transforms: Float32Array[] = [];\n const views: Float32Array[] = [];\n const nearOut: number[] = [];\n const farOut: number[] = [];\n\n for (let c = 0; c < n; c++) {\n const prevSplit = c === 0 ? 0 : breakDist[c - 1]!;\n const split = breakDist[c]!;\n\n // World-space frustum corners of this slice.\n const corners: [number, number, number][] = [];\n for (let k = 0; k < 8; k++) {\n const ndc = FRUSTUM_NDC[k]!;\n corners.push(transformCoord(invViewProj, ndc[0], ndc[1], ndc[2]));\n }\n for (let k = 0; k < 4; k++) {\n const nearC = corners[k]!;\n const farC = corners[k + 4]!;\n const rx = farC[0] - nearC[0];\n const ry = farC[1] - nearC[1];\n const rz = farC[2] - nearC[2];\n corners[k + 4] = [nearC[0] + rx * split, nearC[1] + ry * split, nearC[2] + rz * split];\n corners[k] = [nearC[0] + rx * prevSplit, nearC[1] + ry * prevSplit, nearC[2] + rz * prevSplit];\n }\n\n // Centroid.\n let cx = 0,\n cy = 0,\n cz = 0;\n for (const p of corners) {\n cx += p[0];\n cy += p[1];\n cz += p[2];\n }\n cx /= 8;\n cy /= 8;\n cz /= 8;\n\n let minX: number, maxX: number, minY: number, maxY: number, minEz: number, maxEz: number;\n let stableRadius = 0;\n if (cfg._stabilizeCascades) {\n let radius = 0;\n for (const p of corners) {\n radius = Math.max(radius, Math.hypot(p[0] - cx, p[1] - cy, p[2] - cz));\n }\n radius = Math.ceil(radius * 16) / 16;\n stableRadius = radius;\n minX = minY = minEz = -radius;\n maxX = maxY = maxEz = radius;\n } else {\n // Temp light view centred on the centroid to fit a tight AABB.\n const tmpView = buildLightViewMatrix(dx, dy, dz, cx, cy, cz);\n minX = minY = minEz = Infinity;\n maxX = maxY = maxEz = -Infinity;\n for (const p of corners) {\n const lp = transformCoord(tmpView, p[0], p[1], p[2]);\n minX = Math.min(minX, lp[0]);\n maxX = Math.max(maxX, lp[0]);\n minY = Math.min(minY, lp[1]);\n maxY = Math.max(maxY, lp[1]);\n minEz = Math.min(minEz, lp[2]);\n maxEz = Math.max(maxEz, lp[2]);\n }\n }\n\n // Shadow camera sits behind the slice along the light direction.\n const eyeX = cx + dx * minEz;\n const eyeY = cy + dy * minEz;\n const eyeZ = cz + dz * minEz;\n const view = buildLightViewMatrix(dx, dy, dz, eyeX, eyeY, eyeZ);\n\n let viewMinZ = 0;\n let viewMaxZ = maxEz - minEz;\n\n // Tighten Z to the caster bounding box in cascade view space (depthClamp = false behaviour:\n // keep all casters inside the frustum so no GPU depth-clip feature is required).\n if (aabb) {\n let cMinZ = Infinity;\n let cMaxZ = -Infinity;\n for (let k = 0; k < 8; k++) {\n const wx = k & 1 ? aabb._max[0] : aabb._min[0];\n const wy = k & 2 ? aabb._max[1] : aabb._min[1];\n const wz = k & 4 ? aabb._max[2] : aabb._min[2];\n const lz = view[2]! * wx + view[6]! * wy + view[10]! * wz + view[14]!;\n cMinZ = Math.min(cMinZ, lz);\n cMaxZ = Math.max(cMaxZ, lz);\n }\n if (cMinZ <= viewMaxZ) {\n viewMinZ = Math.min(viewMinZ, cMinZ);\n viewMaxZ = Math.min(viewMaxZ, cMaxZ);\n }\n\n // Z is intentionally NOT quantized here. The caster-AABB fit (cMinZ/cMaxZ) is C0-continuous in the\n // light direction — each is a min/max of linear functions of the light vector, so it has kinks but no\n // jumps — meaning the near/far drift SMOOTHLY as the light rotates. A constant NDC depth bias maps to a\n // WORLD bias of bias·(far−near), and the stored depths are likewise normalised by (far−near); the old\n // `zq = max(0.5, radius/128)` floor/ceil snapped that range to a grid, so both the effective bias AND\n // the stored depth STEPPED at each quantum boundary as the light direction changed — appearing as\n // self-shadow acne that VIBRATES. Removing the quantize makes those steps a sub-millimetre, imperceptible\n // drift, and still covers the moving-caster case it was added for (the range drifts, it never pops).\n }\n\n // The caster matrix adds the world-space bias toward clip Z=1. Reserve the same distance at the far plane\n // so geometry on the tightly fitted caster bound remains inside the clip volume after that offset.\n if (cfg._worldSpaceBias) {\n viewMaxZ += cfg._worldSpaceBias;\n }\n\n const proj0 = orthoOffCenterLH(minX, maxX, minY, maxY, viewMinZ, viewMaxZ);\n let transform = multiply4x4(proj0, view);\n\n // Texel-snap: lock the shadow grid to world space so it does not crawl as the camera moves, by rounding a\n // fixed WORLD anchor onto the shadow-map texel grid. BJS anchors the WORLD ORIGIN. With a STILL camera and\n // a slowly ROTATING light that is the cause of the visible \"vibration\": the eye is recentred on the cascade\n // centre every frame, so the snap residual is the anchor's offset from the centre measured along the light\n // axes — and the world origin's offset from the centre is large (≈ the cascade's distance from origin), so\n // its projection sweeps many texels per degree of light rotation and Math.round trips a full-texel correction\n // again and again → the whole map pops/boils. We instead anchor the world-grid point NEAREST the cascade\n // centre (cell = one texel in world units): it is still a fixed world point (a translating camera only ever\n // sees whole-cell anchor switches, ≤ a sub-texel grid wiggle that PCF hides), but its offset from the centre\n // is < 1 texel, so a full light rotation sweeps it < 1 texel → effectively no rotation pop. Non-stabilized\n // path keeps the origin anchor (no stableRadius → no texel-world size to build the world grid from).\n let aClipX = transform[12]!;\n let aClipY = transform[13]!;\n if (cfg._stabilizeCascades && stableRadius > 0) {\n const texelWorld = (2 * stableRadius) / cfg._mapSize;\n // Align the world anchor grid to the LIGHT's right/up axes (R,U), not world x/y/z. A translating camera then\n // switches cells by exactly ONE texel along R/U -> an integer texel shift in clip space (no crawl). The old\n // world-axis grid jumped texelWorld along a world axis, which projects to a NON-integer texel count (R,U are\n // not the world axes) -> the sub-texel wiggle that crawled during translation. R,U = view rows 0,1.\n const rX = view[0]!,\n rY = view[4]!,\n rZ = view[8]!;\n const uX = view[1]!,\n uY = view[5]!,\n uZ = view[9]!;\n // Project the centre onto R,U, round to the texel grid, rebuild the world anchor in the R-U plane (the\n // light-dir component only affects clip Z, so dropping it leaves clip X/Y, which depend on R,U, exact).\n const sr = Math.round((rX * cx + rY * cy + rZ * cz) / texelWorld) * texelWorld;\n const tr = Math.round((uX * cx + uY * cy + uZ * cz) / texelWorld) * texelWorld;\n const ax = sr * rX + tr * uX;\n const ay = sr * rY + tr * uY;\n const az = sr * rZ + tr * uZ;\n aClipX = transform[0]! * ax + transform[4]! * ay + transform[8]! * az + transform[12]!;\n aClipY = transform[1]! * ax + transform[5]! * ay + transform[9]! * az + transform[13]!;\n }\n const ox = aClipX * (cfg._mapSize / 2);\n const oy = aClipY * (cfg._mapSize / 2);\n const offX = (Math.round(ox) - ox) * (2 / cfg._mapSize);\n const offY = (Math.round(oy) - oy) * (2 / cfg._mapSize);\n const snap = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, offX, offY, 0, 1]);\n const proj = multiply4x4(snap, proj0);\n transform = multiply4x4(proj, view);\n\n transforms.push(transform);\n views.push(view);\n nearOut.push(viewMinZ);\n farOut.push(viewMaxZ);\n }\n\n return {\n _transforms: transforms,\n _biased: transforms.map((t) => new Float32Array(t)),\n _views: views,\n _near: nearOut,\n _far: farOut,\n _viewFrustumZ: viewFrustumZ,\n _frustumLengths: frustumLengths,\n };\n}\n\nfunction _castersWorldAabb(casterMeshes: readonly Mesh[]): { _min: [number, number, number]; _max: [number, number, number] } | null {\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity,\n maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (const mesh of casterMeshes) {\n // Thin-instanced casters are drawn at `finalWorld = mesh.world * instanceMatrix` (see\n // thin-instance-fragment.ts), so a single `mesh.worldMatrix × boundMin/Max` box ignores the per-instance\n // spread entirely — one prototype-sized box wrecks the cascade Z-fit (an off-world herd collapsed every\n // shadow). Bound the caster by the union of every drawn instance instead, using the SAME composition the\n // shader uses.\n const ti = mesh.thinInstances;\n if (ti && ti.count > 0 && ti.matrices) {\n const a = _thinInstanceWorldAabb(mesh, ti);\n if (a) {\n minX = Math.min(minX, a._min[0]);\n maxX = Math.max(maxX, a._max[0]);\n minY = Math.min(minY, a._min[1]);\n maxY = Math.max(maxY, a._max[1]);\n minZ = Math.min(minZ, a._min[2]);\n maxZ = Math.max(maxZ, a._max[2]);\n }\n continue;\n }\n const world = mesh.worldMatrix;\n const bmin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const bmax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n for (let k = 0; k < 8; k++) {\n const lx = k & 1 ? bmax[0]! : bmin[0]!;\n const ly = k & 2 ? bmax[1]! : bmin[1]!;\n const lz = k & 4 ? bmax[2]! : bmin[2]!;\n const wx = world[0]! * lx + world[4]! * ly + world[8]! * lz + world[12]!;\n const wy = world[1]! * lx + world[5]! * ly + world[9]! * lz + world[13]!;\n const wz = world[2]! * lx + world[6]! * ly + world[10]! * lz + world[14]!;\n minX = Math.min(minX, wx);\n maxX = Math.max(maxX, wx);\n minY = Math.min(minY, wy);\n maxY = Math.max(maxY, wy);\n minZ = Math.min(minZ, wz);\n maxZ = Math.max(maxZ, wz);\n }\n }\n if (!Number.isFinite(minX)) {\n return null;\n }\n return { _min: [minX, minY, minZ], _max: [maxX, maxY, maxZ] };\n}\n\ninterface ThinCasterAabb {\n _min: [number, number, number];\n _max: [number, number, number];\n}\n\n/** Per-mesh cache of a thin-instanced caster's world AABB. It keys on instance data, prototype\n * transform, and the shared non-transform caster epoch.\n * Lazily allocated so this module keeps zero import-time side effects and stays tree-shakable. */\nlet _thinCasterAabbCache: WeakMap<Mesh, { _version: number; _worldVersion: number; _aabb: ThinCasterAabb | null }> | null = null;\nfunction _getThinCasterAabbCache(): WeakMap<Mesh, { _version: number; _worldVersion: number; _aabb: ThinCasterAabb | null }> {\n if (!_thinCasterAabbCache) {\n _thinCasterAabbCache = new WeakMap();\n }\n return _thinCasterAabbCache;\n}\n\n/** World AABB of a thin-instanced caster. Matches the shader's `finalWorld = mesh.world * instanceMatrix`\n * exactly: each local bound corner is transformed by the per-instance matrix, then by the prototype mesh\n * world matrix. Parked/degenerate instances (zero linear part — drawn as zero-area, used to hide an unused\n * tail) are skipped so a tail parked far off-world can't balloon the box. */\nfunction _thinInstanceWorldAabb(mesh: Mesh, ti: NonNullable<Mesh[\"thinInstances\"]>): ThinCasterAabb | null {\n const cache = _getThinCasterAabbCache();\n const worldVersion = mesh.worldMatrixVersion;\n const cached = cache.get(mesh);\n if (cached && cached._version === ti._version && cached._worldVersion === worldVersion) {\n return cached._aabb;\n }\n // Hoist the prototype world matrix once (worldMatrix is a getter) — it is constant across all instances.\n const world = mesh.worldMatrix;\n const bmin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const bmax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n const mats = ti.matrices;\n const count = Math.min(ti.count, (mats.length / 16) | 0);\n let minX = Infinity,\n minY = Infinity,\n minZ = Infinity,\n maxX = -Infinity,\n maxY = -Infinity,\n maxZ = -Infinity;\n for (let i = 0; i < count; i++) {\n const o = i * 16;\n // Skip parked instances (zero 3×3 linear part → zero-area triangles that rasterize to nothing).\n const lin =\n Math.abs(mats[o]!) +\n Math.abs(mats[o + 1]!) +\n Math.abs(mats[o + 2]!) +\n Math.abs(mats[o + 4]!) +\n Math.abs(mats[o + 5]!) +\n Math.abs(mats[o + 6]!) +\n Math.abs(mats[o + 8]!) +\n Math.abs(mats[o + 9]!) +\n Math.abs(mats[o + 10]!);\n if (lin < 1e-9) {\n continue;\n }\n for (let k = 0; k < 8; k++) {\n const lx = k & 1 ? bmax[0]! : bmin[0]!;\n const ly = k & 2 ? bmax[1]! : bmin[1]!;\n const lz = k & 4 ? bmax[2]! : bmin[2]!;\n // 1) instance-local: ip = instanceMatrix * localCorner\n const ix = mats[o]! * lx + mats[o + 4]! * ly + mats[o + 8]! * lz + mats[o + 12]!;\n const iy = mats[o + 1]! * lx + mats[o + 5]! * ly + mats[o + 9]! * lz + mats[o + 13]!;\n const iz = mats[o + 2]! * lx + mats[o + 6]! * ly + mats[o + 10]! * lz + mats[o + 14]!;\n // 2) world: wp = mesh.world * ip (matches finalWorld = mesh.world * instanceMatrix)\n const wx = world[0]! * ix + world[4]! * iy + world[8]! * iz + world[12]!;\n const wy = world[1]! * ix + world[5]! * iy + world[9]! * iz + world[13]!;\n const wz = world[2]! * ix + world[6]! * iy + world[10]! * iz + world[14]!;\n if (wx < minX) {\n minX = wx;\n }\n if (wx > maxX) {\n maxX = wx;\n }\n if (wy < minY) {\n minY = wy;\n }\n if (wy > maxY) {\n maxY = wy;\n }\n if (wz < minZ) {\n minZ = wz;\n }\n if (wz > maxZ) {\n maxZ = wz;\n }\n }\n }\n const aabb: ThinCasterAabb | null = Number.isFinite(minX) ? { _min: [minX, minY, minZ], _max: [maxX, maxY, maxZ] } : null;\n cache.set(mesh, { _version: ti._version, _worldVersion: worldVersion, _aabb: aabb });\n return aabb;\n}\n\nfunction _writeCsmUbo(out: Float32Array, cascades: CsmCascades, cfg: CsmConfig): void {\n out.fill(0);\n const n = cascades._transforms.length;\n for (let i = 0; i < n; i++) {\n out.set(cascades._transforms[i]!, i * 16);\n }\n for (let i = 0; i < n; i++) {\n out[64 + i] = cascades._viewFrustumZ[i]!;\n out[68 + i] = cascades._frustumLengths[i]!;\n }\n out[72] = cfg._darkness;\n out[73] = cfg._mapSize;\n out[74] = 1 / cfg._mapSize;\n out[75] = cfg._frustumEdgeFalloff;\n out[76] = n;\n out[77] = cfg._cascadeBlendPercentage === 0 ? 10000 : 1 / cfg._cascadeBlendPercentage;\n}\n\n/** @internal Convert a physical caster offset to the clip-space Z offset for one orthographic cascade. */\nexport function csmWorldBiasClipOffset(worldSpaceBias: number, near: number, far: number): number {\n const range = far - near;\n if (!Number.isFinite(worldSpaceBias) || worldSpaceBias <= 0 || !Number.isFinite(range) || range <= 0) {\n return 0;\n }\n return worldSpaceBias / range;\n}\n\nfunction _biasViewProjection(viewProj: Float32Array, clipOffset: number): Float32Array {\n const biased = new Float32Array(viewProj);\n for (let col = 0; col < 4; col++) {\n const z = 2 + col * 4;\n const w = 3 + col * 4;\n biased[z] = biased[z]! + clipOffset * biased[w]!;\n }\n return biased;\n}\n"],"names":["tasks"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { F32 } from '../engine/typed-arrays.js';
2
+ import { _cameraChangeKey } from '../camera/camera.js';
2
3
  import { createUniformBuffer } from '../resource/gpu-buffers.js';
3
4
  import { packMat4IntoF32 } from '../math/pack-mat4-into-f32.js';
4
5
  import { allocateMat4 } from '../math/_matrix-allocator.js';
@@ -162,12 +163,12 @@ function createShadowCamera(sg) {
162
163
  function updateShadowCameraBase(camera, cameraVersion, near, far, view, viewProj) {
163
164
  camera.nearPlane = near;
164
165
  camera.farPlane = far;
166
+ camera._shadowCameraVersion = cameraVersion;
165
167
  camera._viewCache = view;
166
168
  camera._viewVer = cameraVersion;
167
169
  camera._vpCache = viewProj;
168
- camera._vpVer = cameraVersion;
170
+ camera._vpVer = _cameraChangeKey(camera);
169
171
  camera._vpAspect = 1;
170
- camera._shadowCameraVersion = cameraVersion;
171
172
  }
172
173
 
173
174
  export { buildLightViewMatrix, casterVersionSum, computeDirectionalLightMatrix, createShadowCamera, createShadowParamsUBO, createShadowRenderTarget, createSharedShadowUBO, multiply4x4, updateShadowCameraBase, writeShadowUboFields };
@@ -1 +1 @@
1
- {"version":3,"file":"shadow-base.js","sources":["../../../src/shadow/shadow-base.ts"],"sourcesContent":["/**\n * Shared shadow helpers used by ESM and PCF shadow generators/tasks.\n */\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport type { DirectionalLight } from \"../light/directional-light.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport { createUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport type { ShadowGenerator } from \"./shadow-generator.js\";\nimport { packMat4IntoF32 } from \"../math/pack-mat4-into-f32.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** Write shadow generator state into a Float32Array(24) for UBO upload.\n * Layout: [lightMatrix(16), depthValues.x, depthValues.y, 0, 0, shadowsInfo(4)] */\nexport function writeShadowUboFields(out: Float32Array, sg: { _lightMatrix: Float32Array; _depthValues: Float32Array; _shadowsInfo: Float32Array }): void {\n packMat4IntoF32(out, sg._lightMatrix, 0);\n out[16] = sg._depthValues[0]!;\n out[17] = sg._depthValues[1]!;\n out[18] = 0;\n out[19] = 0;\n out[20] = sg._shadowsInfo[0]!;\n out[21] = sg._shadowsInfo[1]!;\n out[22] = sg._shadowsInfo[2]!;\n out[23] = sg._shadowsInfo[3]!;\n}\n\n/** Build a light-space view matrix (column-major 4x4) from direction + position.\n * Shared between directional and spot shadow generators. */\nexport function buildLightViewMatrix(dirX: number, dirY: number, dirZ: number, px: number, py: number, pz: number): Float32Array {\n const len = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ) || 1;\n const fx = dirX / len;\n const fy = dirY / len;\n const fz = dirZ / len;\n\n let upX = 0,\n upY = 1,\n upZ = 0;\n if (Math.abs(fy) > 0.99) {\n upX = 0;\n upY = 0;\n upZ = 1;\n }\n // right = cross(up, forward)\n let rx = upY * fz - upZ * fy;\n let ry = upZ * fx - upX * fz;\n let rz = upX * fy - upY * fx;\n const rLen = Math.sqrt(rx * rx + ry * ry + rz * rz) || 1;\n rx /= rLen;\n ry /= rLen;\n rz /= rLen;\n\n // up = cross(forward, right)\n const ux = fy * rz - fz * ry;\n const uy = fz * rx - fx * rz;\n const uz = fx * ry - fy * rx;\n\n // Column-major view matrix (stores basis as rows of rotation, plus translation column)\n return new F32([rx, ux, fx, 0, ry, uy, fy, 0, rz, uz, fz, 0, -(rx * px + ry * py + rz * pz), -(ux * px + uy * py + uz * pz), -(fx * px + fy * py + fz * pz), 1]);\n}\n\n/** Multiply two column-major 4x4 matrices: out = a * b. */\nexport function multiply4x4(a: Float32Array, b: Float32Array): Float32Array {\n const out = new F32(16);\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n let sum = 0;\n for (let k = 0; k < 4; k++) {\n sum += a[row + k * 4]! * b[k + col * 4]!;\n }\n out[row + col * 4] = sum;\n }\n }\n return out;\n}\n\n/** Fit an orthographic directional-light projection to caster world-space bounds. */\nexport function computeDirectionalLightMatrix(\n light: DirectionalLight,\n casterMeshes: readonly Mesh[],\n orthoMinZ: number,\n orthoMaxZ: number,\n offX = 0,\n offY = 0,\n offZ = 0\n): { _view: Float32Array; _viewProj: Float32Array; _near: number; _far: number } {\n const view = buildLightViewMatrix(light.direction.x, light.direction.y, light.direction.z, light.position.x - offX, light.position.y - offY, light.position.z - offZ);\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const mesh of casterMeshes) {\n const world = mesh.worldMatrix;\n const boundMin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const boundMax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n for (let corner = 0; corner < 8; corner++) {\n const localX = corner & 1 ? boundMax[0] : boundMin[0];\n const localY = corner & 2 ? boundMax[1] : boundMin[1];\n const localZ = corner & 4 ? boundMax[2] : boundMin[2];\n const worldX = world[0]! * localX + world[4]! * localY + world[8]! * localZ + world[12]! - offX;\n const worldY = world[1]! * localX + world[5]! * localY + world[9]! * localZ + world[13]! - offY;\n const worldZ = world[2]! * localX + world[6]! * localY + world[10]! * localZ + world[14]! - offZ;\n const viewX = view[0]! * worldX + view[4]! * worldY + view[8]! * worldZ + view[12]!;\n const viewY = view[1]! * worldX + view[5]! * worldY + view[9]! * worldZ + view[13]!;\n minX = Math.min(minX, viewX);\n maxX = Math.max(maxX, viewX);\n minY = Math.min(minY, viewY);\n maxY = Math.max(maxY, viewY);\n }\n }\n if (!Number.isFinite(minX)) {\n minX = -1;\n maxX = 1;\n minY = -1;\n maxY = 1;\n }\n const padX = (maxX - minX) * 0.1;\n const padY = (maxY - minY) * 0.1;\n minX -= padX;\n maxX += padX;\n minY -= padY;\n maxY += padY;\n\n const projection = new F32(16);\n projection[0] = 2 / (maxX - minX);\n projection[5] = 2 / (maxY - minY);\n projection[10] = 1 / (orthoMaxZ - orthoMinZ);\n projection[12] = -(maxX + minX) / (maxX - minX);\n projection[13] = -(maxY + minY) / (maxY - minY);\n projection[14] = -orthoMinZ / (orthoMaxZ - orthoMinZ);\n projection[15] = 1;\n return { _view: view, _viewProj: multiply4x4(projection, view), _near: orthoMinZ, _far: orthoMaxZ };\n}\n\n/** Create the shared shadow-params UBO (32 bytes) holding bias/depthScale/depth-range fields. */\nexport function createShadowParamsUBO(engine: EngineContext, bias: number, depthScale: number): GPUBuffer {\n const data = new F32(8);\n data[0] = bias;\n data[2] = depthScale;\n data[4] = 0; // depthMinZ (WebGPU)\n data[5] = 1; // depthMinZ + depthMaxZ\n return createUniformBuffer(engine, data);\n}\n\n/** Create the eager shadow-map render target used by frame-graph shadow tasks. */\nexport function createShadowRenderTarget(sg: ShadowGenerator, colorTexture: GPUTexture | null = null, depthTexture: GPUTexture = sg._depthTexture): RenderTarget {\n const mapSize = sg._config._mapSize;\n return {\n _descriptor: {\n size: { width: mapSize, height: mapSize },\n format: colorTexture ? \"rgba16float\" : undefined,\n dFormat: \"depth32float\",\n _depthClearValue: 1,\n _depthCompare: \"less-equal\",\n samples: 1,\n },\n _colorTexture: colorTexture,\n _colorView: colorTexture?.createView() ?? null,\n _depthTexture: depthTexture,\n _depthView: depthTexture.createView(),\n _width: mapSize,\n _height: mapSize,\n _eager: true,\n // Borrowed: the depth map is the generator's shared shadow map (persists for the generator's\n // lifetime); per-task render-target disposal must NOT destroy it (it's reused after rebuilds).\n _ownsDepthTexture: false,\n };\n}\n\n/** Create the shared receiver-side shadow UBO (96 bytes), initialised from state. */\nexport function createSharedShadowUBO(\n engine: EngineContext,\n _lightMatrix: Float32Array,\n _depthValues: Float32Array,\n _shadowsInfo: Float32Array\n): { ubo: GPUBuffer; data: Float32Array } {\n const data = new F32(24);\n writeShadowUboFields(data, { _lightMatrix, _depthValues, _shadowsInfo });\n const ubo = createUniformBuffer(engine, data);\n return { ubo, data };\n}\n\n/** Sum caster transform versions plus non-transform geometry/count mutations. */\nexport function casterVersionSum(casterMeshes: readonly Mesh[]): number {\n let sum = 0;\n for (const mesh of casterMeshes) {\n // Bitwise coercion maps the absent optional version to zero without another branch.\n sum += mesh.worldMatrixVersion + ~~(mesh.thinInstances?._version as number);\n }\n return sum;\n}\n\n/** Create the light-owned camera facade used by shadow render tasks.\n * Caches are pre-allocated from the process-global allocator. */\nexport function createShadowCamera(sg: Pick<ShadowGenerator, \"_light\">): Camera {\n return {\n fov: 1,\n nearPlane: 1,\n farPlane: 1,\n children: [],\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n get worldMatrix() {\n return sg._light.worldMatrix;\n },\n get worldMatrixVersion() {\n const state = (this as Camera & { _shadowCameraVersion?: number })._shadowCameraVersion;\n return state ?? sg._light.worldMatrixVersion;\n },\n } as Camera;\n}\n\n/** Update the camera facade caches shared by all shadow task variants. */\nexport function updateShadowCameraBase(camera: Camera, cameraVersion: number, near: number, far: number, view: Float32Array, viewProj: Float32Array): void {\n camera.nearPlane = near;\n camera.farPlane = far;\n camera._viewCache = view;\n camera._viewVer = cameraVersion;\n camera._vpCache = viewProj;\n camera._vpVer = cameraVersion;\n camera._vpAspect = 1;\n (camera as Camera & { _shadowCameraVersion?: number })._shadowCameraVersion = cameraVersion;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shadow-base.js","sources":["../../../src/shadow/shadow-base.ts"],"sourcesContent":["/**\n * Shared shadow helpers used by ESM and PCF shadow generators/tasks.\n */\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport { _cameraChangeKey } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport type { DirectionalLight } from \"../light/directional-light.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport { createUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport type { ShadowGenerator } from \"./shadow-generator.js\";\nimport { packMat4IntoF32 } from \"../math/pack-mat4-into-f32.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** Write shadow generator state into a Float32Array(24) for UBO upload.\n * Layout: [lightMatrix(16), depthValues.x, depthValues.y, 0, 0, shadowsInfo(4)] */\nexport function writeShadowUboFields(out: Float32Array, sg: { _lightMatrix: Float32Array; _depthValues: Float32Array; _shadowsInfo: Float32Array }): void {\n packMat4IntoF32(out, sg._lightMatrix, 0);\n out[16] = sg._depthValues[0]!;\n out[17] = sg._depthValues[1]!;\n out[18] = 0;\n out[19] = 0;\n out[20] = sg._shadowsInfo[0]!;\n out[21] = sg._shadowsInfo[1]!;\n out[22] = sg._shadowsInfo[2]!;\n out[23] = sg._shadowsInfo[3]!;\n}\n\n/** Build a light-space view matrix (column-major 4x4) from direction + position.\n * Shared between directional and spot shadow generators. */\nexport function buildLightViewMatrix(dirX: number, dirY: number, dirZ: number, px: number, py: number, pz: number): Float32Array {\n const len = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ) || 1;\n const fx = dirX / len;\n const fy = dirY / len;\n const fz = dirZ / len;\n\n let upX = 0,\n upY = 1,\n upZ = 0;\n if (Math.abs(fy) > 0.99) {\n upX = 0;\n upY = 0;\n upZ = 1;\n }\n // right = cross(up, forward)\n let rx = upY * fz - upZ * fy;\n let ry = upZ * fx - upX * fz;\n let rz = upX * fy - upY * fx;\n const rLen = Math.sqrt(rx * rx + ry * ry + rz * rz) || 1;\n rx /= rLen;\n ry /= rLen;\n rz /= rLen;\n\n // up = cross(forward, right)\n const ux = fy * rz - fz * ry;\n const uy = fz * rx - fx * rz;\n const uz = fx * ry - fy * rx;\n\n // Column-major view matrix (stores basis as rows of rotation, plus translation column)\n return new F32([rx, ux, fx, 0, ry, uy, fy, 0, rz, uz, fz, 0, -(rx * px + ry * py + rz * pz), -(ux * px + uy * py + uz * pz), -(fx * px + fy * py + fz * pz), 1]);\n}\n\n/** Multiply two column-major 4x4 matrices: out = a * b. */\nexport function multiply4x4(a: Float32Array, b: Float32Array): Float32Array {\n const out = new F32(16);\n for (let row = 0; row < 4; row++) {\n for (let col = 0; col < 4; col++) {\n let sum = 0;\n for (let k = 0; k < 4; k++) {\n sum += a[row + k * 4]! * b[k + col * 4]!;\n }\n out[row + col * 4] = sum;\n }\n }\n return out;\n}\n\n/** Fit an orthographic directional-light projection to caster world-space bounds. */\nexport function computeDirectionalLightMatrix(\n light: DirectionalLight,\n casterMeshes: readonly Mesh[],\n orthoMinZ: number,\n orthoMaxZ: number,\n offX = 0,\n offY = 0,\n offZ = 0\n): { _view: Float32Array; _viewProj: Float32Array; _near: number; _far: number } {\n const view = buildLightViewMatrix(light.direction.x, light.direction.y, light.direction.z, light.position.x - offX, light.position.y - offY, light.position.z - offZ);\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const mesh of casterMeshes) {\n const world = mesh.worldMatrix;\n const boundMin = mesh.boundMin ?? [-0.5, -0.5, -0.5];\n const boundMax = mesh.boundMax ?? [0.5, 0.5, 0.5];\n for (let corner = 0; corner < 8; corner++) {\n const localX = corner & 1 ? boundMax[0] : boundMin[0];\n const localY = corner & 2 ? boundMax[1] : boundMin[1];\n const localZ = corner & 4 ? boundMax[2] : boundMin[2];\n const worldX = world[0]! * localX + world[4]! * localY + world[8]! * localZ + world[12]! - offX;\n const worldY = world[1]! * localX + world[5]! * localY + world[9]! * localZ + world[13]! - offY;\n const worldZ = world[2]! * localX + world[6]! * localY + world[10]! * localZ + world[14]! - offZ;\n const viewX = view[0]! * worldX + view[4]! * worldY + view[8]! * worldZ + view[12]!;\n const viewY = view[1]! * worldX + view[5]! * worldY + view[9]! * worldZ + view[13]!;\n minX = Math.min(minX, viewX);\n maxX = Math.max(maxX, viewX);\n minY = Math.min(minY, viewY);\n maxY = Math.max(maxY, viewY);\n }\n }\n if (!Number.isFinite(minX)) {\n minX = -1;\n maxX = 1;\n minY = -1;\n maxY = 1;\n }\n const padX = (maxX - minX) * 0.1;\n const padY = (maxY - minY) * 0.1;\n minX -= padX;\n maxX += padX;\n minY -= padY;\n maxY += padY;\n\n const projection = new F32(16);\n projection[0] = 2 / (maxX - minX);\n projection[5] = 2 / (maxY - minY);\n projection[10] = 1 / (orthoMaxZ - orthoMinZ);\n projection[12] = -(maxX + minX) / (maxX - minX);\n projection[13] = -(maxY + minY) / (maxY - minY);\n projection[14] = -orthoMinZ / (orthoMaxZ - orthoMinZ);\n projection[15] = 1;\n return { _view: view, _viewProj: multiply4x4(projection, view), _near: orthoMinZ, _far: orthoMaxZ };\n}\n\n/** Create the shared shadow-params UBO (32 bytes) holding bias/depthScale/depth-range fields. */\nexport function createShadowParamsUBO(engine: EngineContext, bias: number, depthScale: number): GPUBuffer {\n const data = new F32(8);\n data[0] = bias;\n data[2] = depthScale;\n data[4] = 0; // depthMinZ (WebGPU)\n data[5] = 1; // depthMinZ + depthMaxZ\n return createUniformBuffer(engine, data);\n}\n\n/** Create the eager shadow-map render target used by frame-graph shadow tasks. */\nexport function createShadowRenderTarget(sg: ShadowGenerator, colorTexture: GPUTexture | null = null, depthTexture: GPUTexture = sg._depthTexture): RenderTarget {\n const mapSize = sg._config._mapSize;\n return {\n _descriptor: {\n size: { width: mapSize, height: mapSize },\n format: colorTexture ? \"rgba16float\" : undefined,\n dFormat: \"depth32float\",\n _depthClearValue: 1,\n _depthCompare: \"less-equal\",\n samples: 1,\n },\n _colorTexture: colorTexture,\n _colorView: colorTexture?.createView() ?? null,\n _depthTexture: depthTexture,\n _depthView: depthTexture.createView(),\n _width: mapSize,\n _height: mapSize,\n _eager: true,\n // Borrowed: the depth map is the generator's shared shadow map (persists for the generator's\n // lifetime); per-task render-target disposal must NOT destroy it (it's reused after rebuilds).\n _ownsDepthTexture: false,\n };\n}\n\n/** Create the shared receiver-side shadow UBO (96 bytes), initialised from state. */\nexport function createSharedShadowUBO(\n engine: EngineContext,\n _lightMatrix: Float32Array,\n _depthValues: Float32Array,\n _shadowsInfo: Float32Array\n): { ubo: GPUBuffer; data: Float32Array } {\n const data = new F32(24);\n writeShadowUboFields(data, { _lightMatrix, _depthValues, _shadowsInfo });\n const ubo = createUniformBuffer(engine, data);\n return { ubo, data };\n}\n\n/** Sum caster transform versions plus non-transform geometry/count mutations. */\nexport function casterVersionSum(casterMeshes: readonly Mesh[]): number {\n let sum = 0;\n for (const mesh of casterMeshes) {\n // Bitwise coercion maps the absent optional version to zero without another branch.\n sum += mesh.worldMatrixVersion + ~~(mesh.thinInstances?._version as number);\n }\n return sum;\n}\n\n/** Create the light-owned camera facade used by shadow render tasks.\n * Caches are pre-allocated from the process-global allocator. */\nexport function createShadowCamera(sg: Pick<ShadowGenerator, \"_light\">): Camera {\n return {\n fov: 1,\n nearPlane: 1,\n farPlane: 1,\n children: [],\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n get worldMatrix() {\n return sg._light.worldMatrix;\n },\n get worldMatrixVersion() {\n const state = (this as Camera & { _shadowCameraVersion?: number })._shadowCameraVersion;\n return state ?? sg._light.worldMatrixVersion;\n },\n } as Camera;\n}\n\n/** Update the camera facade caches shared by all shadow task variants.\n *\n * This facade does not *compute* its matrices through `camera.ts` — the shadow task already\n * built the light's view / view-projection (an orthographic or spot volume that\n * `getProjectionMatrix` knows nothing about) and installs them here, pinning the cache\n * versions so `getViewMatrix` / `getViewProjectionMatrix` hand them straight back.\n *\n * The pin must therefore use the *same* key each getter compares against, or the getter\n * misses and silently rebuilds a perspective projection over the light's volume. The view\n * matrix keys on `worldMatrixVersion` (which the facade reports as `cameraVersion`); the\n * view-projection keys on `_cameraChangeKey`, which additionally folds in the projection\n * revision — and writing `nearPlane` / `farPlane` above moves that revision, so the key is\n * read *after* those writes and after `_shadowCameraVersion` is set. */\nexport function updateShadowCameraBase(camera: Camera, cameraVersion: number, near: number, far: number, view: Float32Array, viewProj: Float32Array): void {\n camera.nearPlane = near;\n camera.farPlane = far;\n (camera as Camera & { _shadowCameraVersion?: number })._shadowCameraVersion = cameraVersion;\n camera._viewCache = view;\n camera._viewVer = cameraVersion;\n camera._vpCache = viewProj;\n camera._vpVer = _cameraChangeKey(camera);\n camera._vpAspect = 1;\n}\n"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import { createEulerProxy } from '../scene/scene-node.js';
5
5
  import { createEmptyUniformBuffer } from '../resource/gpu-buffers.js';
6
6
  import { addDeferredSceneRenderables } from '../scene/scene-core.js';
7
7
  import { mat4MultiplyInto } from '../math/mat4-multiply-into.js';
8
- import { getEffectiveAspectRatio, getViewProjectionMatrix } from '../camera/camera.js';
8
+ import { getEffectiveAspectRatio, _cameraChangeKey, getViewProjectionMatrix } from '../camera/camera.js';
9
9
  import { TEXT_INSTANCE_BYTES } from './text-data.js';
10
10
  import { ensureSharedAtlasGpu } from './_gpu/text-textures.js';
11
11
  import { getOrCreateTextPipeline } from './_gpu/text-pipeline.js';
@@ -169,7 +169,7 @@ function updateTextRenderable(r, engine, gpu, bindGroupLayout, context) {
169
169
  const camera = context._camera ?? null;
170
170
  if (camera) {
171
171
  const aspect = getEffectiveAspectRatio(camera, context.targetWidth, context.targetHeight);
172
- const camVer = camera.worldMatrixVersion;
172
+ const camVer = _cameraChangeKey(camera);
173
173
  if (r._wmDirty || gpu.uploadedCameraVersion !== camVer || gpu.uploadedAspect !== aspect) {
174
174
  const vp = getViewProjectionMatrix(camera, aspect);
175
175
  const wm = r._worldMatrix();
@@ -1 +1 @@
1
- {"version":3,"file":"text-renderable.js","sources":["../../../src/text/text-renderable.ts"],"sourcesContent":["/** TextRenderable — a scene-attachable text entity backed by a TextData.\n * Mirrors Mesh's TRS surface (position/rotation/rotationQuaternion/scaling). */\n\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawBinding, DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport { ObservableQuat } from \"../math/observable-quat.js\";\nimport { composeTrsLocalMatrix, createWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { createEulerProxy } from \"../scene/scene-node.js\";\nimport type { EulerProxy } from \"../scene/scene-node.js\";\nimport { createEmptyUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport { addDeferredSceneRenderables } from \"../scene/scene-core.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Mat4, Mat4Storage, Vec3 } from \"../math/types.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport { getViewProjectionMatrix, getEffectiveAspectRatio } from \"../camera/camera.js\";\nimport type { TextData } from \"./text-data.js\";\nimport { TEXT_INSTANCE_BYTES } from \"./text-data.js\";\nimport { ensureSharedAtlasGpu } from \"./_gpu/text-textures.js\";\nimport { getOrCreateTextPipeline } from \"./_gpu/text-pipeline.js\";\n\n/** Initial transform and draw options for a scene-attached text renderable. */\nexport interface TextRenderableOptions {\n readonly position?: Readonly<Vec3>;\n readonly rotationQuaternion?: { readonly x: number; readonly y: number; readonly z: number; readonly w: number };\n readonly scaling?: Readonly<Vec3>;\n /** Whole-block opacity in [0,1]. Default 1. Per-glyph/per-run color comes from the `TextData`\n * descriptor (`PlacedGlyph.color` / `GlyphRun.defaultColor`), not from the renderable. */\n readonly opacity?: number;\n readonly ignoreDepth?: boolean;\n readonly order?: number;\n}\n\n/** Scene renderable that draws a `TextData` block with mesh-like transform controls. */\nexport interface TextRenderable extends Renderable {\n /** @internal */\n readonly _entityType: \"text\";\n readonly position: ObservableVec3;\n readonly rotation: EulerProxy;\n readonly rotationQuaternion: ObservableQuat;\n readonly scaling: ObservableVec3;\n /** Whole-block opacity in [0,1]. Color is supplied per-glyph by the `TextData` descriptor. */\n opacity: number;\n ignoreDepth: boolean;\n order: number;\n /** @internal */ readonly _data: TextData;\n /** @internal */ readonly _worldMatrix: () => Mat4;\n /** @internal */ _wmDirty: boolean;\n /** @internal */ _gpu: TextRenderableGpu | null;\n /** @internal */ _version: number;\n}\n\ninterface TextRenderableGpu {\n device: GPUDevice;\n textU: GPUBuffer;\n instanceBuf: GPUBuffer;\n instanceCap: number;\n pipeline: GPURenderPipeline;\n uploadedDataVersion: number;\n uploadedCameraVersion: number;\n uploadedAspect: number;\n uploadedViewportW: number;\n uploadedViewportH: number;\n uploadedOpacity: number;\n targetKey: string;\n}\n\nconst TEXT_UBO_BYTES = 64 /* mvp */ + 16 /* viewport */ + 16; /* color */\nconst _mvpScratch = new Float32Array(16);\n\nfunction targetSig(target: RenderTargetSignature): string {\n return (target._colorFormat ?? \"-\") + \":\" + (target._sampleCount ?? 1) + \":\" + (target._depthStencilFormat ?? \"-\");\n}\n\n/** Create a scene renderable that draws the supplied `TextData` through the normal renderable pipeline.\n *\n * @param data - Text data block to render.\n * @param options - Optional transform, opacity, depth, and ordering settings.\n * @returns A transparent renderable suitable for adding to a scene. */\nexport function createTextRenderable(data: TextData, options?: TextRenderableOptions): TextRenderable {\n const pos = options?.position;\n const rq = options?.rotationQuaternion;\n const sc = options?.scaling;\n const initRq = rq ?? { x: 0, y: 0, z: 0, w: 1 };\n\n const wm = createWorldMatrixState(() => composeTrsLocalMatrix(r.position, r.rotationQuaternion, r.scaling));\n const markDirty = (): void => {\n r._wmDirty = true;\n wm.markLocalDirty();\n };\n const quat = new ObservableQuat(initRq.x, initRq.y, initRq.z, initRq.w, markDirty);\n\n const r: TextRenderable = {\n _entityType: \"text\",\n order: options?.order ?? 200,\n isTransparent: true,\n position: new ObservableVec3(pos?.x ?? 0, pos?.y ?? 0, pos?.z ?? 0, markDirty),\n rotationQuaternion: quat,\n rotation: createEulerProxy(quat),\n scaling: new ObservableVec3(sc?.x ?? 1, sc?.y ?? 1, sc?.z ?? 1, markDirty),\n opacity: options?.opacity ?? 1,\n ignoreDepth: options?.ignoreDepth ?? false,\n _data: data,\n _wmDirty: true,\n _gpu: null,\n _version: 0,\n _worldMatrix: () => wm.getWorldMatrix(),\n bind(engine, target): DrawBinding {\n return bindTextRenderable(r, engine, target);\n },\n };\n return r;\n}\n\nfunction ensureGpu(r: TextRenderable, engine: EngineContext, target: RenderTargetSignature): TextRenderableGpu {\n const device = engine._device;\n const sampleCount = target._sampleCount === 1 ? 1 : 4;\n const colorFormat = target._colorFormat;\n if (!colorFormat) {\n throw new Error(\"TextRenderable: render target has no color format.\");\n }\n const depthFormat = target._depthStencilFormat ?? null;\n const depthWrite = !r.ignoreDepth;\n const { pipeline } = getOrCreateTextPipeline(engine, colorFormat, sampleCount, depthFormat, depthWrite);\n const key = targetSig(target);\n let gpu = r._gpu;\n if (gpu && gpu.device !== device) {\n gpu.textU.destroy();\n gpu.instanceBuf.destroy();\n gpu = null;\n }\n if (!gpu || gpu.targetKey !== key || gpu.pipeline !== pipeline) {\n if (!gpu) {\n const cap = Math.max(r._data._instanceCount, 8);\n gpu = {\n device,\n textU: createEmptyUniformBuffer(engine, TEXT_UBO_BYTES, \"text-renderable-ubo\"),\n instanceBuf: device.createBuffer({\n label: \"text-instance\",\n size: cap * TEXT_INSTANCE_BYTES,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n }),\n instanceCap: cap,\n pipeline,\n uploadedDataVersion: -1,\n uploadedCameraVersion: -1,\n uploadedAspect: -1,\n uploadedViewportW: 0,\n uploadedViewportH: 0,\n uploadedOpacity: NaN,\n targetKey: key,\n };\n r._gpu = gpu;\n } else {\n gpu.pipeline = pipeline;\n gpu.targetKey = key;\n // Pipeline change — per-group bind groups must be rebuilt against the new bindGroupLayout.\n for (const g of r._data._groups) {\n g.bindGroup = null;\n g.bindGroupVersion = -1;\n }\n }\n }\n return gpu;\n}\n\nfunction ensureInstanceCapacity(device: GPUDevice, gpu: TextRenderableGpu, needed: number): void {\n if (needed <= gpu.instanceCap) {\n return;\n }\n let cap = gpu.instanceCap;\n while (cap < needed) {\n cap *= 2;\n }\n gpu.instanceBuf.destroy();\n gpu.instanceBuf = device.createBuffer({\n label: \"text-instance\",\n size: cap * TEXT_INSTANCE_BYTES,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n gpu.instanceCap = cap;\n gpu.uploadedDataVersion = -1;\n}\n\nfunction bindTextRenderable(r: TextRenderable, engine: EngineContext, target: RenderTargetSignature): DrawBinding {\n const gpu = ensureGpu(r, engine, target);\n const { cache } = getOrCreateTextPipeline(engine, target._colorFormat!, target._sampleCount === 1 ? 1 : 4, target._depthStencilFormat ?? null, !r.ignoreDepth);\n const quadVertex = cache.quadVertexBuffer;\n const bindGroupLayout = cache.bindGroupLayout;\n\n return {\n renderable: r,\n pipeline: gpu.pipeline,\n update(context: DrawUpdateContext): void {\n updateTextRenderable(r, engine, gpu, bindGroupLayout, context);\n },\n draw(pass): number {\n return drawTextRenderable(gpu, r._data, quadVertex, pass);\n },\n };\n}\n\nfunction updateTextRenderable(r: TextRenderable, engine: EngineContext, gpu: TextRenderableGpu, bindGroupLayout: GPUBindGroupLayout, context: DrawUpdateContext): void {\n const device = engine._device;\n const data = r._data;\n\n // Sync every group's atlas to the GPU; track which need bind-group rebuild.\n for (const g of data._groups) {\n const { rebuilt, gpu: atlasGpu } = ensureSharedAtlasGpu(device, g.curveSet.atlas);\n if (rebuilt || !g.bindGroup || g.bindGroupVersion !== atlasGpu.uploadedVersion) {\n g.bindGroup = device.createBindGroup({\n label: \"text-bg0-\" + g.curveSetId,\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: gpu.textU } },\n { binding: 1, resource: atlasGpu.curveTex.createView() },\n { binding: 2, resource: atlasGpu.bandTex.createView() },\n ],\n });\n g.bindGroupVersion = atlasGpu.uploadedVersion;\n }\n }\n\n // Sync instance buffer if data changed.\n ensureInstanceCapacity(device, gpu, data._instanceCount);\n if (gpu.uploadedDataVersion !== data._version) {\n if (data._instanceCount > 0) {\n // Partial upload when only a sub-range is dirty; full upload after grow/reset (when\n // uploadedDataVersion is -1 we don't trust the dirty range).\n const dirtyValid = gpu.uploadedDataVersion !== -1 && data._dirtyEnd > data._dirtyStart;\n if (dirtyValid) {\n const startFloats = data._dirtyStart * (TEXT_INSTANCE_BYTES / 4);\n const endFloats = data._dirtyEnd * (TEXT_INSTANCE_BYTES / 4);\n const view = data._instances.subarray(startFloats, endFloats);\n device.queue.writeBuffer(gpu.instanceBuf, data._dirtyStart * TEXT_INSTANCE_BYTES, view.buffer as ArrayBuffer, view.byteOffset, view.byteLength);\n } else {\n const view = data._instances.subarray(0, data._instanceCount * (TEXT_INSTANCE_BYTES / 4));\n device.queue.writeBuffer(gpu.instanceBuf, 0, view.buffer as ArrayBuffer, view.byteOffset, view.byteLength);\n }\n }\n gpu.uploadedDataVersion = data._version;\n data._dirtyStart = 0;\n data._dirtyEnd = 0;\n }\n\n // Sync text UBO: mvp (vp * world) + viewport + color. The scene UBO is no longer\n // consumed by the text pipeline, so we compose the mvp here from the active camera.\n // Skip the recompute + upload when the world matrix, camera, and aspect are all unchanged.\n const camera = context._camera ?? null;\n if (camera) {\n const aspect = getEffectiveAspectRatio(camera, context.targetWidth, context.targetHeight);\n const camVer = camera.worldMatrixVersion;\n if (r._wmDirty || gpu.uploadedCameraVersion !== camVer || gpu.uploadedAspect !== aspect) {\n const vp = getViewProjectionMatrix(camera, aspect) as unknown as Float32Array;\n const wm = r._worldMatrix();\n mat4MultiplyInto(_mvpScratch, 0, vp, 0, wm as unknown as Mat4Storage, 0);\n device.queue.writeBuffer(gpu.textU, 0, _mvpScratch.buffer as ArrayBuffer, _mvpScratch.byteOffset, 64);\n r._wmDirty = false;\n gpu.uploadedCameraVersion = camVer;\n gpu.uploadedAspect = aspect;\n }\n }\n if (gpu.uploadedViewportW !== context.targetWidth || gpu.uploadedViewportH !== context.targetHeight) {\n const vp = new Float32Array([context.targetWidth, context.targetHeight, 0, 0]);\n device.queue.writeBuffer(gpu.textU, 64, vp.buffer as ArrayBuffer, vp.byteOffset, 16);\n gpu.uploadedViewportW = context.targetWidth;\n gpu.uploadedViewportH = context.targetHeight;\n }\n // Color uniform carries whole-block opacity as alpha (rgb fixed to white). Per-glyph color\n // comes from the instance `slugColor` attribute.\n if (gpu.uploadedOpacity !== r.opacity) {\n const col = new Float32Array([1, 1, 1, r.opacity]);\n device.queue.writeBuffer(gpu.textU, 80, col.buffer as ArrayBuffer, col.byteOffset, 16);\n gpu.uploadedOpacity = r.opacity;\n }\n}\n\nfunction drawTextRenderable(gpu: TextRenderableGpu, data: TextData, quadVertex: GPUBuffer, pass: GPURenderPassEncoder | GPURenderBundleEncoder): number {\n if (data._instanceCount === 0) {\n return 0;\n }\n pass.setVertexBuffer(0, quadVertex);\n pass.setVertexBuffer(1, gpu.instanceBuf);\n let draws = 0;\n for (const g of data._groups) {\n if (g.slotCount === 0 || !g.bindGroup) {\n continue;\n }\n pass.setBindGroup(0, g.bindGroup);\n pass.draw(6, g.slotCount, 0, g.slotStart);\n draws++;\n }\n return draws;\n}\n\n/** Release GPU buffers owned by a text renderable. The underlying `TextData` and `GlyphStorage` remain caller-owned. */\nexport function disposeTextRenderable(renderable: TextRenderable): void {\n if (renderable._gpu) {\n renderable._gpu.textU.destroy();\n renderable._gpu.instanceBuf.destroy();\n renderable._gpu = null;\n }\n}\n\n/** Attach a `TextRenderable` to a scene. Uses the scene's deferred-renderables hook. */\nexport function addTextRenderable(scene: SceneContext, renderable: TextRenderable): void {\n addDeferredSceneRenderables(scene, () => {\n return {\n renderables: [renderable],\n dispose: () => disposeTextRenderable(renderable),\n };\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"text-renderable.js","sources":["../../../src/text/text-renderable.ts"],"sourcesContent":["/** TextRenderable — a scene-attachable text entity backed by a TextData.\n * Mirrors Mesh's TRS surface (position/rotation/rotationQuaternion/scaling). */\n\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { DrawBinding, DrawUpdateContext, Renderable } from \"../render/renderable.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport { ObservableQuat } from \"../math/observable-quat.js\";\nimport { composeTrsLocalMatrix, createWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { createEulerProxy } from \"../scene/scene-node.js\";\nimport type { EulerProxy } from \"../scene/scene-node.js\";\nimport { createEmptyUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport { addDeferredSceneRenderables } from \"../scene/scene-core.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Mat4, Mat4Storage, Vec3 } from \"../math/types.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport { getViewProjectionMatrix, getEffectiveAspectRatio, _cameraChangeKey } from \"../camera/camera.js\";\nimport type { TextData } from \"./text-data.js\";\nimport { TEXT_INSTANCE_BYTES } from \"./text-data.js\";\nimport { ensureSharedAtlasGpu } from \"./_gpu/text-textures.js\";\nimport { getOrCreateTextPipeline } from \"./_gpu/text-pipeline.js\";\n\n/** Initial transform and draw options for a scene-attached text renderable. */\nexport interface TextRenderableOptions {\n readonly position?: Readonly<Vec3>;\n readonly rotationQuaternion?: { readonly x: number; readonly y: number; readonly z: number; readonly w: number };\n readonly scaling?: Readonly<Vec3>;\n /** Whole-block opacity in [0,1]. Default 1. Per-glyph/per-run color comes from the `TextData`\n * descriptor (`PlacedGlyph.color` / `GlyphRun.defaultColor`), not from the renderable. */\n readonly opacity?: number;\n readonly ignoreDepth?: boolean;\n readonly order?: number;\n}\n\n/** Scene renderable that draws a `TextData` block with mesh-like transform controls. */\nexport interface TextRenderable extends Renderable {\n /** @internal */\n readonly _entityType: \"text\";\n readonly position: ObservableVec3;\n readonly rotation: EulerProxy;\n readonly rotationQuaternion: ObservableQuat;\n readonly scaling: ObservableVec3;\n /** Whole-block opacity in [0,1]. Color is supplied per-glyph by the `TextData` descriptor. */\n opacity: number;\n ignoreDepth: boolean;\n order: number;\n /** @internal */ readonly _data: TextData;\n /** @internal */ readonly _worldMatrix: () => Mat4;\n /** @internal */ _wmDirty: boolean;\n /** @internal */ _gpu: TextRenderableGpu | null;\n /** @internal */ _version: number;\n}\n\ninterface TextRenderableGpu {\n device: GPUDevice;\n textU: GPUBuffer;\n instanceBuf: GPUBuffer;\n instanceCap: number;\n pipeline: GPURenderPipeline;\n uploadedDataVersion: number;\n uploadedCameraVersion: number;\n uploadedAspect: number;\n uploadedViewportW: number;\n uploadedViewportH: number;\n uploadedOpacity: number;\n targetKey: string;\n}\n\nconst TEXT_UBO_BYTES = 64 /* mvp */ + 16 /* viewport */ + 16; /* color */\nconst _mvpScratch = new Float32Array(16);\n\nfunction targetSig(target: RenderTargetSignature): string {\n return (target._colorFormat ?? \"-\") + \":\" + (target._sampleCount ?? 1) + \":\" + (target._depthStencilFormat ?? \"-\");\n}\n\n/** Create a scene renderable that draws the supplied `TextData` through the normal renderable pipeline.\n *\n * @param data - Text data block to render.\n * @param options - Optional transform, opacity, depth, and ordering settings.\n * @returns A transparent renderable suitable for adding to a scene. */\nexport function createTextRenderable(data: TextData, options?: TextRenderableOptions): TextRenderable {\n const pos = options?.position;\n const rq = options?.rotationQuaternion;\n const sc = options?.scaling;\n const initRq = rq ?? { x: 0, y: 0, z: 0, w: 1 };\n\n const wm = createWorldMatrixState(() => composeTrsLocalMatrix(r.position, r.rotationQuaternion, r.scaling));\n const markDirty = (): void => {\n r._wmDirty = true;\n wm.markLocalDirty();\n };\n const quat = new ObservableQuat(initRq.x, initRq.y, initRq.z, initRq.w, markDirty);\n\n const r: TextRenderable = {\n _entityType: \"text\",\n order: options?.order ?? 200,\n isTransparent: true,\n position: new ObservableVec3(pos?.x ?? 0, pos?.y ?? 0, pos?.z ?? 0, markDirty),\n rotationQuaternion: quat,\n rotation: createEulerProxy(quat),\n scaling: new ObservableVec3(sc?.x ?? 1, sc?.y ?? 1, sc?.z ?? 1, markDirty),\n opacity: options?.opacity ?? 1,\n ignoreDepth: options?.ignoreDepth ?? false,\n _data: data,\n _wmDirty: true,\n _gpu: null,\n _version: 0,\n _worldMatrix: () => wm.getWorldMatrix(),\n bind(engine, target): DrawBinding {\n return bindTextRenderable(r, engine, target);\n },\n };\n return r;\n}\n\nfunction ensureGpu(r: TextRenderable, engine: EngineContext, target: RenderTargetSignature): TextRenderableGpu {\n const device = engine._device;\n const sampleCount = target._sampleCount === 1 ? 1 : 4;\n const colorFormat = target._colorFormat;\n if (!colorFormat) {\n throw new Error(\"TextRenderable: render target has no color format.\");\n }\n const depthFormat = target._depthStencilFormat ?? null;\n const depthWrite = !r.ignoreDepth;\n const { pipeline } = getOrCreateTextPipeline(engine, colorFormat, sampleCount, depthFormat, depthWrite);\n const key = targetSig(target);\n let gpu = r._gpu;\n if (gpu && gpu.device !== device) {\n gpu.textU.destroy();\n gpu.instanceBuf.destroy();\n gpu = null;\n }\n if (!gpu || gpu.targetKey !== key || gpu.pipeline !== pipeline) {\n if (!gpu) {\n const cap = Math.max(r._data._instanceCount, 8);\n gpu = {\n device,\n textU: createEmptyUniformBuffer(engine, TEXT_UBO_BYTES, \"text-renderable-ubo\"),\n instanceBuf: device.createBuffer({\n label: \"text-instance\",\n size: cap * TEXT_INSTANCE_BYTES,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n }),\n instanceCap: cap,\n pipeline,\n uploadedDataVersion: -1,\n uploadedCameraVersion: -1,\n uploadedAspect: -1,\n uploadedViewportW: 0,\n uploadedViewportH: 0,\n uploadedOpacity: NaN,\n targetKey: key,\n };\n r._gpu = gpu;\n } else {\n gpu.pipeline = pipeline;\n gpu.targetKey = key;\n // Pipeline change — per-group bind groups must be rebuilt against the new bindGroupLayout.\n for (const g of r._data._groups) {\n g.bindGroup = null;\n g.bindGroupVersion = -1;\n }\n }\n }\n return gpu;\n}\n\nfunction ensureInstanceCapacity(device: GPUDevice, gpu: TextRenderableGpu, needed: number): void {\n if (needed <= gpu.instanceCap) {\n return;\n }\n let cap = gpu.instanceCap;\n while (cap < needed) {\n cap *= 2;\n }\n gpu.instanceBuf.destroy();\n gpu.instanceBuf = device.createBuffer({\n label: \"text-instance\",\n size: cap * TEXT_INSTANCE_BYTES,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n gpu.instanceCap = cap;\n gpu.uploadedDataVersion = -1;\n}\n\nfunction bindTextRenderable(r: TextRenderable, engine: EngineContext, target: RenderTargetSignature): DrawBinding {\n const gpu = ensureGpu(r, engine, target);\n const { cache } = getOrCreateTextPipeline(engine, target._colorFormat!, target._sampleCount === 1 ? 1 : 4, target._depthStencilFormat ?? null, !r.ignoreDepth);\n const quadVertex = cache.quadVertexBuffer;\n const bindGroupLayout = cache.bindGroupLayout;\n\n return {\n renderable: r,\n pipeline: gpu.pipeline,\n update(context: DrawUpdateContext): void {\n updateTextRenderable(r, engine, gpu, bindGroupLayout, context);\n },\n draw(pass): number {\n return drawTextRenderable(gpu, r._data, quadVertex, pass);\n },\n };\n}\n\nfunction updateTextRenderable(r: TextRenderable, engine: EngineContext, gpu: TextRenderableGpu, bindGroupLayout: GPUBindGroupLayout, context: DrawUpdateContext): void {\n const device = engine._device;\n const data = r._data;\n\n // Sync every group's atlas to the GPU; track which need bind-group rebuild.\n for (const g of data._groups) {\n const { rebuilt, gpu: atlasGpu } = ensureSharedAtlasGpu(device, g.curveSet.atlas);\n if (rebuilt || !g.bindGroup || g.bindGroupVersion !== atlasGpu.uploadedVersion) {\n g.bindGroup = device.createBindGroup({\n label: \"text-bg0-\" + g.curveSetId,\n layout: bindGroupLayout,\n entries: [\n { binding: 0, resource: { buffer: gpu.textU } },\n { binding: 1, resource: atlasGpu.curveTex.createView() },\n { binding: 2, resource: atlasGpu.bandTex.createView() },\n ],\n });\n g.bindGroupVersion = atlasGpu.uploadedVersion;\n }\n }\n\n // Sync instance buffer if data changed.\n ensureInstanceCapacity(device, gpu, data._instanceCount);\n if (gpu.uploadedDataVersion !== data._version) {\n if (data._instanceCount > 0) {\n // Partial upload when only a sub-range is dirty; full upload after grow/reset (when\n // uploadedDataVersion is -1 we don't trust the dirty range).\n const dirtyValid = gpu.uploadedDataVersion !== -1 && data._dirtyEnd > data._dirtyStart;\n if (dirtyValid) {\n const startFloats = data._dirtyStart * (TEXT_INSTANCE_BYTES / 4);\n const endFloats = data._dirtyEnd * (TEXT_INSTANCE_BYTES / 4);\n const view = data._instances.subarray(startFloats, endFloats);\n device.queue.writeBuffer(gpu.instanceBuf, data._dirtyStart * TEXT_INSTANCE_BYTES, view.buffer as ArrayBuffer, view.byteOffset, view.byteLength);\n } else {\n const view = data._instances.subarray(0, data._instanceCount * (TEXT_INSTANCE_BYTES / 4));\n device.queue.writeBuffer(gpu.instanceBuf, 0, view.buffer as ArrayBuffer, view.byteOffset, view.byteLength);\n }\n }\n gpu.uploadedDataVersion = data._version;\n data._dirtyStart = 0;\n data._dirtyEnd = 0;\n }\n\n // Sync text UBO: mvp (vp * world) + viewport + color. The scene UBO is no longer\n // consumed by the text pipeline, so we compose the mvp here from the active camera.\n // Skip the recompute + upload when the world matrix, camera, and aspect are all unchanged.\n const camera = context._camera ?? null;\n if (camera) {\n const aspect = getEffectiveAspectRatio(camera, context.targetWidth, context.targetHeight);\n const camVer = _cameraChangeKey(camera);\n if (r._wmDirty || gpu.uploadedCameraVersion !== camVer || gpu.uploadedAspect !== aspect) {\n const vp = getViewProjectionMatrix(camera, aspect) as unknown as Float32Array;\n const wm = r._worldMatrix();\n mat4MultiplyInto(_mvpScratch, 0, vp, 0, wm as unknown as Mat4Storage, 0);\n device.queue.writeBuffer(gpu.textU, 0, _mvpScratch.buffer as ArrayBuffer, _mvpScratch.byteOffset, 64);\n r._wmDirty = false;\n gpu.uploadedCameraVersion = camVer;\n gpu.uploadedAspect = aspect;\n }\n }\n if (gpu.uploadedViewportW !== context.targetWidth || gpu.uploadedViewportH !== context.targetHeight) {\n const vp = new Float32Array([context.targetWidth, context.targetHeight, 0, 0]);\n device.queue.writeBuffer(gpu.textU, 64, vp.buffer as ArrayBuffer, vp.byteOffset, 16);\n gpu.uploadedViewportW = context.targetWidth;\n gpu.uploadedViewportH = context.targetHeight;\n }\n // Color uniform carries whole-block opacity as alpha (rgb fixed to white). Per-glyph color\n // comes from the instance `slugColor` attribute.\n if (gpu.uploadedOpacity !== r.opacity) {\n const col = new Float32Array([1, 1, 1, r.opacity]);\n device.queue.writeBuffer(gpu.textU, 80, col.buffer as ArrayBuffer, col.byteOffset, 16);\n gpu.uploadedOpacity = r.opacity;\n }\n}\n\nfunction drawTextRenderable(gpu: TextRenderableGpu, data: TextData, quadVertex: GPUBuffer, pass: GPURenderPassEncoder | GPURenderBundleEncoder): number {\n if (data._instanceCount === 0) {\n return 0;\n }\n pass.setVertexBuffer(0, quadVertex);\n pass.setVertexBuffer(1, gpu.instanceBuf);\n let draws = 0;\n for (const g of data._groups) {\n if (g.slotCount === 0 || !g.bindGroup) {\n continue;\n }\n pass.setBindGroup(0, g.bindGroup);\n pass.draw(6, g.slotCount, 0, g.slotStart);\n draws++;\n }\n return draws;\n}\n\n/** Release GPU buffers owned by a text renderable. The underlying `TextData` and `GlyphStorage` remain caller-owned. */\nexport function disposeTextRenderable(renderable: TextRenderable): void {\n if (renderable._gpu) {\n renderable._gpu.textU.destroy();\n renderable._gpu.instanceBuf.destroy();\n renderable._gpu = null;\n }\n}\n\n/** Attach a `TextRenderable` to a scene. Uses the scene's deferred-renderables hook. */\nexport function addTextRenderable(scene: SceneContext, renderable: TextRenderable): void {\n addDeferredSceneRenderables(scene, () => {\n return {\n renderables: [renderable],\n dispose: () => disposeTextRenderable(renderable),\n };\n });\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babylonjs/lite",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "A lightweight, tree-shakable, WebGPU-first rendering library derived from Babylon.js.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://doc.babylonjs.com/lite/",
@@ -16,14 +16,6 @@
16
16
  ".": {
17
17
  "types": "./index.d.ts",
18
18
  "import": "./lib/index.js"
19
- },
20
- "./material/standard/enable-standard-vertex-colors": {
21
- "types": "./material/standard/enable-standard-vertex-colors.d.ts",
22
- "import": "./lib/material/standard/enable-standard-vertex-colors.js"
23
- },
24
- "./material/standard/enable-standard-mesh-features": {
25
- "types": "./material/standard/enable-standard-mesh-features.d.ts",
26
- "import": "./lib/material/standard/enable-standard-mesh-features.js"
27
19
  }
28
20
  },
29
21
  "jsdelivr": "./dist/index.js",
@@ -42,7 +34,7 @@
42
34
  }
43
35
  },
44
36
  "babylonLiteRelease": {
45
- "azureBuildId": "56694",
46
- "sourceVersion": "a6ad479090cff91eb20e383c6d956fff96470a36"
37
+ "azureBuildId": "56772",
38
+ "sourceVersion": "42534bbd8bd209a66fc3659d381ad6a0a9493628"
47
39
  }
48
40
  }
@@ -1,4 +0,0 @@
1
- /** Enable Standard skeletal skinning for matching meshes. */
2
- export declare function enableStandardSkeleton(): void;
3
- /** Enable optional Standard material UV translation. */
4
- export declare function enableStandardUvOffset(): void;
@@ -1,2 +0,0 @@
1
- /** Enable RGBA mesh vertex colors for StandardMaterial. */
2
- export declare function enableStandardVertexColors(): void;