@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
|
@@ -103,6 +103,28 @@ export const VERTEX_LAYOUT: readonly VertexAttribute[] = [
|
|
|
103
103
|
];
|
|
104
104
|
|
|
105
105
|
/** Geometry on the device, with the buffers bound in layout order. */
|
|
106
|
+
/**
|
|
107
|
+
* The texture coordinates of a mesh that names texture-array layers: (u, v, layer), three floats.
|
|
108
|
+
*
|
|
109
|
+
* **Three only where layers exist.** Every location is spent, so the layer rides in this attribute,
|
|
110
|
+
* and widening it for every textured mesh would add four bytes to each of its vertices for nothing.
|
|
111
|
+
* A mesh without layers keeps two, and the shader's `vec3` input reads z as 0 — WebGPU fills a
|
|
112
|
+
* component the format does not carry with 0 (and w with 1) — which is layer 0. The pipeline key
|
|
113
|
+
* carries `:layers`, so the two vertex layouts never share a pipeline.
|
|
114
|
+
*/
|
|
115
|
+
export const LAYERED_UVS: VertexAttribute = {
|
|
116
|
+
name: 'uvs',
|
|
117
|
+
shaderLocation: 5,
|
|
118
|
+
format: 'float32x3',
|
|
119
|
+
components: 3,
|
|
120
|
+
optional: true,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/** The attribute as this mesh lays it out: the UV field widens where the mesh names layers. */
|
|
124
|
+
function laidOut(attribute: VertexAttribute, layered: boolean): VertexAttribute {
|
|
125
|
+
return layered && attribute.name === 'uvs' ? LAYERED_UVS : attribute;
|
|
126
|
+
}
|
|
127
|
+
|
|
106
128
|
export interface GpuMesh {
|
|
107
129
|
/**
|
|
108
130
|
* The buffers a draw binds, in the order `vertexBufferLayouts` describes them.
|
|
@@ -125,6 +147,12 @@ export interface GpuMesh {
|
|
|
125
147
|
* its own does.
|
|
126
148
|
*/
|
|
127
149
|
readonly vertexStride: number;
|
|
150
|
+
/**
|
|
151
|
+
* Byte offsets of the joint indices and weights in the interleaved vertex, or null for a mesh
|
|
152
|
+
* that supplied neither. For a pass that skins through a shader of its own — the motion pass —
|
|
153
|
+
* which has to find them without the `present` map the generated pipelines are keyed by.
|
|
154
|
+
*/
|
|
155
|
+
readonly skinOffsets: { readonly joints: number; readonly weights: number } | null;
|
|
128
156
|
readonly indexBuffer: GPUBuffer;
|
|
129
157
|
readonly indexCount: number;
|
|
130
158
|
/**
|
|
@@ -192,7 +220,19 @@ export interface GpuMesh {
|
|
|
192
220
|
* than every mesh paying it.
|
|
193
221
|
*/
|
|
194
222
|
readonly update:
|
|
195
|
-
((
|
|
223
|
+
| ((
|
|
224
|
+
device: GPUDevice,
|
|
225
|
+
positions: Float32Array,
|
|
226
|
+
normals?: Float32Array,
|
|
227
|
+
previous?: GPUBuffer | null,
|
|
228
|
+
) => void)
|
|
229
|
+
| null;
|
|
230
|
+
/**
|
|
231
|
+
* A dynamic mesh's motion state, which the renderer owns: a buffer for last frame's interleaved
|
|
232
|
+
* rows, made the first time a reconstructing renderer rewrites the mesh, and the frame of the
|
|
233
|
+
* last rewrite. Null on a mesh created without `{ dynamic: true }`, which never moves a vertex.
|
|
234
|
+
*/
|
|
235
|
+
readonly motion: { previous: GPUBuffer | null; changed: number } | null;
|
|
196
236
|
dispose(): void;
|
|
197
237
|
}
|
|
198
238
|
|
|
@@ -263,9 +303,10 @@ export function createGpuMeshIncremental(
|
|
|
263
303
|
validateMeshData(data);
|
|
264
304
|
const bounds = boundsOfPositions(data.positions, createBounds());
|
|
265
305
|
const vertexCount = data.positions.length / 3;
|
|
306
|
+
const layered = data.layers !== undefined;
|
|
266
307
|
const supplied = VERTEX_LAYOUT.filter(
|
|
267
308
|
(attribute) => !attribute.optional || data[attribute.name as keyof MeshData] !== undefined,
|
|
268
|
-
);
|
|
309
|
+
).map((attribute) => laidOut(attribute, layered));
|
|
269
310
|
|
|
270
311
|
/* Interleaved: one stride holding every attribute the mesh actually supplied. */
|
|
271
312
|
const stride = supplied.reduce((sum, attribute) => sum + attribute.components * 4, 0);
|
|
@@ -377,6 +418,7 @@ export function createGpuMeshIncremental(
|
|
|
377
418
|
progress,
|
|
378
419
|
hasTangents: data.tangents !== undefined,
|
|
379
420
|
isSkinned: data.joints !== undefined,
|
|
421
|
+
skinOffsets: skinOffsetsOf(supplied),
|
|
380
422
|
hasChannel: data.channel !== undefined,
|
|
381
423
|
morph:
|
|
382
424
|
data.morphTargets === undefined || data.morphTargetCount === undefined
|
|
@@ -440,7 +482,21 @@ function* uploadSteps(job: UploadJob): Generator<void, void, void> {
|
|
|
440
482
|
let fieldOffset = 0;
|
|
441
483
|
for (const attribute of supplied) {
|
|
442
484
|
const source = data[attribute.name as keyof MeshData] as Float32Array;
|
|
443
|
-
|
|
485
|
+
if (attribute === LAYERED_UVS) {
|
|
486
|
+
/* (u, v) from the coordinates and the layer after them, one field of three. */
|
|
487
|
+
interleaveField(interleaved, source, 2, step, fieldOffset, from, to);
|
|
488
|
+
interleaveField(
|
|
489
|
+
interleaved,
|
|
490
|
+
data.layers as Float32Array,
|
|
491
|
+
1,
|
|
492
|
+
step,
|
|
493
|
+
fieldOffset + 2,
|
|
494
|
+
from,
|
|
495
|
+
to,
|
|
496
|
+
);
|
|
497
|
+
} else {
|
|
498
|
+
interleaveField(interleaved, source, attribute.components, step, fieldOffset, from, to);
|
|
499
|
+
}
|
|
444
500
|
fieldOffset += attribute.components;
|
|
445
501
|
}
|
|
446
502
|
device.queue.writeBuffer(vertices, from * stride, interleaved, from * step, (to - from) * step);
|
|
@@ -505,6 +561,22 @@ function interleaveField(
|
|
|
505
561
|
}
|
|
506
562
|
}
|
|
507
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Where the joints and weights sit in a vertex of `supplied`, the attributes a mesh interleaves in
|
|
566
|
+
* layout order; null unless it supplied both.
|
|
567
|
+
*/
|
|
568
|
+
function skinOffsetsOf(supplied: readonly VertexAttribute[]): GpuMesh['skinOffsets'] {
|
|
569
|
+
let floats = 0;
|
|
570
|
+
let joints = -1;
|
|
571
|
+
let weights = -1;
|
|
572
|
+
for (const attribute of supplied) {
|
|
573
|
+
if (attribute.name === 'joints') joints = floats * 4;
|
|
574
|
+
if (attribute.name === 'weights') weights = floats * 4;
|
|
575
|
+
floats += attribute.components;
|
|
576
|
+
}
|
|
577
|
+
return joints >= 0 && weights >= 0 ? { joints, weights } : null;
|
|
578
|
+
}
|
|
579
|
+
|
|
508
580
|
/** The handle, made where it can see only what it hands out. */
|
|
509
581
|
function gpuMeshOf(parts: {
|
|
510
582
|
readonly vertices: GPUBuffer;
|
|
@@ -516,14 +588,17 @@ function gpuMeshOf(parts: {
|
|
|
516
588
|
readonly progress: { readonly uploaded: boolean };
|
|
517
589
|
readonly hasTangents: boolean;
|
|
518
590
|
readonly isSkinned: boolean;
|
|
591
|
+
readonly skinOffsets: GpuMesh['skinOffsets'];
|
|
519
592
|
readonly hasChannel: boolean;
|
|
520
593
|
readonly morph: MorphTexture | null;
|
|
521
594
|
readonly update: GpuMesh['update'];
|
|
522
595
|
}): GpuMesh {
|
|
596
|
+
const motion = parts.update === null ? null : { previous: null as GPUBuffer | null, changed: -1 };
|
|
523
597
|
const { vertices, constants, indexBuffer, progress } = parts;
|
|
524
598
|
return {
|
|
525
599
|
vertexBuffers: [vertices, constants],
|
|
526
600
|
vertexStride: parts.stride,
|
|
601
|
+
skinOffsets: parts.skinOffsets,
|
|
527
602
|
indexBuffer,
|
|
528
603
|
indexCount: parts.indexCount,
|
|
529
604
|
bounds: parts.bounds,
|
|
@@ -535,7 +610,9 @@ function gpuMeshOf(parts: {
|
|
|
535
610
|
hasChannel: parts.hasChannel,
|
|
536
611
|
morph: parts.morph,
|
|
537
612
|
update: parts.update,
|
|
613
|
+
motion,
|
|
538
614
|
dispose(): void {
|
|
615
|
+
motion?.previous?.destroy();
|
|
539
616
|
vertices.destroy();
|
|
540
617
|
constants.destroy();
|
|
541
618
|
indexBuffer.destroy();
|
|
@@ -557,7 +634,12 @@ function dynamicUpdate(
|
|
|
557
634
|
positionField: number,
|
|
558
635
|
normalField: number,
|
|
559
636
|
): NonNullable<GpuMesh['update']> {
|
|
560
|
-
return (
|
|
637
|
+
return (
|
|
638
|
+
target: GPUDevice,
|
|
639
|
+
positions: Float32Array,
|
|
640
|
+
normals?: Float32Array,
|
|
641
|
+
previous: GPUBuffer | null = null,
|
|
642
|
+
): void => {
|
|
561
643
|
if (positions.length !== vertexCount * 3) {
|
|
562
644
|
throw new Error(
|
|
563
645
|
`this mesh has ${vertexCount} vertices and the update has ${positions.length / 3}. ` +
|
|
@@ -565,6 +647,9 @@ function dynamicUpdate(
|
|
|
565
647
|
'every other attribute are sized against it.',
|
|
566
648
|
);
|
|
567
649
|
}
|
|
650
|
+
/* The rows as they stand are last frame's, handed over before a position of them changes.
|
|
651
|
+
`writeBuffer` copies at the call, so patching the array afterwards cannot reach this copy. */
|
|
652
|
+
if (previous !== null) target.queue.writeBuffer(previous, 0, interleaved);
|
|
568
653
|
/* Everything that decides whether this is on screen starts from the bounds, so a cloth
|
|
569
654
|
that blew sideways out of its original box would be culled while still visible. */
|
|
570
655
|
boundsOfPositions(positions, bounds);
|
|
@@ -630,7 +715,9 @@ export function vertexBufferLayouts(
|
|
|
630
715
|
const constants: GPUVertexAttribute[] = [];
|
|
631
716
|
let offset = 0;
|
|
632
717
|
|
|
633
|
-
|
|
718
|
+
const layered = present['layers'] === true;
|
|
719
|
+
VERTEX_LAYOUT.forEach((declared, index) => {
|
|
720
|
+
const attribute = laidOut(declared, layered);
|
|
634
721
|
/*
|
|
635
722
|
* **The instanced pipeline reclaims the two skinning locations, and it is allowed to because
|
|
636
723
|
* it cannot skin.** Locations 11 and 12 are the joint indices and weights; the INSTANCED
|
|
@@ -122,7 +122,8 @@ export function createDepthBindGroupLayout(
|
|
|
122
122
|
{
|
|
123
123
|
binding: PREVIOUS.texture,
|
|
124
124
|
visibility: VISIBILITY_FRAGMENT,
|
|
125
|
-
|
|
125
|
+
/* An array since the sun's maps became one (`shadowMap.ts`): the peel reads its static layer. */
|
|
126
|
+
texture: { sampleType: 'unfilterable-float', viewDimension: '2d-array' },
|
|
126
127
|
},
|
|
127
128
|
{
|
|
128
129
|
binding: PREVIOUS.sampler,
|
|
@@ -136,7 +137,11 @@ export function createDepthBindGroupLayout(
|
|
|
136
137
|
{
|
|
137
138
|
binding: CUTOUT_MAP.texture,
|
|
138
139
|
visibility: VISIBILITY_FRAGMENT,
|
|
139
|
-
texture
|
|
140
|
+
/* A surface texture, and every surface texture is a `2d-array` view. */
|
|
141
|
+
texture: {
|
|
142
|
+
sampleType: 'float' as GPUTextureSampleType,
|
|
143
|
+
viewDimension: '2d-array' as GPUTextureViewDimension,
|
|
144
|
+
},
|
|
140
145
|
},
|
|
141
146
|
{
|
|
142
147
|
binding: CUTOUT_MAP.sampler,
|
|
@@ -28,6 +28,11 @@ export interface DrawCommand {
|
|
|
28
28
|
indexed: boolean;
|
|
29
29
|
count: number;
|
|
30
30
|
instances: number;
|
|
31
|
+
/**
|
|
32
|
+
* A `drawIndexedIndirect` record to draw from instead of `count` and `instances`: an instance
|
|
33
|
+
* cull's survivors, counted on the device. Null for every other draw.
|
|
34
|
+
*/
|
|
35
|
+
indirect: GPUBuffer | null;
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
export interface CommandPool {
|
|
@@ -50,6 +55,7 @@ function emptyCommand(): DrawCommand {
|
|
|
50
55
|
indexed: false,
|
|
51
56
|
count: 0,
|
|
52
57
|
instances: 1,
|
|
58
|
+
indirect: null,
|
|
53
59
|
};
|
|
54
60
|
}
|
|
55
61
|
|
|
@@ -8,6 +8,14 @@ import { vertexBufferLayouts } from './buffers.ts';
|
|
|
8
8
|
import type { PipelineCache } from './pipelineCache.ts';
|
|
9
9
|
import { shaderModule } from './shaderModules.ts';
|
|
10
10
|
|
|
11
|
+
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
12
|
+
const SURFACE_MAPS: ReadonlySet<string> = new Set([
|
|
13
|
+
'uAlbedo',
|
|
14
|
+
'uNormalMap',
|
|
15
|
+
'uOrmMap',
|
|
16
|
+
'uEmissiveMap',
|
|
17
|
+
]);
|
|
18
|
+
|
|
11
19
|
/**
|
|
12
20
|
* The flat pipeline: the shader that draws the world.
|
|
13
21
|
*
|
|
@@ -82,6 +90,8 @@ export interface StageBindings {
|
|
|
82
90
|
>
|
|
83
91
|
>;
|
|
84
92
|
readonly textures: Readonly<Record<string, TextureBinding>>;
|
|
93
|
+
/** Each pipeline-overridable constant's id, by the GLSL name it was declared under. */
|
|
94
|
+
readonly overrides?: Readonly<Record<string, number>>;
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
/*
|
|
@@ -188,6 +198,20 @@ export function flatFragmentBindings(variant: FlatVariant): StageBindings {
|
|
|
188
198
|
return found;
|
|
189
199
|
}
|
|
190
200
|
|
|
201
|
+
/**
|
|
202
|
+
* The lit fragment stage's constants, set from the cache: the glass switch, keyed by its **id**.
|
|
203
|
+
*
|
|
204
|
+
* Not by its name, because an override declared with `@id` answers to the id alone — WebGPU's
|
|
205
|
+
* "pipeline-overridable constant identifier string" — and naga writes one on every specialisation
|
|
206
|
+
* constant. Keyed by name, Chrome refused every lit pipeline: *Pipeline overridable constant
|
|
207
|
+
* "GLASS_SHADOWS" not found*, and the frame drew nothing.
|
|
208
|
+
*/
|
|
209
|
+
function flatFragmentConstants(variant: FlatVariant, cache: PipelineCache): Record<string, number> {
|
|
210
|
+
const id = flatFragmentBindings(variant).overrides?.['GLASS_SHADOWS'];
|
|
211
|
+
if (id === undefined) throw new Error(`flatPass: variant "${variant}" has no glass switch`);
|
|
212
|
+
return { [String(id)]: cache.glassShadows ? 1 : 0 };
|
|
213
|
+
}
|
|
214
|
+
|
|
191
215
|
/** The depth format both backends compare with. */
|
|
192
216
|
/* Re-exported so the twenty passes that already import it from here do not each learn a new
|
|
193
217
|
module; `depthConvention.ts` is where the decision lives and why. */
|
|
@@ -272,8 +296,22 @@ export function createFlatBindGroupLayout(
|
|
|
272
296
|
const integer = texture.type === 'usampler2D' || texture.type === 'usampler3D';
|
|
273
297
|
/* DriftLight's brick index and atlas, the lit pass's only volumes. See `driftLight.ts`. */
|
|
274
298
|
const volume = texture.type === 'sampler3D' || texture.type === 'usampler3D';
|
|
299
|
+
/* Glass tints are colour, mipmapped and filtered: a frosted pane is read at a coarser level. */
|
|
300
|
+
const tint = name.endsWith('GlassTints');
|
|
301
|
+
/*
|
|
302
|
+
* **The four material maps are arrays too, and they are colour.** Every surface texture is a
|
|
303
|
+
* `2d-array` view since texture arrays landed, so the rule below — an array is a shadow map —
|
|
304
|
+
* would declare albedo unfilterable and bind a non-filtering sampler to it, which reads as
|
|
305
|
+
* every textured surface going nearest-neighbour and losing its mip chain. Named, as
|
|
306
|
+
* `uEnvironment` is, because a pattern wide enough to catch them catches the shadow arrays.
|
|
307
|
+
*/
|
|
308
|
+
const surface = SURFACE_MAPS.has(name);
|
|
275
309
|
const isShadow =
|
|
276
|
-
integer ||
|
|
310
|
+
integer ||
|
|
311
|
+
(!tint &&
|
|
312
|
+
!surface &&
|
|
313
|
+
name !== 'uEnvironment' &&
|
|
314
|
+
(name.endsWith('ShadowMap') || cube || array));
|
|
277
315
|
entries.push({
|
|
278
316
|
binding: texture.texture,
|
|
279
317
|
visibility: VISIBILITY_FRAGMENT,
|
|
@@ -443,8 +481,11 @@ export function flatPipeline(
|
|
|
443
481
|
* `depthMask` alone and only turns blending on. A translucent part of a loaded model is a
|
|
444
482
|
* pane of glass in a solid object, not a particle, and it has to occlude what is behind it
|
|
445
483
|
* for the rest of the model to sort correctly.
|
|
484
|
+
*
|
|
485
|
+
* `'additive'` adds instead: colour times alpha onto the target, its alpha kept. The key must
|
|
486
|
+
* carry it (`|add`).
|
|
446
487
|
*/
|
|
447
|
-
translucent = false,
|
|
488
|
+
translucent: boolean | 'additive' = false,
|
|
448
489
|
/** Whether this pipeline reads a joint palette. See `FlatVertexOptions`. */
|
|
449
490
|
skinned = false,
|
|
450
491
|
/** Whether this pipeline reads morph deltas. See `FlatVertexOptions`. */
|
|
@@ -557,7 +598,7 @@ function flatDescriptor(
|
|
|
557
598
|
variant: FlatVariant,
|
|
558
599
|
key: string,
|
|
559
600
|
present: Readonly<Record<string, boolean>>,
|
|
560
|
-
translucent: boolean,
|
|
601
|
+
translucent: boolean | 'additive',
|
|
561
602
|
/** Whether this pipeline reads a joint palette. See `FlatVertexOptions`. */
|
|
562
603
|
skinned: boolean,
|
|
563
604
|
/** Whether this pipeline reads morph deltas. See `FlatVertexOptions`. */
|
|
@@ -603,21 +644,31 @@ function flatDescriptor(
|
|
|
603
644
|
code: FLAT_FRAG_WGSL[variant] ?? '',
|
|
604
645
|
}),
|
|
605
646
|
entryPoint: 'main',
|
|
647
|
+
/* Every variant declares it, so every lit pipeline may set it: see `PipelineCache`. */
|
|
648
|
+
constants: flatFragmentConstants(variant, cache),
|
|
606
649
|
targets: [
|
|
607
650
|
oitTarget(oit) ??
|
|
608
|
-
(translucent
|
|
651
|
+
(translucent === 'additive'
|
|
609
652
|
? {
|
|
610
653
|
format: cache.format,
|
|
611
654
|
blend: {
|
|
612
|
-
color: {
|
|
613
|
-
|
|
614
|
-
dstFactor: 'one-minus-src-alpha',
|
|
615
|
-
operation: 'add',
|
|
616
|
-
},
|
|
617
|
-
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
655
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' },
|
|
656
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
618
657
|
},
|
|
619
658
|
}
|
|
620
|
-
:
|
|
659
|
+
: translucent
|
|
660
|
+
? {
|
|
661
|
+
format: cache.format,
|
|
662
|
+
blend: {
|
|
663
|
+
color: {
|
|
664
|
+
srcFactor: 'src-alpha',
|
|
665
|
+
dstFactor: 'one-minus-src-alpha',
|
|
666
|
+
operation: 'add',
|
|
667
|
+
},
|
|
668
|
+
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
669
|
+
},
|
|
670
|
+
}
|
|
671
|
+
: { format: cache.format }),
|
|
621
672
|
],
|
|
622
673
|
},
|
|
623
674
|
primitive: { topology: 'triangle-list', cullMode: doubleSided ? 'none' : 'back' },
|
|
@@ -0,0 +1,245 @@
|
|
|
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.ts';
|
|
13
|
+
import {
|
|
14
|
+
GLASS_TINT_CUTOUT_FRAG_WGSL,
|
|
15
|
+
GLASS_TINT_CUTOUT_VERT_WGSL,
|
|
16
|
+
GLASS_TINT_FRAG_WGSL,
|
|
17
|
+
GLASS_TINT_INSTANCED_CUTOUT_VERT_WGSL,
|
|
18
|
+
GLASS_TINT_INSTANCED_VERT_WGSL,
|
|
19
|
+
GLASS_TINT_SKINNED_VERT_WGSL,
|
|
20
|
+
GLASS_TINT_VERT_WGSL,
|
|
21
|
+
} from '../../shaders/generated/depth.wgsl.ts';
|
|
22
|
+
import type { ResolvedGlass } from '../../glass.ts';
|
|
23
|
+
import { vertexBufferLayouts } from './buffers.ts';
|
|
24
|
+
import type { PipelineCache } from './pipelineCache.ts';
|
|
25
|
+
import { shaderModule } from './shaderModules.ts';
|
|
26
|
+
import { UniformRing } from './uniformRing.ts';
|
|
27
|
+
|
|
28
|
+
const VISIBILITY_VERTEX = 0x1;
|
|
29
|
+
const VISIBILITY_FRAGMENT = 0x2;
|
|
30
|
+
const USAGE_UNIFORM_DST = 0x40 | 0x8; // UNIFORM | COPY_DST
|
|
31
|
+
|
|
32
|
+
const VERT = DEPTH_BINDINGS.GLASS_TINT_VERT;
|
|
33
|
+
const CUTOUT_VERT = DEPTH_BINDINGS.GLASS_TINT_CUTOUT_VERT;
|
|
34
|
+
const FRAG = DEPTH_BINDINGS.GLASS_TINT_FRAG;
|
|
35
|
+
const CUTOUT_MAP = DEPTH_BINDINGS.GLASS_TINT_CUTOUT_FRAG.textures.uCutoutMap;
|
|
36
|
+
const PALETTE = DEPTH_BINDINGS.GLASS_TINT_SKINNED_VERT.textures.uJointPalette;
|
|
37
|
+
const PANE = FRAG.fields.uGlassPane.offset;
|
|
38
|
+
const LIGHT = FRAG.fields.uGlassLight.offset;
|
|
39
|
+
|
|
40
|
+
/** Panes a frame can tint: a pane is a draw per shadow it reaches, and panes are few. */
|
|
41
|
+
const MAX_TINT_DRAWS = 512;
|
|
42
|
+
|
|
43
|
+
export type GlassTintKind = 'rigid' | 'instanced' | 'skinned' | 'cutout' | 'instancedCutout';
|
|
44
|
+
|
|
45
|
+
/** The multiplying state: colour times what passes, clarity times clarity, order-free. */
|
|
46
|
+
export const GLASS_TINT_BLEND: GPUBlendState = {
|
|
47
|
+
color: { operation: 'add', srcFactor: 'dst', dstFactor: 'zero' },
|
|
48
|
+
alpha: { operation: 'add', srcFactor: 'dst-alpha', dstFactor: 'zero' },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export class GpuGlassTint {
|
|
52
|
+
readonly frag: UniformRing;
|
|
53
|
+
private readonly layouts: Record<'plain' | 'cutout' | 'skinned', GPUBindGroupLayout>;
|
|
54
|
+
private plainGroup: GPUBindGroup | null = null;
|
|
55
|
+
private groupVertBuffer: GPUBuffer | null = null;
|
|
56
|
+
private groupFragBuffer: GPUBuffer | null = null;
|
|
57
|
+
private readonly cutoutGroups = new Map<GPUTextureView, GPUBindGroup>();
|
|
58
|
+
private readonly skinnedGroups = new Map<GPUTextureView, GPUBindGroup>();
|
|
59
|
+
private readonly device: GPUDevice;
|
|
60
|
+
|
|
61
|
+
constructor(device: GPUDevice) {
|
|
62
|
+
this.device = device;
|
|
63
|
+
this.frag = new UniformRing(
|
|
64
|
+
device,
|
|
65
|
+
FRAG.uniformSize,
|
|
66
|
+
MAX_TINT_DRAWS,
|
|
67
|
+
USAGE_UNIFORM_DST,
|
|
68
|
+
'glassTint.ring',
|
|
69
|
+
);
|
|
70
|
+
const vert = (size: number): GPUBindGroupLayoutEntry => ({
|
|
71
|
+
binding: VERT.uniforms,
|
|
72
|
+
visibility: VISIBILITY_VERTEX,
|
|
73
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: size },
|
|
74
|
+
});
|
|
75
|
+
const frag: GPUBindGroupLayoutEntry = {
|
|
76
|
+
binding: FRAG.uniforms,
|
|
77
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
78
|
+
buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: FRAG.uniformSize },
|
|
79
|
+
};
|
|
80
|
+
this.layouts = {
|
|
81
|
+
plain: device.createBindGroupLayout({
|
|
82
|
+
label: 'glassTint.layout',
|
|
83
|
+
entries: [vert(VERT.uniformSize), frag],
|
|
84
|
+
}),
|
|
85
|
+
cutout: device.createBindGroupLayout({
|
|
86
|
+
label: 'glassTint.layout.cutout',
|
|
87
|
+
entries: [
|
|
88
|
+
vert(CUTOUT_VERT.uniformSize),
|
|
89
|
+
frag,
|
|
90
|
+
{
|
|
91
|
+
binding: CUTOUT_MAP.texture,
|
|
92
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
93
|
+
/* A surface texture, and every surface texture is a `2d-array` view. */
|
|
94
|
+
texture: { sampleType: 'float', viewDimension: '2d-array' },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
binding: CUTOUT_MAP.sampler,
|
|
98
|
+
visibility: VISIBILITY_FRAGMENT,
|
|
99
|
+
sampler: { type: 'filtering' },
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
}),
|
|
103
|
+
skinned: device.createBindGroupLayout({
|
|
104
|
+
label: 'glassTint.layout.skinned',
|
|
105
|
+
entries: [
|
|
106
|
+
{
|
|
107
|
+
binding: PALETTE.texture,
|
|
108
|
+
visibility: VISIBILITY_VERTEX,
|
|
109
|
+
texture: { sampleType: 'unfilterable-float' },
|
|
110
|
+
},
|
|
111
|
+
vert(VERT.uniformSize),
|
|
112
|
+
frag,
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** One pane's block: what it lets through, how clear it is, and the light it is drawn for. */
|
|
119
|
+
writePane(slot: number, glass: ResolvedGlass, light: Float32Array): void {
|
|
120
|
+
const pane = paneScratch;
|
|
121
|
+
pane[0] = glass.transmission * glass.tint[0];
|
|
122
|
+
pane[1] = glass.transmission * glass.tint[1];
|
|
123
|
+
pane[2] = glass.transmission * glass.tint[2];
|
|
124
|
+
pane[3] = 1 - glass.frost;
|
|
125
|
+
this.frag.writeFloats(slot, PANE, pane);
|
|
126
|
+
this.frag.writeFloats(slot, LIGHT, light);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The plain group, rebuilt only when a ring has grown a new buffer under it. */
|
|
130
|
+
group(vertBuffer: GPUBuffer): GPUBindGroup {
|
|
131
|
+
if (
|
|
132
|
+
this.plainGroup === null ||
|
|
133
|
+
this.groupVertBuffer !== vertBuffer ||
|
|
134
|
+
this.groupFragBuffer !== this.frag.buffer
|
|
135
|
+
) {
|
|
136
|
+
this.cutoutGroups.clear();
|
|
137
|
+
this.skinnedGroups.clear();
|
|
138
|
+
this.groupVertBuffer = vertBuffer;
|
|
139
|
+
this.groupFragBuffer = this.frag.buffer;
|
|
140
|
+
this.plainGroup = this.device.createBindGroup({
|
|
141
|
+
label: 'glassTint.group',
|
|
142
|
+
layout: this.layouts.plain,
|
|
143
|
+
entries: [
|
|
144
|
+
{ binding: VERT.uniforms, resource: { buffer: vertBuffer, size: VERT.uniformSize } },
|
|
145
|
+
{
|
|
146
|
+
binding: FRAG.uniforms,
|
|
147
|
+
resource: { buffer: this.frag.buffer, size: FRAG.uniformSize },
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return this.plainGroup;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** A cutout pane's group, one per map, built the first time that map casts colour. */
|
|
156
|
+
cutoutGroup(vertBuffer: GPUBuffer, view: GPUTextureView, sampler: GPUSampler): GPUBindGroup {
|
|
157
|
+
this.group(vertBuffer);
|
|
158
|
+
const held = this.cutoutGroups.get(view);
|
|
159
|
+
if (held !== undefined) return held;
|
|
160
|
+
const made = this.device.createBindGroup({
|
|
161
|
+
label: 'glassTint.group.cutout',
|
|
162
|
+
layout: this.layouts.cutout,
|
|
163
|
+
entries: [
|
|
164
|
+
{
|
|
165
|
+
binding: CUTOUT_VERT.uniforms,
|
|
166
|
+
resource: { buffer: vertBuffer, size: CUTOUT_VERT.uniformSize },
|
|
167
|
+
},
|
|
168
|
+
{ binding: FRAG.uniforms, resource: { buffer: this.frag.buffer, size: FRAG.uniformSize } },
|
|
169
|
+
{ binding: CUTOUT_MAP.texture, resource: view },
|
|
170
|
+
{ binding: CUTOUT_MAP.sampler, resource: sampler },
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
this.cutoutGroups.set(view, made);
|
|
174
|
+
return made;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** A skinned pane's group, one per palette view. */
|
|
178
|
+
skinnedGroup(vertBuffer: GPUBuffer, palette: GPUTextureView): GPUBindGroup {
|
|
179
|
+
this.group(vertBuffer);
|
|
180
|
+
const held = this.skinnedGroups.get(palette);
|
|
181
|
+
if (held !== undefined) return held;
|
|
182
|
+
const made = this.device.createBindGroup({
|
|
183
|
+
label: 'glassTint.group.skinned',
|
|
184
|
+
layout: this.layouts.skinned,
|
|
185
|
+
entries: [
|
|
186
|
+
{ binding: PALETTE.texture, resource: palette },
|
|
187
|
+
{ binding: VERT.uniforms, resource: { buffer: vertBuffer, size: VERT.uniformSize } },
|
|
188
|
+
{ binding: FRAG.uniforms, resource: { buffer: this.frag.buffer, size: FRAG.uniformSize } },
|
|
189
|
+
],
|
|
190
|
+
});
|
|
191
|
+
this.skinnedGroups.set(palette, made);
|
|
192
|
+
return made;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** The pipeline for one kind of caster, cull mode and vertex layout, cached by key. */
|
|
196
|
+
pipeline(
|
|
197
|
+
cache: PipelineCache,
|
|
198
|
+
kind: GlassTintKind,
|
|
199
|
+
key: string,
|
|
200
|
+
present: Readonly<Record<string, boolean>>,
|
|
201
|
+
cullMode: GPUCullMode,
|
|
202
|
+
): GPURenderPipeline {
|
|
203
|
+
const cutout = kind === 'cutout' || kind === 'instancedCutout';
|
|
204
|
+
const instanced = kind === 'instanced' || kind === 'instancedCutout';
|
|
205
|
+
const layout =
|
|
206
|
+
kind === 'skinned' ? this.layouts.skinned : cutout ? this.layouts.cutout : this.layouts.plain;
|
|
207
|
+
const vertex =
|
|
208
|
+
kind === 'rigid'
|
|
209
|
+
? GLASS_TINT_VERT_WGSL
|
|
210
|
+
: kind === 'instanced'
|
|
211
|
+
? GLASS_TINT_INSTANCED_VERT_WGSL
|
|
212
|
+
: kind === 'skinned'
|
|
213
|
+
? GLASS_TINT_SKINNED_VERT_WGSL
|
|
214
|
+
: kind === 'cutout'
|
|
215
|
+
? GLASS_TINT_CUTOUT_VERT_WGSL
|
|
216
|
+
: GLASS_TINT_INSTANCED_CUTOUT_VERT_WGSL;
|
|
217
|
+
const label = `glass-tint|${kind}|${cullMode}|${key}`;
|
|
218
|
+
return cache.get(label, () => ({
|
|
219
|
+
label,
|
|
220
|
+
layout: this.device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
221
|
+
vertex: {
|
|
222
|
+
module: shaderModule(this.device, { label: `glassTint.${kind}.vert`, code: vertex }),
|
|
223
|
+
entryPoint: 'main',
|
|
224
|
+
buffers: vertexBufferLayouts(present, instanced),
|
|
225
|
+
},
|
|
226
|
+
fragment: {
|
|
227
|
+
module: shaderModule(this.device, {
|
|
228
|
+
label: cutout ? 'glassTint.cutout.frag' : 'glassTint.frag',
|
|
229
|
+
code: cutout ? GLASS_TINT_CUTOUT_FRAG_WGSL : GLASS_TINT_FRAG_WGSL,
|
|
230
|
+
}),
|
|
231
|
+
entryPoint: 'main',
|
|
232
|
+
targets: [{ format: 'rgba8unorm', blend: GLASS_TINT_BLEND }],
|
|
233
|
+
},
|
|
234
|
+
/* The depth pass's primitive state exactly — its winding included, for the reason
|
|
235
|
+
`depthPipeline` gives: this map is sampled, not presented. */
|
|
236
|
+
primitive: { topology: 'triangle-list', cullMode, frontFace: 'cw' },
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
dispose(): void {
|
|
241
|
+
this.frag.dispose();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const paneScratch = new Float32Array(4);
|