@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
|
@@ -26,6 +26,16 @@ export interface VertexAttribute {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare const VERTEX_LAYOUT: readonly VertexAttribute[];
|
|
28
28
|
/** Geometry on the device, with the buffers bound in layout order. */
|
|
29
|
+
/**
|
|
30
|
+
* The texture coordinates of a mesh that names texture-array layers: (u, v, layer), three floats.
|
|
31
|
+
*
|
|
32
|
+
* **Three only where layers exist.** Every location is spent, so the layer rides in this attribute,
|
|
33
|
+
* and widening it for every textured mesh would add four bytes to each of its vertices for nothing.
|
|
34
|
+
* A mesh without layers keeps two, and the shader's `vec3` input reads z as 0 — WebGPU fills a
|
|
35
|
+
* component the format does not carry with 0 (and w with 1) — which is layer 0. The pipeline key
|
|
36
|
+
* carries `:layers`, so the two vertex layouts never share a pipeline.
|
|
37
|
+
*/
|
|
38
|
+
export declare const LAYERED_UVS: VertexAttribute;
|
|
29
39
|
export interface GpuMesh {
|
|
30
40
|
/**
|
|
31
41
|
* The buffers a draw binds, in the order `vertexBufferLayouts` describes them.
|
|
@@ -48,6 +58,15 @@ export interface GpuMesh {
|
|
|
48
58
|
* its own does.
|
|
49
59
|
*/
|
|
50
60
|
readonly vertexStride: number;
|
|
61
|
+
/**
|
|
62
|
+
* Byte offsets of the joint indices and weights in the interleaved vertex, or null for a mesh
|
|
63
|
+
* that supplied neither. For a pass that skins through a shader of its own — the motion pass —
|
|
64
|
+
* which has to find them without the `present` map the generated pipelines are keyed by.
|
|
65
|
+
*/
|
|
66
|
+
readonly skinOffsets: {
|
|
67
|
+
readonly joints: number;
|
|
68
|
+
readonly weights: number;
|
|
69
|
+
} | null;
|
|
51
70
|
readonly indexBuffer: GPUBuffer;
|
|
52
71
|
readonly indexCount: number;
|
|
53
72
|
/**
|
|
@@ -114,7 +133,16 @@ export interface GpuMesh {
|
|
|
114
133
|
* one CPU-side copy of the vertex data per dynamic mesh, which is why the flag exists rather
|
|
115
134
|
* than every mesh paying it.
|
|
116
135
|
*/
|
|
117
|
-
readonly update: ((device: GPUDevice, positions: Float32Array, normals?: Float32Array) => void) | null;
|
|
136
|
+
readonly update: ((device: GPUDevice, positions: Float32Array, normals?: Float32Array, previous?: GPUBuffer | null) => void) | null;
|
|
137
|
+
/**
|
|
138
|
+
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's interleaved
|
|
139
|
+
* rows, made the first time a reconstructing renderer rewrites the mesh, and the frame of the
|
|
140
|
+
* last rewrite. Null on a mesh created without `{ dynamic: true }`, which never moves a vertex.
|
|
141
|
+
*/
|
|
142
|
+
readonly motion: {
|
|
143
|
+
previous: GPUBuffer | null;
|
|
144
|
+
changed: number;
|
|
145
|
+
} | null;
|
|
118
146
|
dispose(): void;
|
|
119
147
|
}
|
|
120
148
|
/** A mesh on its way to the device, and the iterator that gets it there. */
|
|
@@ -84,6 +84,27 @@ export const VERTEX_LAYOUT = [
|
|
|
84
84
|
*/
|
|
85
85
|
{ name: 'channel', shaderLocation: 13, format: 'float32x4', components: 4, optional: true },
|
|
86
86
|
];
|
|
87
|
+
/** Geometry on the device, with the buffers bound in layout order. */
|
|
88
|
+
/**
|
|
89
|
+
* The texture coordinates of a mesh that names texture-array layers: (u, v, layer), three floats.
|
|
90
|
+
*
|
|
91
|
+
* **Three only where layers exist.** Every location is spent, so the layer rides in this attribute,
|
|
92
|
+
* and widening it for every textured mesh would add four bytes to each of its vertices for nothing.
|
|
93
|
+
* A mesh without layers keeps two, and the shader's `vec3` input reads z as 0 — WebGPU fills a
|
|
94
|
+
* component the format does not carry with 0 (and w with 1) — which is layer 0. The pipeline key
|
|
95
|
+
* carries `:layers`, so the two vertex layouts never share a pipeline.
|
|
96
|
+
*/
|
|
97
|
+
export const LAYERED_UVS = {
|
|
98
|
+
name: 'uvs',
|
|
99
|
+
shaderLocation: 5,
|
|
100
|
+
format: 'float32x3',
|
|
101
|
+
components: 3,
|
|
102
|
+
optional: true,
|
|
103
|
+
};
|
|
104
|
+
/** The attribute as this mesh lays it out: the UV field widens where the mesh names layers. */
|
|
105
|
+
function laidOut(attribute, layered) {
|
|
106
|
+
return layered && attribute.name === 'uvs' ? LAYERED_UVS : attribute;
|
|
107
|
+
}
|
|
87
108
|
/**
|
|
88
109
|
* Upload a mesh, all of it, now.
|
|
89
110
|
*
|
|
@@ -130,7 +151,8 @@ export function createGpuMeshIncremental(device, data, dynamic = false) {
|
|
|
130
151
|
validateMeshData(data);
|
|
131
152
|
const bounds = boundsOfPositions(data.positions, createBounds());
|
|
132
153
|
const vertexCount = data.positions.length / 3;
|
|
133
|
-
const
|
|
154
|
+
const layered = data.layers !== undefined;
|
|
155
|
+
const supplied = VERTEX_LAYOUT.filter((attribute) => !attribute.optional || data[attribute.name] !== undefined).map((attribute) => laidOut(attribute, layered));
|
|
134
156
|
/* Interleaved: one stride holding every attribute the mesh actually supplied. */
|
|
135
157
|
const stride = supplied.reduce((sum, attribute) => sum + attribute.components * 4, 0);
|
|
136
158
|
const step = stride / 4;
|
|
@@ -235,6 +257,7 @@ export function createGpuMeshIncremental(device, data, dynamic = false) {
|
|
|
235
257
|
progress,
|
|
236
258
|
hasTangents: data.tangents !== undefined,
|
|
237
259
|
isSkinned: data.joints !== undefined,
|
|
260
|
+
skinOffsets: skinOffsetsOf(supplied),
|
|
238
261
|
hasChannel: data.channel !== undefined,
|
|
239
262
|
morph: data.morphTargets === undefined || data.morphTargetCount === undefined
|
|
240
263
|
? null
|
|
@@ -270,7 +293,14 @@ function* uploadSteps(job) {
|
|
|
270
293
|
let fieldOffset = 0;
|
|
271
294
|
for (const attribute of supplied) {
|
|
272
295
|
const source = data[attribute.name];
|
|
273
|
-
|
|
296
|
+
if (attribute === LAYERED_UVS) {
|
|
297
|
+
/* (u, v) from the coordinates and the layer after them, one field of three. */
|
|
298
|
+
interleaveField(interleaved, source, 2, step, fieldOffset, from, to);
|
|
299
|
+
interleaveField(interleaved, data.layers, 1, step, fieldOffset + 2, from, to);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
interleaveField(interleaved, source, attribute.components, step, fieldOffset, from, to);
|
|
303
|
+
}
|
|
274
304
|
fieldOffset += attribute.components;
|
|
275
305
|
}
|
|
276
306
|
device.queue.writeBuffer(vertices, from * stride, interleaved, from * step, (to - from) * step);
|
|
@@ -329,12 +359,31 @@ function interleaveField(rows, source, width, step, fieldOffset, from, to) {
|
|
|
329
359
|
rows[write] = source[read];
|
|
330
360
|
}
|
|
331
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Where the joints and weights sit in a vertex of `supplied`, the attributes a mesh interleaves in
|
|
364
|
+
* layout order; null unless it supplied both.
|
|
365
|
+
*/
|
|
366
|
+
function skinOffsetsOf(supplied) {
|
|
367
|
+
let floats = 0;
|
|
368
|
+
let joints = -1;
|
|
369
|
+
let weights = -1;
|
|
370
|
+
for (const attribute of supplied) {
|
|
371
|
+
if (attribute.name === 'joints')
|
|
372
|
+
joints = floats * 4;
|
|
373
|
+
if (attribute.name === 'weights')
|
|
374
|
+
weights = floats * 4;
|
|
375
|
+
floats += attribute.components;
|
|
376
|
+
}
|
|
377
|
+
return joints >= 0 && weights >= 0 ? { joints, weights } : null;
|
|
378
|
+
}
|
|
332
379
|
/** The handle, made where it can see only what it hands out. */
|
|
333
380
|
function gpuMeshOf(parts) {
|
|
381
|
+
const motion = parts.update === null ? null : { previous: null, changed: -1 };
|
|
334
382
|
const { vertices, constants, indexBuffer, progress } = parts;
|
|
335
383
|
return {
|
|
336
384
|
vertexBuffers: [vertices, constants],
|
|
337
385
|
vertexStride: parts.stride,
|
|
386
|
+
skinOffsets: parts.skinOffsets,
|
|
338
387
|
indexBuffer,
|
|
339
388
|
indexCount: parts.indexCount,
|
|
340
389
|
bounds: parts.bounds,
|
|
@@ -346,7 +395,9 @@ function gpuMeshOf(parts) {
|
|
|
346
395
|
hasChannel: parts.hasChannel,
|
|
347
396
|
morph: parts.morph,
|
|
348
397
|
update: parts.update,
|
|
398
|
+
motion,
|
|
349
399
|
dispose() {
|
|
400
|
+
motion?.previous?.destroy();
|
|
350
401
|
vertices.destroy();
|
|
351
402
|
constants.destroy();
|
|
352
403
|
indexBuffer.destroy();
|
|
@@ -359,12 +410,16 @@ function gpuMeshOf(parts) {
|
|
|
359
410
|
* receive have to still be there.
|
|
360
411
|
*/
|
|
361
412
|
function dynamicUpdate(interleaved, vertices, bounds, vertexCount, step, positionField, normalField) {
|
|
362
|
-
return (target, positions, normals) => {
|
|
413
|
+
return (target, positions, normals, previous = null) => {
|
|
363
414
|
if (positions.length !== vertexCount * 3) {
|
|
364
415
|
throw new Error(`this mesh has ${vertexCount} vertices and the update has ${positions.length / 3}. ` +
|
|
365
416
|
"A mesh's vertex count is fixed at creation: the index buffer, the pipeline and " +
|
|
366
417
|
'every other attribute are sized against it.');
|
|
367
418
|
}
|
|
419
|
+
/* The rows as they stand are last frame's, handed over before a position of them changes.
|
|
420
|
+
`writeBuffer` copies at the call, so patching the array afterwards cannot reach this copy. */
|
|
421
|
+
if (previous !== null)
|
|
422
|
+
target.queue.writeBuffer(previous, 0, interleaved);
|
|
368
423
|
/* Everything that decides whether this is on screen starts from the bounds, so a cloth
|
|
369
424
|
that blew sideways out of its original box would be culled while still visible. */
|
|
370
425
|
boundsOfPositions(positions, bounds);
|
|
@@ -423,7 +478,9 @@ instanced = false) {
|
|
|
423
478
|
const interleaved = [];
|
|
424
479
|
const constants = [];
|
|
425
480
|
let offset = 0;
|
|
426
|
-
|
|
481
|
+
const layered = present['layers'] === true;
|
|
482
|
+
VERTEX_LAYOUT.forEach((declared, index) => {
|
|
483
|
+
const attribute = laidOut(declared, layered);
|
|
427
484
|
/*
|
|
428
485
|
* **The instanced pipeline reclaims the two skinning locations, and it is allowed to because
|
|
429
486
|
* it cannot skin.** Locations 11 and 12 are the joint indices and weights; the INSTANCED
|
|
@@ -117,7 +117,7 @@ export declare const DEPTH_FRAG_BINDING: 1;
|
|
|
117
117
|
export declare const DEPTH_PREVIOUS_BINDING: {
|
|
118
118
|
readonly texture: 32;
|
|
119
119
|
readonly sampler: 33;
|
|
120
|
-
readonly type: "
|
|
120
|
+
readonly type: "sampler2DArray";
|
|
121
121
|
};
|
|
122
122
|
/** Where the skinned vertex stage reads the joint palette. Generated, not chosen here. */
|
|
123
123
|
export declare const DEPTH_PALETTE_BINDING: {
|
|
@@ -104,7 +104,8 @@ cutout = false) {
|
|
|
104
104
|
{
|
|
105
105
|
binding: PREVIOUS.texture,
|
|
106
106
|
visibility: VISIBILITY_FRAGMENT,
|
|
107
|
-
|
|
107
|
+
/* An array since the sun's maps became one (`shadowMap.ts`): the peel reads its static layer. */
|
|
108
|
+
texture: { sampleType: 'unfilterable-float', viewDimension: '2d-array' },
|
|
108
109
|
},
|
|
109
110
|
{
|
|
110
111
|
binding: PREVIOUS.sampler,
|
|
@@ -118,7 +119,11 @@ cutout = false) {
|
|
|
118
119
|
{
|
|
119
120
|
binding: CUTOUT_MAP.texture,
|
|
120
121
|
visibility: VISIBILITY_FRAGMENT,
|
|
121
|
-
texture
|
|
122
|
+
/* A surface texture, and every surface texture is a `2d-array` view. */
|
|
123
|
+
texture: {
|
|
124
|
+
sampleType: 'float',
|
|
125
|
+
viewDimension: '2d-array',
|
|
126
|
+
},
|
|
122
127
|
},
|
|
123
128
|
{
|
|
124
129
|
binding: CUTOUT_MAP.sampler,
|
|
@@ -24,6 +24,11 @@ export interface DrawCommand {
|
|
|
24
24
|
indexed: boolean;
|
|
25
25
|
count: number;
|
|
26
26
|
instances: number;
|
|
27
|
+
/**
|
|
28
|
+
* A `drawIndexedIndirect` record to draw from instead of `count` and `instances`: an instance
|
|
29
|
+
* cull's survivors, counted on the device. Null for every other draw.
|
|
30
|
+
*/
|
|
31
|
+
indirect: GPUBuffer | null;
|
|
27
32
|
}
|
|
28
33
|
export interface CommandPool {
|
|
29
34
|
commands: DrawCommand[];
|
|
@@ -58,6 +58,8 @@ export interface StageBindings {
|
|
|
58
58
|
readonly stride?: number;
|
|
59
59
|
}>>;
|
|
60
60
|
readonly textures: Readonly<Record<string, TextureBinding>>;
|
|
61
|
+
/** Each pipeline-overridable constant's id, by the GLSL name it was declared under. */
|
|
62
|
+
readonly overrides?: Readonly<Record<string, number>>;
|
|
61
63
|
}
|
|
62
64
|
/** The key for a set of vertex flags: the same rule `variantKey` uses, flags on, sorted, joined. */
|
|
63
65
|
export declare function flatVertexKey(skinned: boolean, morphed: boolean, instanced?: boolean): string;
|
|
@@ -176,8 +178,11 @@ export declare function flatPipeline(cache: PipelineCache, device: GPUDevice, la
|
|
|
176
178
|
* `depthMask` alone and only turns blending on. A translucent part of a loaded model is a
|
|
177
179
|
* pane of glass in a solid object, not a particle, and it has to occlude what is behind it
|
|
178
180
|
* for the rest of the model to sort correctly.
|
|
181
|
+
*
|
|
182
|
+
* `'additive'` adds instead: colour times alpha onto the target, its alpha kept. The key must
|
|
183
|
+
* carry it (`|add`).
|
|
179
184
|
*/
|
|
180
|
-
translucent?: boolean,
|
|
185
|
+
translucent?: boolean | 'additive',
|
|
181
186
|
/** Whether this pipeline reads a joint palette. See `FlatVertexOptions`. */
|
|
182
187
|
skinned?: boolean,
|
|
183
188
|
/** Whether this pipeline reads morph deltas. See `FlatVertexOptions`. */
|
|
@@ -2,6 +2,13 @@ import { DEPTH_COMPARE, DEPTH_FORMAT, depthOffsetForLayer } from '../../depthCon
|
|
|
2
2
|
import { FLAT_BINDINGS, FLAT_FRAG_WGSL, FLAT_VERT_WGSL, } from '../../shaders/generated/flat.wgsl.js';
|
|
3
3
|
import { vertexBufferLayouts } from './buffers.js';
|
|
4
4
|
import { shaderModule } from './shaderModules.js';
|
|
5
|
+
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
6
|
+
const SURFACE_MAPS = new Set([
|
|
7
|
+
'uAlbedo',
|
|
8
|
+
'uNormalMap',
|
|
9
|
+
'uOrmMap',
|
|
10
|
+
'uEmissiveMap',
|
|
11
|
+
]);
|
|
5
12
|
/**
|
|
6
13
|
* The key for a set of flags.
|
|
7
14
|
*
|
|
@@ -107,6 +114,20 @@ export function flatFragmentBindings(variant) {
|
|
|
107
114
|
throw new Error(`flatPass: no bindings for variant "${variant}"`);
|
|
108
115
|
return found;
|
|
109
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* The lit fragment stage's constants, set from the cache: the glass switch, keyed by its **id**.
|
|
119
|
+
*
|
|
120
|
+
* Not by its name, because an override declared with `@id` answers to the id alone — WebGPU's
|
|
121
|
+
* "pipeline-overridable constant identifier string" — and naga writes one on every specialisation
|
|
122
|
+
* constant. Keyed by name, Chrome refused every lit pipeline: *Pipeline overridable constant
|
|
123
|
+
* "GLASS_SHADOWS" not found*, and the frame drew nothing.
|
|
124
|
+
*/
|
|
125
|
+
function flatFragmentConstants(variant, cache) {
|
|
126
|
+
const id = flatFragmentBindings(variant).overrides?.['GLASS_SHADOWS'];
|
|
127
|
+
if (id === undefined)
|
|
128
|
+
throw new Error(`flatPass: variant "${variant}" has no glass switch`);
|
|
129
|
+
return { [String(id)]: cache.glassShadows ? 1 : 0 };
|
|
130
|
+
}
|
|
110
131
|
/** The depth format both backends compare with. */
|
|
111
132
|
/* Re-exported so the twenty passes that already import it from here do not each learn a new
|
|
112
133
|
module; `depthConvention.ts` is where the decision lives and why. */
|
|
@@ -182,7 +203,21 @@ export function createFlatBindGroupLayout(device, variant, skinned = false, morp
|
|
|
182
203
|
const integer = texture.type === 'usampler2D' || texture.type === 'usampler3D';
|
|
183
204
|
/* DriftLight's brick index and atlas, the lit pass's only volumes. See `driftLight.ts`. */
|
|
184
205
|
const volume = texture.type === 'sampler3D' || texture.type === 'usampler3D';
|
|
185
|
-
|
|
206
|
+
/* Glass tints are colour, mipmapped and filtered: a frosted pane is read at a coarser level. */
|
|
207
|
+
const tint = name.endsWith('GlassTints');
|
|
208
|
+
/*
|
|
209
|
+
* **The four material maps are arrays too, and they are colour.** Every surface texture is a
|
|
210
|
+
* `2d-array` view since texture arrays landed, so the rule below — an array is a shadow map —
|
|
211
|
+
* would declare albedo unfilterable and bind a non-filtering sampler to it, which reads as
|
|
212
|
+
* every textured surface going nearest-neighbour and losing its mip chain. Named, as
|
|
213
|
+
* `uEnvironment` is, because a pattern wide enough to catch them catches the shadow arrays.
|
|
214
|
+
*/
|
|
215
|
+
const surface = SURFACE_MAPS.has(name);
|
|
216
|
+
const isShadow = integer ||
|
|
217
|
+
(!tint &&
|
|
218
|
+
!surface &&
|
|
219
|
+
name !== 'uEnvironment' &&
|
|
220
|
+
(name.endsWith('ShadowMap') || cube || array));
|
|
186
221
|
entries.push({
|
|
187
222
|
binding: texture.texture,
|
|
188
223
|
visibility: VISIBILITY_FRAGMENT,
|
|
@@ -332,6 +367,9 @@ export function flatPipeline(cache, device, layout, variant, key, present,
|
|
|
332
367
|
* `depthMask` alone and only turns blending on. A translucent part of a loaded model is a
|
|
333
368
|
* pane of glass in a solid object, not a particle, and it has to occlude what is behind it
|
|
334
369
|
* for the rest of the model to sort correctly.
|
|
370
|
+
*
|
|
371
|
+
* `'additive'` adds instead: colour times alpha onto the target, its alpha kept. The key must
|
|
372
|
+
* carry it (`|add`).
|
|
335
373
|
*/
|
|
336
374
|
translucent = false,
|
|
337
375
|
/** Whether this pipeline reads a joint palette. See `FlatVertexOptions`. */
|
|
@@ -449,21 +487,31 @@ doubleSided = false) {
|
|
|
449
487
|
code: FLAT_FRAG_WGSL[variant] ?? '',
|
|
450
488
|
}),
|
|
451
489
|
entryPoint: 'main',
|
|
490
|
+
/* Every variant declares it, so every lit pipeline may set it: see `PipelineCache`. */
|
|
491
|
+
constants: flatFragmentConstants(variant, cache),
|
|
452
492
|
targets: [
|
|
453
493
|
oitTarget(oit) ??
|
|
454
|
-
(translucent
|
|
494
|
+
(translucent === 'additive'
|
|
455
495
|
? {
|
|
456
496
|
format: cache.format,
|
|
457
497
|
blend: {
|
|
458
|
-
color: {
|
|
459
|
-
|
|
460
|
-
dstFactor: 'one-minus-src-alpha',
|
|
461
|
-
operation: 'add',
|
|
462
|
-
},
|
|
463
|
-
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
498
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' },
|
|
499
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
464
500
|
},
|
|
465
501
|
}
|
|
466
|
-
:
|
|
502
|
+
: translucent
|
|
503
|
+
? {
|
|
504
|
+
format: cache.format,
|
|
505
|
+
blend: {
|
|
506
|
+
color: {
|
|
507
|
+
srcFactor: 'src-alpha',
|
|
508
|
+
dstFactor: 'one-minus-src-alpha',
|
|
509
|
+
operation: 'add',
|
|
510
|
+
},
|
|
511
|
+
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
512
|
+
},
|
|
513
|
+
}
|
|
514
|
+
: { format: cache.format }),
|
|
467
515
|
],
|
|
468
516
|
},
|
|
469
517
|
primitive: { topology: 'triangle-list', cullMode: doubleSided ? 'none' : 'back' },
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ResolvedGlass } from '../../glass.ts';
|
|
2
|
+
import type { PipelineCache } from './pipelineCache.ts';
|
|
3
|
+
import { UniformRing } from './uniformRing.ts';
|
|
4
|
+
export type GlassTintKind = 'rigid' | 'instanced' | 'skinned' | 'cutout' | 'instancedCutout';
|
|
5
|
+
/** The multiplying state: colour times what passes, clarity times clarity, order-free. */
|
|
6
|
+
export declare const GLASS_TINT_BLEND: GPUBlendState;
|
|
7
|
+
export declare class GpuGlassTint {
|
|
8
|
+
readonly frag: UniformRing;
|
|
9
|
+
private readonly layouts;
|
|
10
|
+
private plainGroup;
|
|
11
|
+
private groupVertBuffer;
|
|
12
|
+
private groupFragBuffer;
|
|
13
|
+
private readonly cutoutGroups;
|
|
14
|
+
private readonly skinnedGroups;
|
|
15
|
+
private readonly device;
|
|
16
|
+
constructor(device: GPUDevice);
|
|
17
|
+
/** One pane's block: what it lets through, how clear it is, and the light it is drawn for. */
|
|
18
|
+
writePane(slot: number, glass: ResolvedGlass, light: Float32Array): void;
|
|
19
|
+
/** The plain group, rebuilt only when a ring has grown a new buffer under it. */
|
|
20
|
+
group(vertBuffer: GPUBuffer): GPUBindGroup;
|
|
21
|
+
/** A cutout pane's group, one per map, built the first time that map casts colour. */
|
|
22
|
+
cutoutGroup(vertBuffer: GPUBuffer, view: GPUTextureView, sampler: GPUSampler): GPUBindGroup;
|
|
23
|
+
/** A skinned pane's group, one per palette view. */
|
|
24
|
+
skinnedGroup(vertBuffer: GPUBuffer, palette: GPUTextureView): GPUBindGroup;
|
|
25
|
+
/** The pipeline for one kind of caster, cull mode and vertex layout, cached by key. */
|
|
26
|
+
pipeline(cache: PipelineCache, kind: GlassTintKind, key: string, present: Readonly<Record<string, boolean>>, cullMode: GPUCullMode): GPURenderPipeline;
|
|
27
|
+
dispose(): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a pane lets through, drawn into a shadow's tint layer on this device: the layouts, the
|
|
3
|
+
* per-draw block, the bind groups and the pipelines for the five tint programs (`depth.ts`).
|
|
4
|
+
*
|
|
5
|
+
* **The vertex half is the depth pass's**, block for block — the tint's vertex stages are the depth
|
|
6
|
+
* ones with the world position handed on — so a draw's vertex slot comes from the shadow pass's own
|
|
7
|
+
* ring and only the pane's 32 bytes are this file's. **The fragment half multiplies**: an
|
|
8
|
+
* `rgba8unorm` target cleared to white, `dst × src` for colour and `dst-alpha × src` for clarity, and
|
|
9
|
+
* no depth, so every pane on a ray counts in any order. Built the first time glass casts, so a scene
|
|
10
|
+
* with no glass builds none of it.
|
|
11
|
+
*/
|
|
12
|
+
import { DEPTH_BINDINGS } from '../../shaders/generated/depth.wgsl.js';
|
|
13
|
+
import { GLASS_TINT_CUTOUT_FRAG_WGSL, GLASS_TINT_CUTOUT_VERT_WGSL, GLASS_TINT_FRAG_WGSL, GLASS_TINT_INSTANCED_CUTOUT_VERT_WGSL, GLASS_TINT_INSTANCED_VERT_WGSL, GLASS_TINT_SKINNED_VERT_WGSL, GLASS_TINT_VERT_WGSL, } from '../../shaders/generated/depth.wgsl.js';
|
|
14
|
+
import { vertexBufferLayouts } from './buffers.js';
|
|
15
|
+
import { shaderModule } from './shaderModules.js';
|
|
16
|
+
import { UniformRing } from './uniformRing.js';
|
|
17
|
+
const VISIBILITY_VERTEX = 0x1;
|
|
18
|
+
const VISIBILITY_FRAGMENT = 0x2;
|
|
19
|
+
const USAGE_UNIFORM_DST = 0x40 | 0x8; // UNIFORM | COPY_DST
|
|
20
|
+
const VERT = DEPTH_BINDINGS.GLASS_TINT_VERT;
|
|
21
|
+
const CUTOUT_VERT = DEPTH_BINDINGS.GLASS_TINT_CUTOUT_VERT;
|
|
22
|
+
const FRAG = DEPTH_BINDINGS.GLASS_TINT_FRAG;
|
|
23
|
+
const CUTOUT_MAP = DEPTH_BINDINGS.GLASS_TINT_CUTOUT_FRAG.textures.uCutoutMap;
|
|
24
|
+
const PALETTE = DEPTH_BINDINGS.GLASS_TINT_SKINNED_VERT.textures.uJointPalette;
|
|
25
|
+
const PANE = FRAG.fields.uGlassPane.offset;
|
|
26
|
+
const LIGHT = FRAG.fields.uGlassLight.offset;
|
|
27
|
+
/** Panes a frame can tint: a pane is a draw per shadow it reaches, and panes are few. */
|
|
28
|
+
const MAX_TINT_DRAWS = 512;
|
|
29
|
+
/** The multiplying state: colour times what passes, clarity times clarity, order-free. */
|
|
30
|
+
export const GLASS_TINT_BLEND = {
|
|
31
|
+
color: { operation: 'add', srcFactor: 'dst', dstFactor: 'zero' },
|
|
32
|
+
alpha: { operation: 'add', srcFactor: 'dst-alpha', dstFactor: 'zero' },
|
|
33
|
+
};
|
|
34
|
+
export class GpuGlassTint {
|
|
35
|
+
frag;
|
|
36
|
+
layouts;
|
|
37
|
+
plainGroup = null;
|
|
38
|
+
groupVertBuffer = null;
|
|
39
|
+
groupFragBuffer = null;
|
|
40
|
+
cutoutGroups = new Map();
|
|
41
|
+
skinnedGroups = new Map();
|
|
42
|
+
device;
|
|
43
|
+
constructor(device) {
|
|
44
|
+
this.device = device;
|
|
45
|
+
this.frag = new UniformRing(device, FRAG.uniformSize, MAX_TINT_DRAWS, USAGE_UNIFORM_DST, 'glassTint.ring');
|
|
46
|
+
const vert = (size) => ({
|
|
47
|
+
binding: VERT.uniforms,
|
|
48
|
+
visibility: VISIBILITY_VERTEX,
|
|
49
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: size },
|
|
50
|
+
});
|
|
51
|
+
const frag = {
|
|
52
|
+
binding: FRAG.uniforms,
|
|
53
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
54
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FRAG.uniformSize },
|
|
55
|
+
};
|
|
56
|
+
this.layouts = {
|
|
57
|
+
plain: device.createBindGroupLayout({
|
|
58
|
+
label: 'glassTint.layout',
|
|
59
|
+
entries: [vert(VERT.uniformSize), frag],
|
|
60
|
+
}),
|
|
61
|
+
cutout: device.createBindGroupLayout({
|
|
62
|
+
label: 'glassTint.layout.cutout',
|
|
63
|
+
entries: [
|
|
64
|
+
vert(CUTOUT_VERT.uniformSize),
|
|
65
|
+
frag,
|
|
66
|
+
{
|
|
67
|
+
binding: CUTOUT_MAP.texture,
|
|
68
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
69
|
+
/* A surface texture, and every surface texture is a `2d-array` view. */
|
|
70
|
+
texture: { sampleType: 'float', viewDimension: '2d-array' },
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
binding: CUTOUT_MAP.sampler,
|
|
74
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
75
|
+
sampler: { type: 'filtering' },
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
}),
|
|
79
|
+
skinned: device.createBindGroupLayout({
|
|
80
|
+
label: 'glassTint.layout.skinned',
|
|
81
|
+
entries: [
|
|
82
|
+
{
|
|
83
|
+
binding: PALETTE.texture,
|
|
84
|
+
visibility: VISIBILITY_VERTEX,
|
|
85
|
+
texture: { sampleType: 'unfilterable-float' },
|
|
86
|
+
},
|
|
87
|
+
vert(VERT.uniformSize),
|
|
88
|
+
frag,
|
|
89
|
+
],
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** One pane's block: what it lets through, how clear it is, and the light it is drawn for. */
|
|
94
|
+
writePane(slot, glass, light) {
|
|
95
|
+
const pane = paneScratch;
|
|
96
|
+
pane[0] = glass.transmission * glass.tint[0];
|
|
97
|
+
pane[1] = glass.transmission * glass.tint[1];
|
|
98
|
+
pane[2] = glass.transmission * glass.tint[2];
|
|
99
|
+
pane[3] = 1 - glass.frost;
|
|
100
|
+
this.frag.writeFloats(slot, PANE, pane);
|
|
101
|
+
this.frag.writeFloats(slot, LIGHT, light);
|
|
102
|
+
}
|
|
103
|
+
/** The plain group, rebuilt only when a ring has grown a new buffer under it. */
|
|
104
|
+
group(vertBuffer) {
|
|
105
|
+
if (this.plainGroup === null ||
|
|
106
|
+
this.groupVertBuffer !== vertBuffer ||
|
|
107
|
+
this.groupFragBuffer !== this.frag.buffer) {
|
|
108
|
+
this.cutoutGroups.clear();
|
|
109
|
+
this.skinnedGroups.clear();
|
|
110
|
+
this.groupVertBuffer = vertBuffer;
|
|
111
|
+
this.groupFragBuffer = this.frag.buffer;
|
|
112
|
+
this.plainGroup = this.device.createBindGroup({
|
|
113
|
+
label: 'glassTint.group',
|
|
114
|
+
layout: this.layouts.plain,
|
|
115
|
+
entries: [
|
|
116
|
+
{ binding: VERT.uniforms, resource: { buffer: vertBuffer, size: VERT.uniformSize } },
|
|
117
|
+
{
|
|
118
|
+
binding: FRAG.uniforms,
|
|
119
|
+
resource: { buffer: this.frag.buffer, size: FRAG.uniformSize },
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return this.plainGroup;
|
|
125
|
+
}
|
|
126
|
+
/** A cutout pane's group, one per map, built the first time that map casts colour. */
|
|
127
|
+
cutoutGroup(vertBuffer, view, sampler) {
|
|
128
|
+
this.group(vertBuffer);
|
|
129
|
+
const held = this.cutoutGroups.get(view);
|
|
130
|
+
if (held !== undefined)
|
|
131
|
+
return held;
|
|
132
|
+
const made = this.device.createBindGroup({
|
|
133
|
+
label: 'glassTint.group.cutout',
|
|
134
|
+
layout: this.layouts.cutout,
|
|
135
|
+
entries: [
|
|
136
|
+
{
|
|
137
|
+
binding: CUTOUT_VERT.uniforms,
|
|
138
|
+
resource: { buffer: vertBuffer, size: CUTOUT_VERT.uniformSize },
|
|
139
|
+
},
|
|
140
|
+
{ binding: FRAG.uniforms, resource: { buffer: this.frag.buffer, size: FRAG.uniformSize } },
|
|
141
|
+
{ binding: CUTOUT_MAP.texture, resource: view },
|
|
142
|
+
{ binding: CUTOUT_MAP.sampler, resource: sampler },
|
|
143
|
+
],
|
|
144
|
+
});
|
|
145
|
+
this.cutoutGroups.set(view, made);
|
|
146
|
+
return made;
|
|
147
|
+
}
|
|
148
|
+
/** A skinned pane's group, one per palette view. */
|
|
149
|
+
skinnedGroup(vertBuffer, palette) {
|
|
150
|
+
this.group(vertBuffer);
|
|
151
|
+
const held = this.skinnedGroups.get(palette);
|
|
152
|
+
if (held !== undefined)
|
|
153
|
+
return held;
|
|
154
|
+
const made = this.device.createBindGroup({
|
|
155
|
+
label: 'glassTint.group.skinned',
|
|
156
|
+
layout: this.layouts.skinned,
|
|
157
|
+
entries: [
|
|
158
|
+
{ binding: PALETTE.texture, resource: palette },
|
|
159
|
+
{ binding: VERT.uniforms, resource: { buffer: vertBuffer, size: VERT.uniformSize } },
|
|
160
|
+
{ binding: FRAG.uniforms, resource: { buffer: this.frag.buffer, size: FRAG.uniformSize } },
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
this.skinnedGroups.set(palette, made);
|
|
164
|
+
return made;
|
|
165
|
+
}
|
|
166
|
+
/** The pipeline for one kind of caster, cull mode and vertex layout, cached by key. */
|
|
167
|
+
pipeline(cache, kind, key, present, cullMode) {
|
|
168
|
+
const cutout = kind === 'cutout' || kind === 'instancedCutout';
|
|
169
|
+
const instanced = kind === 'instanced' || kind === 'instancedCutout';
|
|
170
|
+
const layout = kind === 'skinned' ? this.layouts.skinned : cutout ? this.layouts.cutout : this.layouts.plain;
|
|
171
|
+
const vertex = kind === 'rigid'
|
|
172
|
+
? GLASS_TINT_VERT_WGSL
|
|
173
|
+
: kind === 'instanced'
|
|
174
|
+
? GLASS_TINT_INSTANCED_VERT_WGSL
|
|
175
|
+
: kind === 'skinned'
|
|
176
|
+
? GLASS_TINT_SKINNED_VERT_WGSL
|
|
177
|
+
: kind === 'cutout'
|
|
178
|
+
? GLASS_TINT_CUTOUT_VERT_WGSL
|
|
179
|
+
: GLASS_TINT_INSTANCED_CUTOUT_VERT_WGSL;
|
|
180
|
+
const label = `glass-tint|${kind}|${cullMode}|${key}`;
|
|
181
|
+
return cache.get(label, () => ({
|
|
182
|
+
label,
|
|
183
|
+
layout: this.device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
184
|
+
vertex: {
|
|
185
|
+
module: shaderModule(this.device, { label: `glassTint.${kind}.vert`, code: vertex }),
|
|
186
|
+
entryPoint: 'main',
|
|
187
|
+
buffers: vertexBufferLayouts(present, instanced),
|
|
188
|
+
},
|
|
189
|
+
fragment: {
|
|
190
|
+
module: shaderModule(this.device, {
|
|
191
|
+
label: cutout ? 'glassTint.cutout.frag' : 'glassTint.frag',
|
|
192
|
+
code: cutout ? GLASS_TINT_CUTOUT_FRAG_WGSL : GLASS_TINT_FRAG_WGSL,
|
|
193
|
+
}),
|
|
194
|
+
entryPoint: 'main',
|
|
195
|
+
targets: [{ format: 'rgba8unorm', blend: GLASS_TINT_BLEND }],
|
|
196
|
+
},
|
|
197
|
+
/* The depth pass's primitive state exactly — its winding included, for the reason
|
|
198
|
+
`depthPipeline` gives: this map is sampled, not presented. */
|
|
199
|
+
primitive: { topology: 'triangle-list', cullMode, frontFace: 'cw' },
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
dispose() {
|
|
203
|
+
this.frag.dispose();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const paneScratch = new Float32Array(4);
|