@driftengine/core 4.4.2 → 4.6.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.
- package/CHANGELOG.json +97 -0
- package/README.md +1 -1
- package/dist/geometry/boxCsg.d.ts +28 -0
- package/dist/geometry/boxCsg.js +139 -0
- package/dist/geometry/csg.d.ts +36 -0
- package/dist/geometry/csg.js +329 -0
- package/dist/geometry/meshBuilder.js +13 -0
- package/dist/geometry/meshConcat.js +1 -0
- package/dist/geometry/pixelFont.js +2 -0
- package/dist/geometry/solid.d.ts +61 -0
- package/dist/geometry/solid.js +152 -0
- package/dist/geometry/solidFlat.d.ts +35 -0
- package/dist/geometry/solidFlat.js +428 -0
- package/dist/geometry/solidHarness.d.ts +19 -0
- package/dist/geometry/solidHarness.js +66 -0
- package/dist/geometry/solidNormals.d.ts +17 -0
- package/dist/geometry/solidNormals.js +86 -0
- package/dist/geometry/solidRound.d.ts +41 -0
- package/dist/geometry/solidRound.js +323 -0
- package/dist/geometry/solidWriter.d.ts +16 -0
- package/dist/geometry/solidWriter.js +42 -0
- package/dist/index.d.ts +28 -3
- package/dist/index.js +20 -1
- package/dist/render/backend/api.d.ts +34 -14
- package/dist/render/backend/drawFog.d.ts +26 -0
- package/dist/render/backend/drawFog.js +30 -0
- package/dist/render/backend/materialChanges.d.ts +2 -1
- package/dist/render/backend/materialChanges.js +6 -1
- package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
- package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
- package/dist/render/backend/webgl2/instanced.d.ts +24 -5
- package/dist/render/backend/webgl2/instanced.js +72 -15
- package/dist/render/backend/webgl2/renderer.d.ts +201 -16
- package/dist/render/backend/webgl2/renderer.js +596 -224
- package/dist/render/backend/webgpu/buffers.d.ts +29 -1
- package/dist/render/backend/webgpu/buffers.js +61 -4
- package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
- package/dist/render/backend/webgpu/depthPass.js +7 -2
- package/dist/render/backend/webgpu/drawCommand.d.ts +5 -0
- package/dist/render/backend/webgpu/drawCommand.js +1 -0
- package/dist/render/backend/webgpu/flatPass.d.ts +6 -1
- package/dist/render/backend/webgpu/flatPass.js +57 -9
- package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
- package/dist/render/backend/webgpu/glassTintPass.js +206 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
- package/dist/render/backend/webgpu/instanceCullPass.d.ts +34 -0
- package/dist/render/backend/webgpu/instanceCullPass.js +144 -0
- package/dist/render/backend/webgpu/instanced.d.ts +23 -2
- package/dist/render/backend/webgpu/instanced.js +41 -4
- package/dist/render/backend/webgpu/latePass.d.ts +30 -0
- package/dist/render/backend/webgpu/latePass.js +140 -0
- package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
- package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
- package/dist/render/backend/webgpu/motionPass.js +491 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
- package/dist/render/backend/webgpu/pipelineCache.js +11 -1
- package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
- package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
- package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
- package/dist/render/backend/webgpu/postPass.d.ts +3 -13
- package/dist/render/backend/webgpu/renderer.d.ts +271 -64
- package/dist/render/backend/webgpu/renderer.js +1395 -580
- package/dist/render/backend/webgpu/scatterPass.js +2 -1
- package/dist/render/backend/webgpu/sdfTextPass.js +6 -1
- package/dist/render/backend/webgpu/shaders/instanceCull.wgsl.d.ts +18 -0
- package/dist/render/backend/webgpu/shaders/instanceCull.wgsl.js +59 -0
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
- package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
- package/dist/render/backend/webgpu/snapshotMips.js +52 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +22 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +78 -39
- package/dist/render/driftLight/bake.d.ts +7 -0
- package/dist/render/driftLight/bake.js +61 -56
- package/dist/render/driftLight/denseField.d.ts +46 -0
- package/dist/render/driftLight/denseField.js +109 -0
- package/dist/render/driftLight/lightField.d.ts +10 -5
- package/dist/render/driftLight/lightField.js +25 -19
- package/dist/render/driftLight/presence.d.ts +50 -0
- package/dist/render/driftLight/presence.js +43 -0
- package/dist/render/driftLight/uniforms.d.ts +3 -3
- package/dist/render/driftLight/uniforms.js +5 -6
- package/dist/render/driftLight/worldLightField.d.ts +41 -0
- package/dist/render/driftLight/worldLightField.js +66 -0
- package/dist/render/fixtureAtlas.d.ts +20 -0
- package/dist/render/fixtureAtlas.js +49 -0
- package/dist/render/glass.d.ts +45 -0
- package/dist/render/glass.js +39 -0
- package/dist/render/glassCasters.d.ts +40 -0
- package/dist/render/glassCasters.js +84 -0
- package/dist/render/glassShadow.d.ts +78 -0
- package/dist/render/glassShadow.js +125 -0
- package/dist/render/globalMediumPass.d.ts +2 -3
- package/dist/render/globalMediumPass.js +2 -8
- package/dist/render/gpudriven/lit.d.ts +12 -0
- package/dist/render/gpudriven/lit.js +23 -0
- package/dist/render/gpudriven/materialTable.d.ts +15 -5
- package/dist/render/gpudriven/materialTable.js +26 -6
- package/dist/render/gpudriven/pipeline.d.ts +1 -1
- package/dist/render/gpudriven/pipeline.js +4 -3
- package/dist/render/gpudriven/sunGlass.d.ts +35 -0
- package/dist/render/gpudriven/sunGlass.js +89 -0
- package/dist/render/instanceCull.d.ts +63 -0
- package/dist/render/instanceCull.js +160 -0
- package/dist/render/instances.d.ts +15 -0
- package/dist/render/lightBudget.d.ts +36 -35
- package/dist/render/lightBudget.js +38 -37
- package/dist/render/lightGrid.d.ts +42 -0
- package/dist/render/lightGrid.js +87 -0
- package/dist/render/mesh.d.ts +18 -24
- package/dist/render/mesh.js +51 -68
- package/dist/render/occlusion.d.ts +10 -0
- package/dist/render/occlusion.js +36 -7
- package/dist/render/pointGlassTint.d.ts +59 -0
- package/dist/render/pointGlassTint.js +198 -0
- package/dist/render/pointLightSelection.d.ts +7 -0
- package/dist/render/pointLightSelection.js +29 -4
- package/dist/render/pointShadowArray.d.ts +56 -3
- package/dist/render/pointShadowArray.js +127 -16
- package/dist/render/pointShadowMap.d.ts +23 -1
- package/dist/render/pointShadowMap.js +27 -1
- package/dist/render/rainField.d.ts +13 -0
- package/dist/render/rainField.js +27 -5
- package/dist/render/recon/changeFrames.d.ts +15 -0
- package/dist/render/recon/changeFrames.js +21 -0
- package/dist/render/recon/lateDepth.d.ts +11 -0
- package/dist/render/recon/lateDepth.js +70 -0
- package/dist/render/recon/lateRouting.d.ts +14 -0
- package/dist/render/recon/lateRouting.js +18 -0
- package/dist/render/recon/mover.d.ts +57 -0
- package/dist/render/recon/mover.js +86 -0
- package/dist/render/recon/resolve.d.ts +34 -4
- package/dist/render/recon/resolve.js +161 -20
- package/dist/render/renderQuality.d.ts +35 -0
- package/dist/render/renderQuality.js +7 -0
- package/dist/render/rendererHarness.js +16 -0
- package/dist/render/sceneTarget.d.ts +9 -1
- package/dist/render/sceneTarget.js +60 -12
- package/dist/render/shaders/depth.d.ts +16 -1
- package/dist/render/shaders/depth.js +94 -15
- package/dist/render/shaders/flat/directionalShadow.js +91 -6
- package/dist/render/shaders/flat/driftLight.d.ts +1 -1
- package/dist/render/shaders/flat/driftLight.js +32 -7
- package/dist/render/shaders/flat/glassTint.d.ts +6 -0
- package/dist/render/shaders/flat/glassTint.js +25 -0
- package/dist/render/shaders/flat/index.d.ts +13 -0
- package/dist/render/shaders/flat/index.js +9 -3
- package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
- package/dist/render/shaders/flat/lampGlass.js +183 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +190 -38
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
- package/dist/render/shaders/flat/pointShadow.js +2 -0
- package/dist/render/shaders/flat/preamble.js +96 -26
- package/dist/render/shaders/flat/surfaceEffects.d.ts +29 -0
- package/dist/render/shaders/flat/surfaceEffects.js +152 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +230 -7
- package/dist/render/shaders/generated/depth.wgsl.js +230 -7
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1644 -1596
- package/dist/render/shaders/generated/flat.wgsl.js +1683 -1621
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.js +21 -17
- package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/rush.wgsl.d.ts +21 -16
- package/dist/render/shaders/generated/rush.wgsl.js +21 -16
- package/dist/render/shaders/generated/sdfText.wgsl.d.ts +2 -2
- package/dist/render/shaders/generated/sdfText.wgsl.js +2 -2
- package/dist/render/shaders/generated/text.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/text.wgsl.js +1 -1
- package/dist/render/shaders/gi/driftLight.wgsl.d.ts +1 -1
- package/dist/render/shaders/gi/driftLight.wgsl.js +27 -4
- package/dist/render/shaders/globalMedium.js +6 -6
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
- package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
- package/dist/render/shaders/lightVolume.js +6 -6
- package/dist/render/shaders/octahedralResolve.d.ts +8 -0
- package/dist/render/shaders/octahedralResolve.js +48 -17
- package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
- package/dist/render/shaders/recon/lateDepth.wgsl.js +69 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +84 -0
- package/dist/render/shaders/recon/resolve.wgsl.d.ts +8 -7
- package/dist/render/shaders/recon/resolve.wgsl.js +161 -27
- package/dist/render/shaders/rush.js +11 -1
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/sdfText.js +3 -2
- package/dist/render/shaders/text.d.ts +1 -1
- package/dist/render/shaders/text.js +18 -9
- package/dist/render/shadowCasters.d.ts +20 -1
- package/dist/render/shadowCasters.js +15 -1
- package/dist/render/shadowMap.d.ts +54 -5
- package/dist/render/shadowMap.js +190 -36
- package/dist/render/sunGlassTint.d.ts +25 -0
- package/dist/render/sunGlassTint.js +79 -0
- package/dist/render/surfaceEffects.d.ts +83 -0
- package/dist/render/surfaceEffects.js +75 -0
- package/dist/render/surfaceScene.d.ts +8 -0
- package/dist/render/surfaceScene.js +8 -0
- package/dist/render/surfaceTexture.d.ts +18 -2
- package/dist/render/surfaceTexture.js +68 -15
- package/dist/render/temporalAa.d.ts +25 -6
- package/dist/render/temporalAa.js +45 -15
- package/dist/render/textureSource.d.ts +30 -0
- package/dist/render/textureSource.js +53 -0
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +15 -1
- package/dist/render/vertexDefaults.js +2 -0
- package/dist/world/hlod.d.ts +104 -0
- package/dist/world/hlod.js +214 -0
- package/package.json +6 -6
- package/src/geometry/boxCsg.ts +186 -0
- package/src/geometry/csg.ts +384 -0
- package/src/geometry/meshBuilder.ts +15 -0
- package/src/geometry/meshConcat.ts +1 -0
- package/src/geometry/pixelFont.ts +2 -0
- package/src/geometry/solid.ts +189 -0
- package/src/geometry/solidFlat.ts +522 -0
- package/src/geometry/solidHarness.ts +83 -0
- package/src/geometry/solidNormals.ts +103 -0
- package/src/geometry/solidRound.ts +443 -0
- package/src/geometry/solidWriter.ts +58 -0
- package/src/index.ts +61 -1
- package/src/render/backend/api.ts +36 -11
- package/src/render/backend/drawFog.ts +31 -0
- package/src/render/backend/materialChanges.ts +9 -2
- package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
- package/src/render/backend/webgl2/instanced.ts +80 -14
- package/src/render/backend/webgl2/renderer.ts +700 -250
- package/src/render/backend/webgpu/buffers.ts +92 -5
- package/src/render/backend/webgpu/depthPass.ts +7 -2
- package/src/render/backend/webgpu/drawCommand.ts +6 -0
- package/src/render/backend/webgpu/flatPass.ts +62 -11
- package/src/render/backend/webgpu/glassTintPass.ts +245 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
- package/src/render/backend/webgpu/instanceCullPass.ts +165 -0
- package/src/render/backend/webgpu/instanced.ts +42 -4
- package/src/render/backend/webgpu/latePass.ts +161 -0
- package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
- package/src/render/backend/webgpu/motionPass.ts +535 -0
- package/src/render/backend/webgpu/pipelineCache.ts +12 -1
- package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
- package/src/render/backend/webgpu/renderer.ts +1671 -670
- package/src/render/backend/webgpu/scatterPass.ts +2 -1
- package/src/render/backend/webgpu/sdfTextPass.ts +6 -1
- package/src/render/backend/webgpu/shaders/instanceCull.wgsl.ts +61 -0
- package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
- package/src/render/backend/webgpu/snapshotMips.ts +80 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +91 -51
- package/src/render/driftLight/bake.ts +85 -62
- package/src/render/driftLight/denseField.ts +149 -0
- package/src/render/driftLight/lightField.ts +33 -18
- package/src/render/driftLight/presence.ts +69 -0
- package/src/render/driftLight/uniforms.ts +8 -9
- package/src/render/driftLight/worldLightField.ts +83 -0
- package/src/render/fixtureAtlas.ts +63 -0
- package/src/render/glass.ts +74 -0
- package/src/render/glassCasters.ts +164 -0
- package/src/render/glassShadow.ts +153 -0
- package/src/render/globalMediumPass.ts +4 -11
- package/src/render/gpudriven/lit.ts +31 -0
- package/src/render/gpudriven/materialTable.ts +28 -6
- package/src/render/gpudriven/pipeline.ts +4 -3
- package/src/render/gpudriven/sunGlass.ts +117 -0
- package/src/render/instanceCull.ts +205 -0
- package/src/render/instances.ts +16 -0
- package/src/render/lightBudget.ts +41 -38
- package/src/render/lightGrid.ts +130 -0
- package/src/render/mesh.ts +59 -72
- package/src/render/occlusion.ts +51 -7
- package/src/render/pointGlassTint.ts +250 -0
- package/src/render/pointLightSelection.ts +72 -4
- package/src/render/pointShadowArray.ts +188 -22
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/rainField.ts +39 -5
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/lateDepth.ts +83 -0
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/recon/resolve.ts +206 -20
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +16 -0
- package/src/render/sceneTarget.ts +62 -11
- package/src/render/shaders/depth.ts +118 -15
- package/src/render/shaders/flat/directionalShadow.ts +97 -6
- package/src/render/shaders/flat/driftLight.ts +32 -7
- package/src/render/shaders/flat/glassTint.ts +25 -0
- package/src/render/shaders/flat/index.ts +22 -3
- package/src/render/shaders/flat/lampGlass.ts +185 -0
- package/src/render/shaders/flat/main.ts +190 -38
- package/src/render/shaders/flat/pointShadow.ts +2 -0
- package/src/render/shaders/flat/preamble.ts +96 -26
- package/src/render/shaders/flat/surfaceEffects.ts +152 -0
- package/src/render/shaders/generated/depth.wgsl.ts +237 -7
- package/src/render/shaders/generated/flat.wgsl.ts +1685 -1621
- package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
- package/src/render/shaders/generated/lightVolume.wgsl.ts +23 -17
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/rush.wgsl.ts +21 -16
- package/src/render/shaders/generated/sdfText.wgsl.ts +2 -2
- package/src/render/shaders/generated/text.wgsl.ts +1 -1
- package/src/render/shaders/gi/driftLight.wgsl.ts +27 -4
- package/src/render/shaders/globalMedium.ts +6 -6
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
- package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
- package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
- package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
- package/src/render/shaders/lightVolume.ts +6 -6
- package/src/render/shaders/octahedralResolve.ts +50 -17
- package/src/render/shaders/recon/lateDepth.wgsl.ts +72 -0
- package/src/render/shaders/recon/motion.wgsl.ts +84 -0
- package/src/render/shaders/recon/resolve.wgsl.ts +161 -27
- package/src/render/shaders/rush.ts +11 -1
- package/src/render/shaders/sdfText.ts +3 -2
- package/src/render/shaders/text.ts +18 -9
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/surfaceEffects.ts +132 -0
- package/src/render/surfaceScene.ts +16 -0
- package/src/render/surfaceTexture.ts +110 -19
- package/src/render/temporalAa.ts +78 -14
- package/src/render/textureSource.ts +72 -0
- package/src/render/translucentQueue.ts +20 -1
- package/src/render/vertexDefaults.ts +2 -0
- package/src/world/hlod.ts +290 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The glass a shadow pass was offered, kept aside to be drawn twice once the opaque casters are in:
|
|
3
|
+
* where the nearest pane is, and what the panes let through. See `glassShadow.ts`.
|
|
4
|
+
*
|
|
5
|
+
* **Recorded rather than drawn at once**, because the two glass passes each need the whole set and
|
|
6
|
+
* a pass of their own, and the caster enumeration is the consumer's to run exactly once per pass.
|
|
7
|
+
* A pool of entries grown on demand and never shrunk, so a steady scene records into the entries
|
|
8
|
+
* the frame before it made — no allocation per frame, the house rule for a per-pass path.
|
|
9
|
+
*
|
|
10
|
+
* What it keeps by reference is only what outlives the pass that recorded it: the mesh, the batch
|
|
11
|
+
* and its instance data, a skinned caster's palette, and the material. The model matrix is copied,
|
|
12
|
+
* because a caller is entitled to reuse one scratch matrix between sink calls.
|
|
13
|
+
*/
|
|
14
|
+
import type { ReadonlyMat4 } from 'gl-matrix';
|
|
15
|
+
import type { ResolvedGlass } from './glass.ts';
|
|
16
|
+
import type { InstancedHandle, MeshHandle } from './backend/api.ts';
|
|
17
|
+
import type { MeshInstances } from './instances.ts';
|
|
18
|
+
import type { SceneCasterMaterial } from './shadowCasters.ts';
|
|
19
|
+
/** Where a replay goes: each entry with its own glass, as the depth and tint passes want it. */
|
|
20
|
+
export interface GlassReplaySink {
|
|
21
|
+
mesh(mesh: MeshHandle, model: ReadonlyMat4, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
22
|
+
instanced(batch: InstancedHandle, data: MeshInstances, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
23
|
+
skinnedMesh(mesh: MeshHandle, model: ReadonlyMat4, palette: Float32Array, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
24
|
+
}
|
|
25
|
+
export declare class GlassCasterList {
|
|
26
|
+
private readonly pool;
|
|
27
|
+
private used;
|
|
28
|
+
/** How many glass casters this pass has recorded. */
|
|
29
|
+
get count(): number;
|
|
30
|
+
/** How many entries the pool holds, recorded or not: what a steady scene stops growing. */
|
|
31
|
+
get pooled(): number;
|
|
32
|
+
recordMesh(mesh: MeshHandle, model: ReadonlyMat4, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
33
|
+
recordInstanced(batch: InstancedHandle, data: MeshInstances, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
34
|
+
recordSkinned(mesh: MeshHandle, model: ReadonlyMat4, palette: Float32Array, material: SceneCasterMaterial | undefined, glass: ResolvedGlass): void;
|
|
35
|
+
/** Every recorded caster, in the order it was offered. */
|
|
36
|
+
replay(sink: GlassReplaySink): void;
|
|
37
|
+
/** Forget this pass's casters; the entries stay for the next one. */
|
|
38
|
+
clear(): void;
|
|
39
|
+
private take;
|
|
40
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const MESH = 0;
|
|
2
|
+
const INSTANCED = 1;
|
|
3
|
+
const SKINNED = 2;
|
|
4
|
+
export class GlassCasterList {
|
|
5
|
+
pool = [];
|
|
6
|
+
used = 0;
|
|
7
|
+
/** How many glass casters this pass has recorded. */
|
|
8
|
+
get count() {
|
|
9
|
+
return this.used;
|
|
10
|
+
}
|
|
11
|
+
/** How many entries the pool holds, recorded or not: what a steady scene stops growing. */
|
|
12
|
+
get pooled() {
|
|
13
|
+
return this.pool.length;
|
|
14
|
+
}
|
|
15
|
+
recordMesh(mesh, model, material, glass) {
|
|
16
|
+
const entry = this.take(MESH, material, glass);
|
|
17
|
+
entry.mesh = mesh;
|
|
18
|
+
entry.model.set(model);
|
|
19
|
+
}
|
|
20
|
+
recordInstanced(batch, data, material, glass) {
|
|
21
|
+
const entry = this.take(INSTANCED, material, glass);
|
|
22
|
+
entry.batch = batch;
|
|
23
|
+
entry.data = data;
|
|
24
|
+
}
|
|
25
|
+
recordSkinned(mesh, model, palette, material, glass) {
|
|
26
|
+
const entry = this.take(SKINNED, material, glass);
|
|
27
|
+
entry.mesh = mesh;
|
|
28
|
+
entry.palette = palette;
|
|
29
|
+
entry.model.set(model);
|
|
30
|
+
}
|
|
31
|
+
/** Every recorded caster, in the order it was offered. */
|
|
32
|
+
replay(sink) {
|
|
33
|
+
for (let i = 0; i < this.used; i++) {
|
|
34
|
+
const entry = this.pool[i];
|
|
35
|
+
if (entry.kind === INSTANCED && entry.batch !== null && entry.data !== null) {
|
|
36
|
+
sink.instanced(entry.batch, entry.data, entry.material, entry.glass);
|
|
37
|
+
}
|
|
38
|
+
else if (entry.kind === SKINNED && entry.mesh !== null && entry.palette !== null) {
|
|
39
|
+
sink.skinnedMesh(entry.mesh, entry.model, entry.palette, entry.material, entry.glass);
|
|
40
|
+
}
|
|
41
|
+
else if (entry.mesh !== null) {
|
|
42
|
+
sink.mesh(entry.mesh, entry.model, entry.material, entry.glass);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Forget this pass's casters; the entries stay for the next one. */
|
|
47
|
+
clear() {
|
|
48
|
+
for (let i = 0; i < this.used; i++) {
|
|
49
|
+
const entry = this.pool[i];
|
|
50
|
+
/* Released so a disposed mesh is not held alive by a list nobody will replay again. */
|
|
51
|
+
entry.mesh = null;
|
|
52
|
+
entry.batch = null;
|
|
53
|
+
entry.data = null;
|
|
54
|
+
entry.palette = null;
|
|
55
|
+
entry.material = undefined;
|
|
56
|
+
}
|
|
57
|
+
this.used = 0;
|
|
58
|
+
}
|
|
59
|
+
take(kind, material, glass) {
|
|
60
|
+
let entry = this.pool[this.used];
|
|
61
|
+
if (entry === undefined) {
|
|
62
|
+
entry = {
|
|
63
|
+
kind,
|
|
64
|
+
mesh: null,
|
|
65
|
+
batch: null,
|
|
66
|
+
data: null,
|
|
67
|
+
palette: null,
|
|
68
|
+
model: new Float32Array(16),
|
|
69
|
+
material,
|
|
70
|
+
glass: { transmission: 0, frost: 0, tint: [1, 1, 1] },
|
|
71
|
+
};
|
|
72
|
+
this.pool.push(entry);
|
|
73
|
+
}
|
|
74
|
+
this.used++;
|
|
75
|
+
entry.kind = kind;
|
|
76
|
+
entry.material = material;
|
|
77
|
+
entry.glass.transmission = glass.transmission;
|
|
78
|
+
entry.glass.frost = glass.frost;
|
|
79
|
+
entry.glass.tint[0] = glass.tint[0];
|
|
80
|
+
entry.glass.tint[1] = glass.tint[1];
|
|
81
|
+
entry.glass.tint[2] = glass.tint[2];
|
|
82
|
+
return entry;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coloured light through glass: how one pane filters light, how panes combine, which receivers a
|
|
3
|
+
* pane tints, and how far frost spreads the colour — the reference the shaders state term for term.
|
|
4
|
+
*
|
|
5
|
+
* **Frost spreads light, it does not remove it.** Etched glass passes 88–91% of visible light
|
|
6
|
+
* against clear float glass's ~90%, so a frosted pane passes `transmission × (1 − F) × tint` like a
|
|
7
|
+
* clear one and only the filter widens. What it gives up: the spread stays inside the opaque frame's
|
|
8
|
+
* shadow, so light from a frosted pane does not reach past the outline of the frame around it. What
|
|
9
|
+
* would make it wrong is glass that genuinely absorbs as it diffuses — opal glass, milk glass — for
|
|
10
|
+
* which a lower `transmission` is the honest statement.
|
|
11
|
+
*
|
|
12
|
+
* **What else it does not reach**: light that bounces. DriftRay's probe bake and DriftLight's summed
|
|
13
|
+
* far field see a pane as absent, so the light a tinted window sends round a room by bouncing is its
|
|
14
|
+
* sun's own colour; only the direct light through the pane takes the tint.
|
|
15
|
+
*/
|
|
16
|
+
import { type ResolvedGlass } from './glass.ts';
|
|
17
|
+
/** One tint texel: the light a stack of panes lets through, and how clear the stack is. */
|
|
18
|
+
export interface GlassTexel {
|
|
19
|
+
r: number;
|
|
20
|
+
g: number;
|
|
21
|
+
b: number;
|
|
22
|
+
clarity: number;
|
|
23
|
+
}
|
|
24
|
+
/** No glass: everything passes, perfectly clear. What a tint map is cleared to. */
|
|
25
|
+
export declare const CLEAR_TEXEL: Readonly<GlassTexel>;
|
|
26
|
+
/** How widely a fully frosted pane spreads its colour: a 30° half-angle cone behind it. */
|
|
27
|
+
export declare const FROST_SPREAD: number;
|
|
28
|
+
/**
|
|
29
|
+
* The spread never exceeds this many base filter radii, and the tap count never changes.
|
|
30
|
+
*
|
|
31
|
+
* **Sixty-four, because the tint is read from the mip level the spread asks for**: each tap is then
|
|
32
|
+
* already an average over its own share of the spread, so taps far apart do not alias into grain.
|
|
33
|
+
* It was eight before the tint had mips, and on a sun map a few centimetres a texel that capped a
|
|
34
|
+
* frosted pane's spread at seven centimetres — frost that nobody saw. What the cap still bounds is
|
|
35
|
+
* a pane so frosted and so far above a floor that its colour would wash over a room.
|
|
36
|
+
*/
|
|
37
|
+
export declare const FROST_RADIUS_CAP = 64;
|
|
38
|
+
/** One pane as a tint texel, lit at `cosLight` to its normal. Fresnel as `glass.ts` states it. */
|
|
39
|
+
export declare function paneTexel(glass: ResolvedGlass, cosLight: number, out: GlassTexel): GlassTexel;
|
|
40
|
+
/** Two stacks of glass on one ray: a product, so the order they are drawn in cannot matter. */
|
|
41
|
+
export declare function combinePanes(a: GlassTexel, b: GlassTexel, out: GlassTexel): GlassTexel;
|
|
42
|
+
/**
|
|
43
|
+
* What one filter tap contributes: the glass's texel where the receiver is behind the pane, and
|
|
44
|
+
* nothing where it is on the light's side of it — or is the pane, which the bias keeps untinted.
|
|
45
|
+
*/
|
|
46
|
+
export declare function tapTint(receiverDepth: number, glassDepth: number, bias: number, glass: GlassTexel, out: GlassTexel): GlassTexel;
|
|
47
|
+
/**
|
|
48
|
+
* A frosted pane's tint at a receiver: the outline from the taps at the base radius, the colour
|
|
49
|
+
* from the spread taps that found glass — nothing else.
|
|
50
|
+
*
|
|
51
|
+
* **Split because a tint cannot carry light out past a pane.** Blurring the tint map whole pulls in
|
|
52
|
+
* the white of the unobstructed ground around a pane, which brightens the patch — measured at 10%
|
|
53
|
+
* more light over a frosted window than a clear one — while the pane's own light, which should
|
|
54
|
+
* spread onto that ground, has no way to exceed full sun there. So the outline stays where the
|
|
55
|
+
* clear pane's is (`coverage`, the share of outline taps behind glass) and only the colour spreads,
|
|
56
|
+
* averaged over glass alone (`colourSum` over `colourCount`, the summed pane shares `unmixTint`
|
|
57
|
+
* reports — continuous, so a colour crossing between panes blends rather than stepping): neighbouring
|
|
58
|
+
* panes mix, a pattern blurs, and the light through the patch is what it was. What it gives up is
|
|
59
|
+
* spread past the outline, which the spec states; with no glass found by the spread the colour is
|
|
60
|
+
* clear.
|
|
61
|
+
*/
|
|
62
|
+
export declare function spreadTint(coverage: number, colourSum: GlassTexel, colourCount: number, out: GlassTexel): GlassTexel;
|
|
63
|
+
/**
|
|
64
|
+
* A coarse level of the tint, with the open ground's white taken back out: returns the pane's share
|
|
65
|
+
* of the texel and writes the pane's own colour to `out`.
|
|
66
|
+
*
|
|
67
|
+
* **Why a level needs this**: it averages a pane with whatever lies beside it, and beside a pane is
|
|
68
|
+
* usually open ground, which the tint holds as white — so a frosted patch read coarse is paler than
|
|
69
|
+
* the pane, and measured 6% more light than the clear pane over the same floor. The clarity channel
|
|
70
|
+
* says how much of the texel was pane: open ground holds 1, the pane its own `centreClarity`, so
|
|
71
|
+
* the pane's share is `(1 − a) / (1 − centreClarity)` and its colour follows by subtraction. What it
|
|
72
|
+
* assumes is that the frost around a receiver is the frost at its centre, which is true within a
|
|
73
|
+
* pane and blends where two panes of different frost meet; a clear pane (`centreClarity` 1) is
|
|
74
|
+
* never read coarse, so it is returned as it stands.
|
|
75
|
+
*/
|
|
76
|
+
export declare function unmixTint(mip: GlassTexel, centreClarity: number, out: GlassTexel): number;
|
|
77
|
+
/** The filter radius for a receiver `paneToReceiver` behind a pane of this clarity. */
|
|
78
|
+
export declare function frostRadius(clarity: number, paneToReceiver: number, baseRadius: number): number;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coloured light through glass: how one pane filters light, how panes combine, which receivers a
|
|
3
|
+
* pane tints, and how far frost spreads the colour — the reference the shaders state term for term.
|
|
4
|
+
*
|
|
5
|
+
* **Frost spreads light, it does not remove it.** Etched glass passes 88–91% of visible light
|
|
6
|
+
* against clear float glass's ~90%, so a frosted pane passes `transmission × (1 − F) × tint` like a
|
|
7
|
+
* clear one and only the filter widens. What it gives up: the spread stays inside the opaque frame's
|
|
8
|
+
* shadow, so light from a frosted pane does not reach past the outline of the frame around it. What
|
|
9
|
+
* would make it wrong is glass that genuinely absorbs as it diffuses — opal glass, milk glass — for
|
|
10
|
+
* which a lower `transmission` is the honest statement.
|
|
11
|
+
*
|
|
12
|
+
* **What else it does not reach**: light that bounces. DriftRay's probe bake and DriftLight's summed
|
|
13
|
+
* far field see a pane as absent, so the light a tinted window sends round a room by bouncing is its
|
|
14
|
+
* sun's own colour; only the direct light through the pane takes the tint.
|
|
15
|
+
*/
|
|
16
|
+
import { schlickFresnel } from './glass.js';
|
|
17
|
+
/** No glass: everything passes, perfectly clear. What a tint map is cleared to. */
|
|
18
|
+
export const CLEAR_TEXEL = { r: 1, g: 1, b: 1, clarity: 1 };
|
|
19
|
+
/** How widely a fully frosted pane spreads its colour: a 30° half-angle cone behind it. */
|
|
20
|
+
export const FROST_SPREAD = Math.tan(Math.PI / 6);
|
|
21
|
+
/**
|
|
22
|
+
* The spread never exceeds this many base filter radii, and the tap count never changes.
|
|
23
|
+
*
|
|
24
|
+
* **Sixty-four, because the tint is read from the mip level the spread asks for**: each tap is then
|
|
25
|
+
* already an average over its own share of the spread, so taps far apart do not alias into grain.
|
|
26
|
+
* It was eight before the tint had mips, and on a sun map a few centimetres a texel that capped a
|
|
27
|
+
* frosted pane's spread at seven centimetres — frost that nobody saw. What the cap still bounds is
|
|
28
|
+
* a pane so frosted and so far above a floor that its colour would wash over a room.
|
|
29
|
+
*/
|
|
30
|
+
export const FROST_RADIUS_CAP = 64;
|
|
31
|
+
/** One pane as a tint texel, lit at `cosLight` to its normal. Fresnel as `glass.ts` states it. */
|
|
32
|
+
export function paneTexel(glass, cosLight, out) {
|
|
33
|
+
const passes = glass.transmission * (1 - schlickFresnel(cosLight));
|
|
34
|
+
out.r = passes * glass.tint[0];
|
|
35
|
+
out.g = passes * glass.tint[1];
|
|
36
|
+
out.b = passes * glass.tint[2];
|
|
37
|
+
out.clarity = 1 - glass.frost;
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** Two stacks of glass on one ray: a product, so the order they are drawn in cannot matter. */
|
|
41
|
+
export function combinePanes(a, b, out) {
|
|
42
|
+
out.r = a.r * b.r;
|
|
43
|
+
out.g = a.g * b.g;
|
|
44
|
+
out.b = a.b * b.b;
|
|
45
|
+
out.clarity = a.clarity * b.clarity;
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* What one filter tap contributes: the glass's texel where the receiver is behind the pane, and
|
|
50
|
+
* nothing where it is on the light's side of it — or is the pane, which the bias keeps untinted.
|
|
51
|
+
*/
|
|
52
|
+
export function tapTint(receiverDepth, glassDepth, bias, glass, out) {
|
|
53
|
+
const behind = receiverDepth > glassDepth + bias;
|
|
54
|
+
out.r = behind ? glass.r : 1;
|
|
55
|
+
out.g = behind ? glass.g : 1;
|
|
56
|
+
out.b = behind ? glass.b : 1;
|
|
57
|
+
out.clarity = behind ? glass.clarity : 1;
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A frosted pane's tint at a receiver: the outline from the taps at the base radius, the colour
|
|
62
|
+
* from the spread taps that found glass — nothing else.
|
|
63
|
+
*
|
|
64
|
+
* **Split because a tint cannot carry light out past a pane.** Blurring the tint map whole pulls in
|
|
65
|
+
* the white of the unobstructed ground around a pane, which brightens the patch — measured at 10%
|
|
66
|
+
* more light over a frosted window than a clear one — while the pane's own light, which should
|
|
67
|
+
* spread onto that ground, has no way to exceed full sun there. So the outline stays where the
|
|
68
|
+
* clear pane's is (`coverage`, the share of outline taps behind glass) and only the colour spreads,
|
|
69
|
+
* averaged over glass alone (`colourSum` over `colourCount`, the summed pane shares `unmixTint`
|
|
70
|
+
* reports — continuous, so a colour crossing between panes blends rather than stepping): neighbouring
|
|
71
|
+
* panes mix, a pattern blurs, and the light through the patch is what it was. What it gives up is
|
|
72
|
+
* spread past the outline, which the spec states; with no glass found by the spread the colour is
|
|
73
|
+
* clear.
|
|
74
|
+
*/
|
|
75
|
+
export function spreadTint(coverage, colourSum, colourCount, out) {
|
|
76
|
+
const r = colourCount > 0 ? colourSum.r / colourCount : 1;
|
|
77
|
+
const g = colourCount > 0 ? colourSum.g / colourCount : 1;
|
|
78
|
+
const b = colourCount > 0 ? colourSum.b / colourCount : 1;
|
|
79
|
+
out.r = 1 + (r - 1) * coverage;
|
|
80
|
+
out.g = 1 + (g - 1) * coverage;
|
|
81
|
+
out.b = 1 + (b - 1) * coverage;
|
|
82
|
+
out.clarity = 1;
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A coarse level of the tint, with the open ground's white taken back out: returns the pane's share
|
|
87
|
+
* of the texel and writes the pane's own colour to `out`.
|
|
88
|
+
*
|
|
89
|
+
* **Why a level needs this**: it averages a pane with whatever lies beside it, and beside a pane is
|
|
90
|
+
* usually open ground, which the tint holds as white — so a frosted patch read coarse is paler than
|
|
91
|
+
* the pane, and measured 6% more light than the clear pane over the same floor. The clarity channel
|
|
92
|
+
* says how much of the texel was pane: open ground holds 1, the pane its own `centreClarity`, so
|
|
93
|
+
* the pane's share is `(1 − a) / (1 − centreClarity)` and its colour follows by subtraction. What it
|
|
94
|
+
* assumes is that the frost around a receiver is the frost at its centre, which is true within a
|
|
95
|
+
* pane and blends where two panes of different frost meet; a clear pane (`centreClarity` 1) is
|
|
96
|
+
* never read coarse, so it is returned as it stands.
|
|
97
|
+
*/
|
|
98
|
+
export function unmixTint(mip, centreClarity, out) {
|
|
99
|
+
if (centreClarity >= 1) {
|
|
100
|
+
out.r = mip.r;
|
|
101
|
+
out.g = mip.g;
|
|
102
|
+
out.b = mip.b;
|
|
103
|
+
out.clarity = mip.clarity;
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
const share = Math.min(1, Math.max(0, (1 - mip.clarity) / (1 - centreClarity)));
|
|
107
|
+
if (share <= 0) {
|
|
108
|
+
out.r = 1;
|
|
109
|
+
out.g = 1;
|
|
110
|
+
out.b = 1;
|
|
111
|
+
out.clarity = 1;
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
const ground = 1 - share;
|
|
115
|
+
out.r = Math.min(1, Math.max(0, (mip.r - ground) / share));
|
|
116
|
+
out.g = Math.min(1, Math.max(0, (mip.g - ground) / share));
|
|
117
|
+
out.b = Math.min(1, Math.max(0, (mip.b - ground) / share));
|
|
118
|
+
out.clarity = centreClarity;
|
|
119
|
+
return share;
|
|
120
|
+
}
|
|
121
|
+
/** The filter radius for a receiver `paneToReceiver` behind a pane of this clarity. */
|
|
122
|
+
export function frostRadius(clarity, paneToReceiver, baseRadius) {
|
|
123
|
+
const spread = (1 - clarity) * FROST_SPREAD * Math.max(paneToReceiver, 0);
|
|
124
|
+
return Math.min(Math.max(baseRadius, spread), baseRadius * FROST_RADIUS_CAP);
|
|
125
|
+
}
|
|
@@ -11,9 +11,8 @@ export interface MediumLight {
|
|
|
11
11
|
readonly sunShadow: number;
|
|
12
12
|
/** World → light clip, **uncorrected**: the shader does its own `* 0.5 + 0.5`. */
|
|
13
13
|
readonly lightViewProj: ReadonlyMat4;
|
|
14
|
-
|
|
15
|
-
readonly
|
|
16
|
-
readonly dynamicShadowMap: WebGLTexture;
|
|
14
|
+
/** The sun's static, moving and peeled maps, as one array. See `shadowMap.ts`. */
|
|
15
|
+
readonly sunShadows: WebGLTexture;
|
|
17
16
|
readonly peeledEnabled: boolean;
|
|
18
17
|
}
|
|
19
18
|
/**
|
|
@@ -158,14 +158,8 @@ export class GlobalMediumPass {
|
|
|
158
158
|
gl.bindTexture(gl.TEXTURE_2D, depth);
|
|
159
159
|
gl.uniform1i(u['uDepth'] ?? null, 0);
|
|
160
160
|
gl.activeTexture(gl.TEXTURE1);
|
|
161
|
-
gl.bindTexture(gl.
|
|
162
|
-
gl.uniform1i(u['
|
|
163
|
-
gl.activeTexture(gl.TEXTURE2);
|
|
164
|
-
gl.bindTexture(gl.TEXTURE_2D, light.peeledShadowMap);
|
|
165
|
-
gl.uniform1i(u['uPeeledShadowMap'] ?? null, 2);
|
|
166
|
-
gl.activeTexture(gl.TEXTURE3);
|
|
167
|
-
gl.bindTexture(gl.TEXTURE_2D, light.dynamicShadowMap);
|
|
168
|
-
gl.uniform1i(u['uDynamicShadowMap'] ?? null, 3);
|
|
161
|
+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, light.sunShadows);
|
|
162
|
+
gl.uniform1i(u['uSunShadows'] ?? null, 1);
|
|
169
163
|
gl.uniformMatrix4fv(u['uDepthToWorld'] ?? null, false, this.depthToWorld);
|
|
170
164
|
gl.uniform3f(u['uCameraPos'] ?? null, eye[0] ?? 0, eye[1] ?? 0, eye[2] ?? 0);
|
|
171
165
|
gl.uniform3f(u['uSunDir'] ?? null, light.sunDir[0] ?? 0, light.sunDir[1] ?? 1, light.sunDir[2] ?? 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** What the second pipeline's shading pass computes, in TypeScript, so something can disagree. */
|
|
2
|
+
import { type ResolvedGlass } from '../glass.ts';
|
|
2
3
|
/**
|
|
3
4
|
* **The lit expression had no reference until 2026-09-16, and that was a gap rather than a policy.**
|
|
4
5
|
*
|
|
@@ -163,3 +164,14 @@ export declare function newLitColour(): Float32Array;
|
|
|
163
164
|
* so the two orders had never been asked to differ.
|
|
164
165
|
*/
|
|
165
166
|
export declare function litColour(surface: LitSurface, environment: LitEnvironment, out: Float32Array): Float32Array;
|
|
167
|
+
/**
|
|
168
|
+
* Glass over its own shading: what is behind it shown by how much it lets through and how little it
|
|
169
|
+
* reflects at this angle, and the light behind it glowing through by how frosted it is — the forward
|
|
170
|
+
* path's glass branch (`flat/main.ts`) and `glass.ts`'s arithmetic, for the blended raster's twin.
|
|
171
|
+
*
|
|
172
|
+
* **`cosView` is taken unsigned**, because a pane passes the same light seen from either side.
|
|
173
|
+
* `sunGlow` is the light arriving at the pane's far side from the eye, which frost scatters toward
|
|
174
|
+
* it; a clear pane shows that light's source in `seen` instead. Allocates nothing: `out` is the
|
|
175
|
+
* caller's, and may be `own`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function glassShade(own: readonly [number, number, number], seen: readonly [number, number, number], glass: ResolvedGlass, cosView: number, sunGlow: readonly [number, number, number], out: [number, number, number]): [number, number, number];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** What the second pipeline's shading pass computes, in TypeScript, so something can disagree. */
|
|
2
2
|
import { EMISSIVE_SHADOW_SHARE, MIN_LOBE_ALPHA } from '../shaders/flat/lobes.js';
|
|
3
3
|
import { environmentWeight } from './ibl.js';
|
|
4
|
+
import { schlickFresnel } from '../glass.js';
|
|
4
5
|
/**
|
|
5
6
|
* How much of the sky a normal sees, against how much of the ground.
|
|
6
7
|
*
|
|
@@ -163,3 +164,25 @@ export function litColour(surface, environment, out) {
|
|
|
163
164
|
}
|
|
164
165
|
return out;
|
|
165
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Glass over its own shading: what is behind it shown by how much it lets through and how little it
|
|
169
|
+
* reflects at this angle, and the light behind it glowing through by how frosted it is — the forward
|
|
170
|
+
* path's glass branch (`flat/main.ts`) and `glass.ts`'s arithmetic, for the blended raster's twin.
|
|
171
|
+
*
|
|
172
|
+
* **`cosView` is taken unsigned**, because a pane passes the same light seen from either side.
|
|
173
|
+
* `sunGlow` is the light arriving at the pane's far side from the eye, which frost scatters toward
|
|
174
|
+
* it; a clear pane shows that light's source in `seen` instead. Allocates nothing: `out` is the
|
|
175
|
+
* caller's, and may be `own`.
|
|
176
|
+
*/
|
|
177
|
+
export function glassShade(own, seen, glass, cosView, sunGlow, out) {
|
|
178
|
+
const t = glass.transmission;
|
|
179
|
+
const shown = t * (1 - schlickFresnel(Math.abs(cosView)));
|
|
180
|
+
const glowing = glass.frost * t;
|
|
181
|
+
for (let c = 0; c < 3; c++) {
|
|
182
|
+
const tint = glass.tint[c];
|
|
183
|
+
const mine = own[c];
|
|
184
|
+
out[c] =
|
|
185
|
+
mine + (seen[c] * tint - mine) * shown + sunGlow[c] * tint * glowing;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** A GPU-driven material as the shading pass reads it:
|
|
1
|
+
/** A GPU-driven material as the shading pass reads it: seven blocks, one of them integers. */
|
|
2
2
|
import type { GpuDrivenMaterial } from '../backend/webgpu/gpuDrivenPass.ts';
|
|
3
3
|
import type { GpuDrivenProgram } from './decodeTables.ts';
|
|
4
4
|
/**
|
|
@@ -30,17 +30,18 @@ export interface GpuDrivenTextures {
|
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Words a material entry: tint and emissive, the surface scalars, four program indices, the UV
|
|
33
|
-
* scale and two strengths, the two ORM scales with the cutout and blend flags,
|
|
34
|
-
* the
|
|
33
|
+
* scale and two strengths, the two ORM scales with the cutout and blend flags, the opacity with the
|
|
34
|
+
* glass's transmission and frost and one spare, and the glass's tint with one spare.
|
|
35
35
|
*
|
|
36
36
|
* **It was eight until 2026-09-17**, and metalness took its last spare lane the same day, so the
|
|
37
37
|
* programs and the scales needed three more blocks rather than squeezing into what was left. It
|
|
38
38
|
* became twenty-four on 2026-09-18, when transparency arrived and there was nowhere left to put an
|
|
39
39
|
* opacity: the cutout took lane 18 and the blend flag took 19, and lane 11 is a reserved program
|
|
40
40
|
* slot rather than a gap. A sixteen-byte block is 1 kB across the whole table, against the 64 kB a
|
|
41
|
-
* uniform buffer may hold.
|
|
41
|
+
* uniform buffer may hold. **Twenty-eight on 2026-09-29**, for glass: its transmission and frost
|
|
42
|
+
* took two of the opacity block's spares and its tint needed a block of its own.
|
|
42
43
|
*/
|
|
43
|
-
export declare const GPU_DRIVEN_MATERIAL_FLOATS =
|
|
44
|
+
export declare const GPU_DRIVEN_MATERIAL_FLOATS = 28;
|
|
44
45
|
/**
|
|
45
46
|
* Below this base-colour alpha the raster discards a fragment. Zero means no test.
|
|
46
47
|
*
|
|
@@ -66,6 +67,15 @@ export declare const MATERIAL_BLEND = 19;
|
|
|
66
67
|
* all. A material that does not blend never reads this.
|
|
67
68
|
*/
|
|
68
69
|
export declare const MATERIAL_OPACITY = 20;
|
|
70
|
+
/**
|
|
71
|
+
* Glass (`glass.ts`): how much light passes, and how milky it is. Zero transmission is not glass,
|
|
72
|
+
* and a material that is glass is drawn in the blended half whatever `blend` says — a visibility
|
|
73
|
+
* buffer holds one surface a pixel, and glass is two.
|
|
74
|
+
*/
|
|
75
|
+
export declare const MATERIAL_GLASS_TRANSMISSION = 21;
|
|
76
|
+
export declare const MATERIAL_GLASS_FROST = 22;
|
|
77
|
+
/** The colour light takes through the glass: three lanes, white where the material is not glass. */
|
|
78
|
+
export declare const MATERIAL_GLASS_TINT = 24;
|
|
69
79
|
/**
|
|
70
80
|
* Where a material's emissive program is: the fourth program lane, which the table reserved and
|
|
71
81
|
* initialised to none before anything used it.
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
/** A GPU-driven material as the shading pass reads it:
|
|
1
|
+
/** A GPU-driven material as the shading pass reads it: seven blocks, one of them integers. */
|
|
2
|
+
import { resolveGlass } from '../glass.js';
|
|
2
3
|
import { DECODE_NO_PROGRAM } from '../shaders/gpudriven/decode.wgsl.js';
|
|
3
4
|
/**
|
|
4
5
|
* Words a material entry: tint and emissive, the surface scalars, four program indices, the UV
|
|
5
|
-
* scale and two strengths, the two ORM scales with the cutout and blend flags,
|
|
6
|
-
* the
|
|
6
|
+
* scale and two strengths, the two ORM scales with the cutout and blend flags, the opacity with the
|
|
7
|
+
* glass's transmission and frost and one spare, and the glass's tint with one spare.
|
|
7
8
|
*
|
|
8
9
|
* **It was eight until 2026-09-17**, and metalness took its last spare lane the same day, so the
|
|
9
10
|
* programs and the scales needed three more blocks rather than squeezing into what was left. It
|
|
10
11
|
* became twenty-four on 2026-09-18, when transparency arrived and there was nowhere left to put an
|
|
11
12
|
* opacity: the cutout took lane 18 and the blend flag took 19, and lane 11 is a reserved program
|
|
12
13
|
* slot rather than a gap. A sixteen-byte block is 1 kB across the whole table, against the 64 kB a
|
|
13
|
-
* uniform buffer may hold.
|
|
14
|
+
* uniform buffer may hold. **Twenty-eight on 2026-09-29**, for glass: its transmission and frost
|
|
15
|
+
* took two of the opacity block's spares and its tint needed a block of its own.
|
|
14
16
|
*/
|
|
15
|
-
export const GPU_DRIVEN_MATERIAL_FLOATS =
|
|
17
|
+
export const GPU_DRIVEN_MATERIAL_FLOATS = 28;
|
|
16
18
|
/**
|
|
17
19
|
* Below this base-colour alpha the raster discards a fragment. Zero means no test.
|
|
18
20
|
*
|
|
@@ -38,6 +40,15 @@ export const MATERIAL_BLEND = 19;
|
|
|
38
40
|
* all. A material that does not blend never reads this.
|
|
39
41
|
*/
|
|
40
42
|
export const MATERIAL_OPACITY = 20;
|
|
43
|
+
/**
|
|
44
|
+
* Glass (`glass.ts`): how much light passes, and how milky it is. Zero transmission is not glass,
|
|
45
|
+
* and a material that is glass is drawn in the blended half whatever `blend` says — a visibility
|
|
46
|
+
* buffer holds one surface a pixel, and glass is two.
|
|
47
|
+
*/
|
|
48
|
+
export const MATERIAL_GLASS_TRANSMISSION = 21;
|
|
49
|
+
export const MATERIAL_GLASS_FROST = 22;
|
|
50
|
+
/** The colour light takes through the glass: three lanes, white where the material is not glass. */
|
|
51
|
+
export const MATERIAL_GLASS_TINT = 24;
|
|
41
52
|
/**
|
|
42
53
|
* Where a material's emissive program is: the fourth program lane, which the table reserved and
|
|
43
54
|
* initialised to none before anything used it.
|
|
@@ -106,10 +117,19 @@ export function writeMaterialTable(materials, indices, slots) {
|
|
|
106
117
|
float(m, 17, textures?.metallicScale ?? 1);
|
|
107
118
|
/* Zero is off, so a material that says nothing about cutout writes the table it wrote before. */
|
|
108
119
|
float(m, MATERIAL_ALPHA_CUTOFF, material.alphaCutoff ?? 0);
|
|
120
|
+
/* Glass A's clamps and its test of what is glass at all, so both pipelines agree on it. */
|
|
121
|
+
const glass = resolveGlass(material.glass, glassScratch);
|
|
109
122
|
/* Zero is opaque, so a material that says nothing about blending stays in the opaque half. */
|
|
110
|
-
float(m, MATERIAL_BLEND, material.blend === true ? 1 : 0);
|
|
123
|
+
float(m, MATERIAL_BLEND, material.blend === true || glass ? 1 : 0);
|
|
111
124
|
/* One, so a material that asked to blend and said nothing else is as solid as an opaque one. */
|
|
112
125
|
float(m, MATERIAL_OPACITY, material.opacity ?? 1);
|
|
126
|
+
float(m, MATERIAL_GLASS_TRANSMISSION, glassScratch.transmission);
|
|
127
|
+
float(m, MATERIAL_GLASS_FROST, glassScratch.frost);
|
|
128
|
+
float(m, MATERIAL_GLASS_TINT, glassScratch.tint[0]);
|
|
129
|
+
float(m, MATERIAL_GLASS_TINT + 1, glassScratch.tint[1]);
|
|
130
|
+
float(m, MATERIAL_GLASS_TINT + 2, glassScratch.tint[2]);
|
|
113
131
|
});
|
|
114
132
|
return buffer;
|
|
115
133
|
}
|
|
134
|
+
/** One resolution every material's glass is read through. */
|
|
135
|
+
const glassScratch = { transmission: 0, frost: 0, tint: [1, 1, 1] };
|
|
@@ -83,7 +83,7 @@ export declare const GPU_DRIVEN_RESOURCES: GpuDrivenResources;
|
|
|
83
83
|
* What each stage is called, in the order they are recorded — one render or compute pass each, or
|
|
84
84
|
* one copy between them.
|
|
85
85
|
*/
|
|
86
|
-
export declare const GPU_DRIVEN_PASSES: readonly ['clearColour', 'shadow', 'instanceCull', 'cut', 'phaseOneDraw', 'pyramid', 'phaseTwoCull', 'phaseTwoDraw', 'blendCull', '
|
|
86
|
+
export declare const GPU_DRIVEN_PASSES: readonly ['clearColour', 'shadow', 'instanceCull', 'cut', 'phaseOneDraw', 'pyramid', 'phaseTwoCull', 'phaseTwoDraw', 'blendCull', 'visibilityCopy', 'bin', 'cursorCopy', 'shade', 'blendDraw', 'blendResolve'];
|
|
87
87
|
export type GpuDrivenPassName = (typeof GPU_DRIVEN_PASSES)[number];
|
|
88
88
|
/**
|
|
89
89
|
* **Every stage is ordered, so none merges with a neighbour.** Two adjacent compute stages could
|
|
@@ -82,11 +82,11 @@ export const GPU_DRIVEN_PASSES = [
|
|
|
82
82
|
'phaseTwoCull',
|
|
83
83
|
'phaseTwoDraw',
|
|
84
84
|
'blendCull',
|
|
85
|
-
'blendDraw',
|
|
86
85
|
'visibilityCopy',
|
|
87
86
|
'bin',
|
|
88
87
|
'cursorCopy',
|
|
89
88
|
'shade',
|
|
89
|
+
'blendDraw',
|
|
90
90
|
'blendResolve',
|
|
91
91
|
];
|
|
92
92
|
/**
|
|
@@ -148,10 +148,11 @@ function edgesFor(res) {
|
|
|
148
148
|
/*
|
|
149
149
|
* **It reads the depth the opaque half wrote and does not write it.** A pane behind a wall is
|
|
150
150
|
* rejected at the wall; nothing here writes depth, so two panes do not hide each other and
|
|
151
|
-
* there is something left to blend.
|
|
151
|
+
* there is something left to blend. **And it reads the shaded colour**, because glass shows the
|
|
152
|
+
* opaque picture behind it — which is why it is recorded after `shade` rather than before.
|
|
152
153
|
*/
|
|
153
154
|
blendDraw: [
|
|
154
|
-
[res.blendList, res.clusters, res.depth],
|
|
155
|
+
[res.blendList, res.clusters, res.depth, res.colour],
|
|
155
156
|
[res.oitAccum, res.oitReveal],
|
|
156
157
|
],
|
|
157
158
|
visibilityCopy: [[res.visibility], [res.visibilityCopy]],
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The second pipeline's sunlight through glass, as a reference: `glassTintAt` over the glass depth
|
|
3
|
+
* and tint maps the GPU-driven pass draws from the sun, for `shade.wgsl.ts`'s lookup to be read
|
|
4
|
+
* against.
|
|
5
|
+
*
|
|
6
|
+
* **The forward path's rule, not a second one** (`glassShadow.ts`, and `sunGlassLookup` in
|
|
7
|
+
* `flat/directionalShadow.ts`): the outline from taps at the base filter radius that count a pane
|
|
8
|
+
* only where the receiver is behind it, and the colour from spread taps read coarse, unmixed from
|
|
9
|
+
* the ground around the pane by its clarity and weighed by its share. Frost widens only the
|
|
10
|
+
* colour's taps, so the light a frosted pane passes is the light a clear one does.
|
|
11
|
+
*
|
|
12
|
+
* **What differs is where two numbers come from.** A compute invocation has no derivatives, so the
|
|
13
|
+
* map's scale in metres is the caller's (`uvPerMetre`, which an orthographic light matrix states
|
|
14
|
+
* outright); and a coarse level here is a box average over the spread's footprint, which is what a
|
|
15
|
+
* mip level approximates on the device. `scripts/gpu-parity.mjs` holds the device's per-tap
|
|
16
|
+
* arithmetic to `glassShadow.ts`; the sampling is what the glass page measures.
|
|
17
|
+
*/
|
|
18
|
+
import { type GlassTexel } from '../glassShadow.ts';
|
|
19
|
+
/** The two maps the sun's glass pass draws, square, row-major from v = 0. */
|
|
20
|
+
export interface SunGlassMaps {
|
|
21
|
+
readonly size: number;
|
|
22
|
+
/** The nearest pane's depth a texel, 1 where no pane was drawn. */
|
|
23
|
+
readonly glassDepth: Float32Array;
|
|
24
|
+
/** What the panes on a texel's ray let through, and their clarity: four floats a texel. */
|
|
25
|
+
readonly tint: Float32Array;
|
|
26
|
+
}
|
|
27
|
+
export interface SunGlassSettings {
|
|
28
|
+
/** Metres the light's depth range spans, which turns a depth difference into a distance. */
|
|
29
|
+
readonly depthSpan: number;
|
|
30
|
+
/** Map units a metre across the light, which turns a spread in metres into one on the map. */
|
|
31
|
+
readonly uvPerMetre: number;
|
|
32
|
+
readonly taps: number;
|
|
33
|
+
}
|
|
34
|
+
/** What the sun keeps through glass at a receiver at map position (u, v) and light depth `depth`. */
|
|
35
|
+
export declare function glassTintAt(u: number, v: number, depth: number, maps: SunGlassMaps, settings: SunGlassSettings, out: GlassTexel): GlassTexel;
|