@driftengine/core 4.9.0 → 4.11.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 +133 -11
- package/README.md +43 -38
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -4
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/backend/api.d.ts +10 -3
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +189 -4
- package/dist/render/backend/webgl2/renderer.js +614 -66
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +24 -4
- package/dist/render/backend/webgpu/buffers.js +116 -59
- package/dist/render/backend/webgpu/clothKernels.d.ts +8 -0
- package/dist/render/backend/webgpu/clothKernels.js +76 -0
- package/dist/render/backend/webgpu/clothOps.d.ts +39 -0
- package/dist/render/backend/webgpu/clothOps.js +78 -0
- package/dist/render/backend/webgpu/clothSetLayout.d.ts +25 -0
- package/dist/render/backend/webgpu/clothSetLayout.js +84 -0
- package/dist/render/backend/webgpu/clothSetPack.d.ts +33 -0
- package/dist/render/backend/webgpu/clothSetPack.js +144 -0
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/drawCommand.d.ts +20 -4
- package/dist/render/backend/webgpu/drawCommand.js +11 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
- package/dist/render/backend/webgpu/flatPass.js +137 -20
- package/dist/render/backend/webgpu/gpuClothSet.d.ts +80 -0
- package/dist/render/backend/webgpu/gpuClothSet.js +462 -0
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/latePass.js +1 -0
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/motionPass.js +15 -6
- package/dist/render/backend/webgpu/pipelineCache.d.ts +28 -1
- package/dist/render/backend/webgpu/pipelineCache.js +46 -1
- package/dist/render/backend/webgpu/postPass.d.ts +1 -1
- package/dist/render/backend/webgpu/renderer.d.ts +200 -35
- package/dist/render/backend/webgpu/renderer.js +993 -168
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +9 -2
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +121 -47
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +242 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/backend/webgpu/vertexFormats.d.ts +22 -0
- package/dist/render/backend/webgpu/vertexFormats.js +97 -0
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/globalMediumPass.d.ts +2 -0
- package/dist/render/globalMediumPass.js +1 -0
- package/dist/render/indexWidth.d.ts +17 -0
- package/dist/render/indexWidth.js +23 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightMatrix.d.ts +11 -0
- package/dist/render/lightMatrix.js +14 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +14 -0
- package/dist/render/mesh.js +44 -14
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/renderQuality.d.ts +30 -0
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.d.ts +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/screenSpaceReflection.d.ts +2 -1
- package/dist/render/shader.d.ts +15 -0
- package/dist/render/shader.js +41 -0
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/flat/directionalShadow.js +84 -10
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +3 -0
- package/dist/render/shaders/flat/index.d.ts +21 -0
- package/dist/render/shaders/flat/index.js +42 -7
- package/dist/render/shaders/flat/layered.d.ts +19 -0
- package/dist/render/shaders/flat/layered.js +115 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +58 -21
- package/dist/render/shaders/flat/mapReads.d.ts +10 -0
- package/dist/render/shaders/flat/mapReads.js +38 -0
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/movingSun.d.ts +21 -0
- package/dist/render/shaders/flat/movingSun.js +46 -0
- package/dist/render/shaders/flat/normalMap.d.ts +6 -2
- package/dist/render/shaders/flat/normalMap.js +14 -3
- package/dist/render/shaders/flat/overlay.d.ts +3 -2
- package/dist/render/shaders/flat/overlay.js +42 -20
- package/dist/render/shaders/flat/pointShadow.js +2 -2
- package/dist/render/shaders/flat/preamble.js +59 -27
- package/dist/render/shaders/flat/worldUv.d.ts +22 -0
- package/dist/render/shaders/flat/worldUv.js +113 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3616 -3042
- package/dist/render/shaders/generated/flat.wgsl.js +3688 -3113
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +8 -3
- package/dist/render/shaders/generated/globalMedium.wgsl.js +8 -3
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +15 -10
- package/dist/render/shaders/generated/lightVolume.wgsl.js +16 -11
- package/dist/render/shaders/globalMedium.js +9 -1
- package/dist/render/shaders/lightVolume.js +9 -1
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/tangentFrame.d.ts +1 -1
- package/dist/render/shaders/tangentFrame.js +16 -3
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/skinnedClothRun.d.ts +28 -0
- package/dist/render/skinnedClothRun.js +103 -35
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceLayers.d.ts +39 -0
- package/dist/render/surfaceLayers.js +26 -0
- package/dist/render/surfaceOverlay.d.ts +16 -3
- package/dist/render/surfaceOverlay.js +11 -6
- package/dist/render/surfaceProjection.d.ts +34 -0
- package/dist/render/surfaceProjection.js +30 -0
- package/dist/render/surfaceTexture.d.ts +68 -7
- package/dist/render/surfaceTexture.js +56 -17
- package/dist/render/vertexPacking.d.ts +48 -0
- package/dist/render/vertexPacking.js +68 -0
- package/package.json +6 -6
- package/src/index.ts +12 -4
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/backend/api.ts +13 -3
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +723 -79
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +195 -70
- package/src/render/backend/webgpu/clothKernels.ts +86 -0
- package/src/render/backend/webgpu/clothOps.ts +86 -0
- package/src/render/backend/webgpu/clothSetLayout.ts +102 -0
- package/src/render/backend/webgpu/clothSetPack.ts +197 -0
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/drawCommand.ts +25 -4
- package/src/render/backend/webgpu/flatPass.ts +212 -41
- package/src/render/backend/webgpu/gpuClothSet.ts +564 -0
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/latePass.ts +1 -0
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/motionPass.ts +18 -7
- package/src/render/backend/webgpu/pipelineCache.ts +53 -7
- package/src/render/backend/webgpu/renderer.ts +1201 -202
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +121 -47
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +364 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/backend/webgpu/vertexFormats.ts +113 -0
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/glCompressed.ts +83 -0
- package/src/render/globalMediumPass.ts +7 -0
- package/src/render/indexWidth.ts +27 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightMatrix.ts +15 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +72 -14
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/renderQuality.ts +38 -0
- package/src/render/rendererHarness.ts +15 -0
- package/src/render/screenSpaceReflection.ts +2 -1
- package/src/render/shader.ts +59 -0
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/flat/directionalShadow.ts +84 -10
- package/src/render/shaders/flat/glassTint.ts +7 -1
- package/src/render/shaders/flat/index.ts +63 -7
- package/src/render/shaders/flat/layered.ts +115 -0
- package/src/render/shaders/flat/main.ts +58 -21
- package/src/render/shaders/flat/mapReads.ts +38 -0
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/movingSun.ts +46 -0
- package/src/render/shaders/flat/normalMap.ts +14 -3
- package/src/render/shaders/flat/overlay.ts +42 -20
- package/src/render/shaders/flat/pointShadow.ts +2 -2
- package/src/render/shaders/flat/preamble.ts +59 -27
- package/src/render/shaders/flat/worldUv.ts +113 -0
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/flat.wgsl.ts +3688 -3113
- package/src/render/shaders/generated/globalMedium.wgsl.ts +8 -3
- package/src/render/shaders/generated/lightVolume.wgsl.ts +16 -11
- package/src/render/shaders/globalMedium.ts +9 -1
- package/src/render/shaders/lightVolume.ts +9 -1
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/tangentFrame.ts +16 -3
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/skinnedClothRun.ts +138 -38
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceLayers.ts +57 -0
- package/src/render/surfaceOverlay.ts +24 -7
- package/src/render/surfaceProjection.ts +57 -0
- package/src/render/surfaceTexture.ts +124 -27
- package/src/render/vertexPacking.ts +109 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +0 -74
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +0 -452
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +0 -502
|
@@ -5,6 +5,7 @@ import { CUTOUT_DITHER_GLSL } from '../cutoutDither.js';
|
|
|
5
5
|
import { SKINNING_GLSL } from './skinning.js';
|
|
6
6
|
import { CLOTH_BINDING_GLSL } from './clothBinding.js';
|
|
7
7
|
import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from './vertexChannel.js';
|
|
8
|
+
import { BONE_ANIMATION_GLSL } from './boneAnimation.js';
|
|
8
9
|
/**
|
|
9
10
|
* Depth-only shadow pass. Its optional peel mode rejects the first recorded
|
|
10
11
|
* surface so the next independently fading occluder can be retained.
|
|
@@ -77,6 +78,17 @@ uniform vec2 uUvOffset;
|
|
|
77
78
|
uniform vec2 uAlphaCutout;
|
|
78
79
|
#endif
|
|
79
80
|
|
|
81
|
+
#if ANIMATED
|
|
82
|
+
/*
|
|
83
|
+
* **A bone animation's, after every other declaration** so no field of the variants before it
|
|
84
|
+
* moves: the grain lane the vertex's bone rides in, the scene's clock, and the chunk the colour
|
|
85
|
+
* pass runs — the same expression, or a crowd's shadow stands still while the crowd moves.
|
|
86
|
+
*/
|
|
87
|
+
layout(location = 8) in float aGrain;
|
|
88
|
+
uniform float uSceneTime;
|
|
89
|
+
${BONE_ANIMATION_GLSL}
|
|
90
|
+
#endif
|
|
91
|
+
|
|
80
92
|
out vec4 vLightPosition;
|
|
81
93
|
#if CUTOUT
|
|
82
94
|
/* The texture coordinate and, in z, the texture-array layer the face wears. */
|
|
@@ -98,6 +110,12 @@ void main() {
|
|
|
98
110
|
#else
|
|
99
111
|
vec4 local = vec4(aPosition, 1.0);
|
|
100
112
|
#endif
|
|
113
|
+
#if ANIMATED
|
|
114
|
+
/* Turned and placed as the colour pass turns and places it; its normal and tangent unused. */
|
|
115
|
+
vec3 animatedNormal = vec3(0.0, 1.0, 0.0);
|
|
116
|
+
vec3 animatedTangent = vec3(1.0, 0.0, 0.0);
|
|
117
|
+
local = vec4(boneAnimate(local.xyz, animatedNormal, animatedTangent), 1.0);
|
|
118
|
+
#endif
|
|
101
119
|
#if INSTANCED
|
|
102
120
|
mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
|
|
103
121
|
/* The bottom row is the instance's texture cell, rebuilt as the row it stands for: see flat. */
|
|
@@ -144,9 +162,9 @@ void main() {
|
|
|
144
162
|
}
|
|
145
163
|
`;
|
|
146
164
|
/** The rigid variant: the world, a prop, a mesh with no rig behind it. */
|
|
147
|
-
export const DEPTH_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false }, 'depth');
|
|
165
|
+
export const DEPTH_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false }, 'depth');
|
|
148
166
|
/** The skinned variant, which reads a joint palette and moves the vertex by it. */
|
|
149
|
-
export const DEPTH_SKINNED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false }, 'depth-skinned');
|
|
167
|
+
export const DEPTH_SKINNED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false }, 'depth-skinned');
|
|
150
168
|
/**
|
|
151
169
|
* The variant an instanced draw casts its shadow through.
|
|
152
170
|
*
|
|
@@ -155,7 +173,7 @@ export const DEPTH_SKINNED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINN
|
|
|
155
173
|
* right place and the rest stacked underneath it, which reads as a lighting fault rather than as
|
|
156
174
|
* a missing variant, and is the shape the per-draw ring exists to prevent one level up.
|
|
157
175
|
*/
|
|
158
|
-
export const DEPTH_INSTANCED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false }, 'depth-instanced');
|
|
176
|
+
export const DEPTH_INSTANCED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: false }, 'depth-instanced');
|
|
159
177
|
/**
|
|
160
178
|
* The variants a cutout caster casts through: a leaf card, a chain link, a fence, whose shape is in
|
|
161
179
|
* its texture's alpha rather than in its geometry.
|
|
@@ -166,8 +184,15 @@ export const DEPTH_INSTANCED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKI
|
|
|
166
184
|
* leaves every opaque caster byte for byte as it was. What it costs is one more program each, and
|
|
167
185
|
* a skinned cutout, which nothing has asked for, is not among them.
|
|
168
186
|
*/
|
|
169
|
-
export const DEPTH_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false }, 'depth-cutout');
|
|
170
|
-
export const DEPTH_INSTANCED_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false }, 'depth-instanced-cutout');
|
|
187
|
+
export const DEPTH_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false, ANIMATED: false }, 'depth-cutout');
|
|
188
|
+
export const DEPTH_INSTANCED_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: false }, 'depth-instanced-cutout');
|
|
189
|
+
/**
|
|
190
|
+
* The variants a crowd casts through: an instanced batch playing a bone animation, its vertices
|
|
191
|
+
* where the clip puts them at each instance's moment. See `shaders/boneAnimation.ts`. No glass
|
|
192
|
+
* variant: a crowd is not glass, and a glass batch that animates casts its tint from rest.
|
|
193
|
+
*/
|
|
194
|
+
export const DEPTH_INSTANCED_ANIMATED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: true }, 'depth-instanced-animated');
|
|
195
|
+
export const DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: true }, 'depth-instanced-animated-cutout');
|
|
171
196
|
export const DEPTH_FRAG = `#version 300 es
|
|
172
197
|
precision highp float;
|
|
173
198
|
in vec4 vLightPosition;
|
|
@@ -238,11 +263,11 @@ void main() {
|
|
|
238
263
|
* exactly where it casts its depth, deformed and placed the same way, or the coloured patch parts
|
|
239
264
|
* from the pane's own shadow edge. The only addition is `vGlassWorld`.
|
|
240
265
|
*/
|
|
241
|
-
export const GLASS_TINT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true }, 'glass-tint');
|
|
242
|
-
export const GLASS_TINT_SKINNED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true }, 'glass-tint-skinned');
|
|
243
|
-
export const GLASS_TINT_INSTANCED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true }, 'glass-tint-instanced');
|
|
244
|
-
export const GLASS_TINT_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true }, 'glass-tint-cutout');
|
|
245
|
-
export const GLASS_TINT_INSTANCED_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true }, 'glass-tint-instanced-cutout');
|
|
266
|
+
export const GLASS_TINT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false }, 'glass-tint');
|
|
267
|
+
export const GLASS_TINT_SKINNED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false }, 'glass-tint-skinned');
|
|
268
|
+
export const GLASS_TINT_INSTANCED_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true, ANIMATED: false }, 'glass-tint-instanced');
|
|
269
|
+
export const GLASS_TINT_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true, ANIMATED: false }, 'glass-tint-cutout');
|
|
270
|
+
export const GLASS_TINT_INSTANCED_CUTOUT_VERT = resolveConditionals(DEPTH_VERT_SOURCE, { SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true, ANIMATED: false }, 'glass-tint-instanced-cutout');
|
|
246
271
|
/**
|
|
247
272
|
* What a pane lets through: its transmission and colour, less what it reflects toward the light,
|
|
248
273
|
* and how clear it is — `glassShadow.ts`'s `paneTexel`, stated for the device. Drawn with a
|
|
@@ -29,13 +29,56 @@ export const DIRECTIONALSHADOW_GLSL = `vec2 receiverPlaneDepthGradient(vec3 p) {
|
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/* One stored depth against a receiver, in a map spanning \`span\` metres of depth. */
|
|
33
|
+
float directionalVisibilityAt(float receiverDepth, float compareDepth, float storedDepth, float span) {
|
|
33
34
|
if (compareDepth <= storedDepth) return 1.0;
|
|
34
|
-
float rayDistance = max(receiverDepth - storedDepth, 0.0) *
|
|
35
|
+
float rayDistance = max(receiverDepth - storedDepth, 0.0) * span;
|
|
35
36
|
float groundDistance = rayDistance * length(uDirectionalDir.xz);
|
|
36
37
|
return 1.0 - shadowReach(groundDistance, uShadowMaxDistance);
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
float directionalVisibility(float receiverDepth, float compareDepth, float storedDepth) {
|
|
41
|
+
return directionalVisibilityAt(receiverDepth, compareDepth, storedDepth, uShadowDepthSpan);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* How far inside its square a receiver stands in a layer's map: 1 well inside, 0 at its border. */
|
|
45
|
+
float sunMapFade(vec3 p) {
|
|
46
|
+
if (p.z > 1.0 || p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0) return 0.0;
|
|
47
|
+
vec2 fromCentre = abs(p.xy - 0.5) * 2.0;
|
|
48
|
+
return (1.0 - smoothstep(0.72, 0.98, max(fromCentre.x, fromCentre.y))) *
|
|
49
|
+
(1.0 - smoothstep(0.90, 1.0, p.z));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* The moving layer at its own place, where it has a matrix of its own (movingSun.ts): the coarse
|
|
54
|
+
* test of shadowFactor, and its filter, each against the moving map's own depth span, and lit by
|
|
55
|
+
* how far inside the moving map's square the receiver stands rather than cut at its border.
|
|
56
|
+
*/
|
|
57
|
+
float movingSunCoarse(vec3 pm, float span) {
|
|
58
|
+
float inside = sunMapFade(pm);
|
|
59
|
+
if (inside <= 0.0) return 1.0;
|
|
60
|
+
float stored = textureLod(uSunShadows, vec3(pm.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r;
|
|
61
|
+
return mix(1.0, directionalVisibilityAt(pm.z, pm.z - 1.0 / span, stored, span), inside);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
float movingSunFiltered(vec3 pm, vec2 gradient, float span) {
|
|
65
|
+
float inside = sunMapFade(pm);
|
|
66
|
+
if (inside <= 0.0) return 1.0;
|
|
67
|
+
float texel = 1.35 / uShadowMapSize;
|
|
68
|
+
float slopeLimit = 9.1 / uShadowMapSize;
|
|
69
|
+
float lit = 0.0;
|
|
70
|
+
for (int i = 0; i < ${MAX_SHADOW_FILTER_TAPS}; i++) {
|
|
71
|
+
if (i >= uShadowFilterTaps) break;
|
|
72
|
+
vec2 sampleUv = pm.xy + DIRECTIONAL_PCF_OFFSETS[i] * texel;
|
|
73
|
+
vec2 texelCentre = (floor(sampleUv * uShadowMapSize) + 0.5) / uShadowMapSize;
|
|
74
|
+
float slopeOffset = clamp(dot(gradient, texelCentre - pm.xy), -slopeLimit, slopeLimit);
|
|
75
|
+
float tapReceiverDepth = pm.z + slopeOffset;
|
|
76
|
+
float stored = textureLod(uSunShadows, vec3(sampleUv, ${SUN_DYNAMIC_LAYER}.0), 0.0).r;
|
|
77
|
+
lit += directionalVisibilityAt(tapReceiverDepth, tapReceiverDepth - 0.14 / span, stored, span);
|
|
78
|
+
}
|
|
79
|
+
return mix(1.0, lit / float(max(uShadowFilterTaps, 1)), inside);
|
|
80
|
+
}
|
|
81
|
+
|
|
39
82
|
float shadowFactor(float directionalNdl) {
|
|
40
83
|
if (uShadowStrength <= 0.0) return 1.0;
|
|
41
84
|
|
|
@@ -65,6 +108,14 @@ float shadowFactor(float directionalNdl) {
|
|
|
65
108
|
vec3 p = vLightPos.xyz / vLightPos.w;
|
|
66
109
|
p = p * 0.5 + 0.5;
|
|
67
110
|
vec2 depthGradient = receiverPlaneDepthGradient(p);
|
|
111
|
+
/* The moving layer's own place and plane where it has a matrix of its own (movingSun.ts), taken
|
|
112
|
+
here beside the static layer's for the same reason: above every varying-dependent return. */
|
|
113
|
+
vec3 pm = p;
|
|
114
|
+
vec2 movingGradient = depthGradient;
|
|
115
|
+
if (MOVING_SUN) {
|
|
116
|
+
pm = movingSunAt();
|
|
117
|
+
movingGradient = receiverPlaneDepthGradient(pm);
|
|
118
|
+
}
|
|
68
119
|
|
|
69
120
|
// Near a surface's own light terminator its direct-light term is already
|
|
70
121
|
// approaching zero, while the orthographic projection of that surface
|
|
@@ -129,7 +180,8 @@ float shadowFactor(float directionalNdl) {
|
|
|
129
180
|
float coarseCompare = p.z - 1.0 / uShadowDepthSpan;
|
|
130
181
|
float coarse =
|
|
131
182
|
directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r) *
|
|
132
|
-
|
|
183
|
+
(MOVING_SUN ? movingSunCoarse(pm, movingSunSpan()) :
|
|
184
|
+
directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r));
|
|
133
185
|
if (uPeeledShadowEnabled != 0) {
|
|
134
186
|
coarse *= directionalVisibility(p.z, coarseCompare, textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r);
|
|
135
187
|
}
|
|
@@ -193,7 +245,6 @@ float shadowFactor(float directionalNdl) {
|
|
|
193
245
|
* there is no mip to select and level zero is the only thing \`texture\` could have read.
|
|
194
246
|
*/
|
|
195
247
|
float staticDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_STATIC_LAYER}.0), 0.0).r;
|
|
196
|
-
float dynamicDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_DYNAMIC_LAYER}.0), 0.0).r;
|
|
197
248
|
staticLit += directionalVisibility(tapReceiverDepth, compare, staticDepth);
|
|
198
249
|
if (uPeeledShadowEnabled != 0) {
|
|
199
250
|
float peeledDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_PEELED_LAYER}.0), 0.0).r;
|
|
@@ -201,12 +252,18 @@ float shadowFactor(float directionalNdl) {
|
|
|
201
252
|
} else {
|
|
202
253
|
peeledLit += 1.0;
|
|
203
254
|
}
|
|
204
|
-
|
|
255
|
+
/* The moving layer here where it shares the static one's place; at its own below otherwise.
|
|
256
|
+
Branched on the switch itself, never its negation: see overridableConstants in transform.mjs. */
|
|
257
|
+
if (MOVING_SUN) {
|
|
258
|
+
} else {
|
|
259
|
+
float dynamicDepth = textureLod(uSunShadows, vec3(sampleUv, ${SUN_DYNAMIC_LAYER}.0), 0.0).r;
|
|
260
|
+
dynamicLit += directionalVisibility(tapReceiverDepth, compare, dynamicDepth);
|
|
261
|
+
}
|
|
205
262
|
}
|
|
206
263
|
float tapCount = float(max(uShadowFilterTaps, 1));
|
|
207
264
|
staticLit /= tapCount;
|
|
208
265
|
peeledLit /= tapCount;
|
|
209
|
-
dynamicLit
|
|
266
|
+
dynamicLit = MOVING_SUN ? movingSunFiltered(pm, movingGradient, movingSunSpan()) : dynamicLit / tapCount;
|
|
210
267
|
|
|
211
268
|
// Independent layers preserve every recorded fact at an overlap: each
|
|
212
269
|
// caster keeps its own distance fade, and their transmissions compose
|
|
@@ -227,11 +284,11 @@ float shadowFactor(float directionalNdl) {
|
|
|
227
284
|
* behind the receiver lending it colour within the spread, which only a receiver between two panes
|
|
228
285
|
* meets. One function for both layers, because two copies were most of the lit shaders' growth.
|
|
229
286
|
*/
|
|
230
|
-
vec3 sunGlassLayer(vec3 p, float paneLayer, float tintLayer, float bias, float texel, float uvPerMetre) {
|
|
287
|
+
vec3 sunGlassLayer(vec3 p, float paneLayer, float tintLayer, float bias, float texel, float uvPerMetre, float span) {
|
|
231
288
|
float tintSize = float(textureSize(uSunGlassTints, 0).x);
|
|
232
289
|
float clarity = textureLod(uSunGlassTints, vec3(p.xy, tintLayer), 0.0).a;
|
|
233
290
|
float behind =
|
|
234
|
-
max(p.z - textureLod(uSunShadows, vec3(p.xy, paneLayer), 0.0).r, 0.0) *
|
|
291
|
+
max(p.z - textureLod(uSunShadows, vec3(p.xy, paneLayer), 0.0).r, 0.0) * span;
|
|
235
292
|
float radius = clamp(
|
|
236
293
|
(1.0 - clarity) * ${FROST_SPREAD.toFixed(6)} * behind * uvPerMetre,
|
|
237
294
|
texel,
|
|
@@ -271,6 +328,13 @@ vec3 sunGlassLookup(float directionalNdl) {
|
|
|
271
328
|
/* Map units per metre along the receiver, from derivatives taken first in uniform control flow,
|
|
272
329
|
so a frost spread stated in metres lands the same whatever size of light matrix a consumer built. */
|
|
273
330
|
float uvPerMetre = length(dFdx(p.xy)) / max(length(dFdx(vWorldPos)), 1e-6);
|
|
331
|
+
/* The moving glass at its own place where its layer has a matrix of its own: movingSun.ts. */
|
|
332
|
+
vec3 pm = p;
|
|
333
|
+
float movingPerMetre = uvPerMetre;
|
|
334
|
+
if (MOVING_SUN) {
|
|
335
|
+
pm = movingSunAt();
|
|
336
|
+
movingPerMetre = length(dFdx(pm.xy)) / max(length(dFdx(vWorldPos)), 1e-6);
|
|
337
|
+
}
|
|
274
338
|
if (uShadowStrength <= 0.0 || textureSize(uSunGlassTints, 0).x <= 1) return vec3(1.0);
|
|
275
339
|
if (directionalNdl <= 0.0) return vec3(1.0);
|
|
276
340
|
if (p.z > 1.0 || p.x < 0.0 || p.x > 1.0 || p.y < 0.0 || p.y > 1.0) return vec3(1.0);
|
|
@@ -288,8 +352,18 @@ vec3 sunGlassLookup(float directionalNdl) {
|
|
|
288
352
|
|
|
289
353
|
float bias = 0.14 / uShadowDepthSpan;
|
|
290
354
|
float texel = 1.35 / uShadowMapSize;
|
|
291
|
-
vec3 staticTint = sunGlassLayer(p, ${SUN_GLASS_STATIC_LAYER}.0, 0.0, bias, texel, uvPerMetre);
|
|
292
|
-
vec3 movingTint =
|
|
355
|
+
vec3 staticTint = sunGlassLayer(p, ${SUN_GLASS_STATIC_LAYER}.0, 0.0, bias, texel, uvPerMetre, uShadowDepthSpan);
|
|
356
|
+
vec3 movingTint = MOVING_SUN && sunMapFade(pm) <= 0.0
|
|
357
|
+
? vec3(1.0)
|
|
358
|
+
: sunGlassLayer(
|
|
359
|
+
pm,
|
|
360
|
+
${SUN_GLASS_MOVING_LAYER}.0,
|
|
361
|
+
1.0,
|
|
362
|
+
MOVING_SUN ? 0.14 / movingSunSpan() : bias,
|
|
363
|
+
texel,
|
|
364
|
+
movingPerMetre,
|
|
365
|
+
MOVING_SUN ? movingSunSpan() : uShadowDepthSpan
|
|
366
|
+
);
|
|
293
367
|
return mix(vec3(1.0), staticTint * movingTint, strength);
|
|
294
368
|
}
|
|
295
369
|
|
|
@@ -8,7 +8,7 @@ export declare function glassTintGlsl(glassShadows: boolean): string;
|
|
|
8
8
|
* The lit stage's switches, by the name of the constant each is: the decision both backends make
|
|
9
9
|
* about which optional code a lit program carries. See `litSwitchesGlsl`.
|
|
10
10
|
*/
|
|
11
|
-
export type LitSwitch = 'GLASS_SHADOWS' | 'CLUSTERED_LIGHTS' | 'LIGHT_FIXTURES' | 'SURFACE_EFFECTS' | 'DRIFT_LIGHT' | 'PHYSICAL_SPECULAR' | 'SURFACE_OVERLAY' | 'REFLECTION_MAPS';
|
|
11
|
+
export type LitSwitch = 'GLASS_SHADOWS' | 'CLUSTERED_LIGHTS' | 'LIGHT_FIXTURES' | 'SURFACE_EFFECTS' | 'DRIFT_LIGHT' | 'PHYSICAL_SPECULAR' | 'SURFACE_OVERLAY' | 'REFLECTION_MAPS' | 'WORLD_UVS' | 'MOVING_SUN' | 'LAYERED';
|
|
12
12
|
/** Every switch off: what a renderer starts from before its profile and its content say otherwise. */
|
|
13
13
|
export declare function noLitSwitches(): Record<LitSwitch, boolean>;
|
|
14
14
|
/** Which of the lit stage's optional features a build reads. See `litSwitchesGlsl`. */
|
|
@@ -38,6 +38,12 @@ export interface FlatVertexOptions {
|
|
|
38
38
|
* Excludes `skinned`: the joint attributes and the instance matrix want the same locations.
|
|
39
39
|
*/
|
|
40
40
|
readonly instanced: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether an instanced variant follows a bone animation: \`shaders/boneAnimation.ts\`. A
|
|
43
|
+
* variant rather than a pipeline constant, because it declares three textures the other
|
|
44
|
+
* instanced pipelines would otherwise have to bind stand-ins for. Instanced only.
|
|
45
|
+
*/
|
|
46
|
+
readonly animated?: boolean;
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* The flat vertex shader, built for one variant.
|
|
@@ -119,6 +125,21 @@ export interface FlatShaderOptions {
|
|
|
119
125
|
* the frame's materials' reflections. True when absent. See `reflectionSurfaceGlsl`.
|
|
120
126
|
*/
|
|
121
127
|
readonly reflectionMaps?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Whether it places a material's maps by the world, `uWorldUv` and all (`SurfaceMaterial
|
|
130
|
+
* .projection`). True when absent. See `worldUvGlsl`.
|
|
131
|
+
*/
|
|
132
|
+
readonly worldUvs?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Whether it reads the sun's moving layer through a matrix of its own, \`uMovingLightViewProj\`
|
|
135
|
+
* and all. True when absent. See \`movingSunGlsl\`.
|
|
136
|
+
*/
|
|
137
|
+
readonly movingSun?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Whether it blends a material's layers by a mask, \`uLayers\` and all (\`SurfaceMaterial.layers\`).
|
|
140
|
+
* True when absent. See \`layeredGlsl\`.
|
|
141
|
+
*/
|
|
142
|
+
readonly layered?: boolean;
|
|
122
143
|
/**
|
|
123
144
|
* How many point lights this build declares room for. `MAX_POINT_LIGHTS` when absent.
|
|
124
145
|
*
|
|
@@ -21,7 +21,12 @@ import { DRIFT_LIGHT_GLSL } from './driftLight.js';
|
|
|
21
21
|
import { SURFACE_EFFECTS_GLSL } from './surfaceEffects.js';
|
|
22
22
|
import { overlayGlsl } from './overlay.js';
|
|
23
23
|
import { reflectionSurfaceGlsl } from './reflectionSurface.js';
|
|
24
|
-
import {
|
|
24
|
+
import { worldUvGlsl } from './worldUv.js';
|
|
25
|
+
import { movingSunGlsl } from './movingSun.js';
|
|
26
|
+
import { layeredGlsl } from './layered.js';
|
|
27
|
+
import { MAP_READS_GLSL } from './mapReads.js';
|
|
28
|
+
import { CHANNEL_BEND, LIT_CHANNEL_ATTRIBUTE } from '../vertexChannel.js';
|
|
29
|
+
import { BONE_ANIMATION_GLSL } from '../boneAnimation.js';
|
|
25
30
|
import { FULL_LIGHT_BUDGET } from '../../uniformVectorBudget.js';
|
|
26
31
|
/**
|
|
27
32
|
* Flat-shaded vertex colours with one dominant directional source, ambient,
|
|
@@ -55,10 +60,16 @@ layout(location = 10) in vec4 aTangent;
|
|
|
55
60
|
${SKINNING_GLSL}
|
|
56
61
|
#endif
|
|
57
62
|
|
|
58
|
-
uniform mat4 uViewProj;
|
|
63
|
+
uniform mat4 uViewProj; // wgsl:view
|
|
59
64
|
/** 1 when the mesh carries a tangent frame. See vHasTangents. */
|
|
60
65
|
uniform int uHasTangents;
|
|
61
|
-
uniform mat4 uLightViewProj;
|
|
66
|
+
uniform mat4 uLightViewProj; // wgsl:view
|
|
67
|
+
/**
|
|
68
|
+
* The scene's clock, what \`setAnimationTime\` set: what a bone animation's instances read
|
|
69
|
+
* their moment from. In the view block, before the wind, so every variant's view block is the
|
|
70
|
+
* plain one's or a prefix of it — the instanced variant declares no wind and keeps this.
|
|
71
|
+
*/
|
|
72
|
+
uniform float uSceneTime; // wgsl:view
|
|
62
73
|
/**
|
|
63
74
|
* How often the surface texture repeats across this mesh's UV range, per axis.
|
|
64
75
|
*
|
|
@@ -121,6 +132,9 @@ layout(location = 15) in vec4 aInstanceTint;
|
|
|
121
132
|
* opacity of one. See lightmap.ts.
|
|
122
133
|
*/
|
|
123
134
|
const bool LIGHTMAP_REGIONS = false; // wgsl:override
|
|
135
|
+
#if ANIMATED
|
|
136
|
+
${BONE_ANIMATION_GLSL}
|
|
137
|
+
#endif
|
|
124
138
|
#else
|
|
125
139
|
uniform mat4 uModel;
|
|
126
140
|
/**
|
|
@@ -146,7 +160,7 @@ uniform vec3 uTint;
|
|
|
146
160
|
* agreeing about where the shared uniforms sit: the instanced variant drops these five along with
|
|
147
161
|
* the two above it, and a dropped field moves nothing. flatPass.ts asserts exactly that.
|
|
148
162
|
*/
|
|
149
|
-
${
|
|
163
|
+
${LIT_CHANNEL_ATTRIBUTE}
|
|
150
164
|
${CHANNEL_BEND}
|
|
151
165
|
#endif
|
|
152
166
|
|
|
@@ -244,6 +258,10 @@ void main() {
|
|
|
244
258
|
vec3 localNormal = aNormal;
|
|
245
259
|
vec3 localTangent = aTangent.xyz;
|
|
246
260
|
#endif
|
|
261
|
+
#if ANIMATED
|
|
262
|
+
/* The clip's turn and place, in the mesh's own space, before the instance places it. */
|
|
263
|
+
local = vec4(boneAnimate(local.xyz, localNormal, localTangent), 1.0);
|
|
264
|
+
#endif
|
|
247
265
|
#if INSTANCED
|
|
248
266
|
mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
|
|
249
267
|
/*
|
|
@@ -353,7 +371,15 @@ export function flatVert(options) {
|
|
|
353
371
|
throw new Error('flatVert: a variant cannot be both morphed and instanced — a morph weight is per draw, ' +
|
|
354
372
|
'so every instance of the batch would wear one expression between them.');
|
|
355
373
|
}
|
|
356
|
-
|
|
374
|
+
if (options.animated === true && !options.instanced) {
|
|
375
|
+
throw new Error('flatVert: a bone animation is played by an instanced variant alone.');
|
|
376
|
+
}
|
|
377
|
+
return resolveConditionals(FLAT_VERT_SOURCE, {
|
|
378
|
+
SKINNED: options.skinned,
|
|
379
|
+
MORPHED: options.morphed,
|
|
380
|
+
INSTANCED: options.instanced,
|
|
381
|
+
ANIMATED: options.animated === true,
|
|
382
|
+
}, 'flatVert');
|
|
357
383
|
}
|
|
358
384
|
/**
|
|
359
385
|
* The flat fragment shader, built for one quality profile.
|
|
@@ -439,6 +465,8 @@ export function flatFrag(options) {
|
|
|
439
465
|
surfaceEffects: options.surfaceEffects ?? true,
|
|
440
466
|
driftLight: options.driftLight ?? true,
|
|
441
467
|
}),
|
|
468
|
+
/* Depth zero and ahead of the sun's lookup, which calls it; its switch takes the next id. */
|
|
469
|
+
movingSunGlsl(options.movingSun ?? true),
|
|
442
470
|
LOBES_GLSL,
|
|
443
471
|
POINTSHADOW_GLSL,
|
|
444
472
|
DIRECTIONALSHADOW_GLSL,
|
|
@@ -464,8 +492,6 @@ export function flatFrag(options) {
|
|
|
464
492
|
* and `main` is unconditional by construction.
|
|
465
493
|
*/
|
|
466
494
|
TANGENT_FRAME_GLSL,
|
|
467
|
-
/* After the frame it calls, unconditional for the same reason. See normalMap.ts. */
|
|
468
|
-
NORMAL_MAP_GLSL,
|
|
469
495
|
/* Unconditional for the same reason, and called only where a cutoff was asked for. */
|
|
470
496
|
CUTOUT_COVERAGE_GLSL,
|
|
471
497
|
CUTOUT_DITHER_GLSL,
|
|
@@ -477,6 +503,15 @@ export function flatFrag(options) {
|
|
|
477
503
|
overlayGlsl(options.surfaceOverlay ?? true),
|
|
478
504
|
/* After the overlay, so its switch takes the next id. See reflectionSurface.ts. */
|
|
479
505
|
reflectionSurfaceGlsl(options.reflectionMaps ?? true),
|
|
506
|
+
/* After the reflection maps, so its switch takes the next id; main calls it. worldUv.ts. */
|
|
507
|
+
worldUvGlsl(options.worldUvs ?? true),
|
|
508
|
+
/* After the projection, so its switch takes the next id; the normal map below calls it. */
|
|
509
|
+
layeredGlsl(options.layered ?? true),
|
|
510
|
+
/* Where each map is read, after both of the ways it can be read otherwise. See mapReads.ts. */
|
|
511
|
+
MAP_READS_GLSL,
|
|
512
|
+
/* After the frame and the projection it calls, unconditional for the same reason as the
|
|
513
|
+
frame. See normalMap.ts. */
|
|
514
|
+
NORMAL_MAP_GLSL,
|
|
480
515
|
/* After the models, whose answer to a rectangle it asks for. See areaLight.ts. */
|
|
481
516
|
AREA_LIGHT_GLSL,
|
|
482
517
|
MAIN_GLSL,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A material blended from layers by a mask: `SurfaceMaterial.layers`, packed into `uLayers` by
|
|
3
|
+
* `surfaceLayers.ts`.
|
|
4
|
+
*
|
|
5
|
+
* **Layer `i` is layer `i` of the material's arrays**, each read at the mesh's coordinates times its
|
|
6
|
+
* own repeat; the mask is layer 0 of the map a shading model would read, at the mesh's coordinates.
|
|
7
|
+
* Each channel lays a layer over everything before it — red layer 1, green 2, blue 3, alpha 4 — so a
|
|
8
|
+
* layer's share is its channel times one less each later channel, and the base keeps what none of
|
|
9
|
+
* them took. Colour, roughness and occlusion are blended by those shares, and the normal map's
|
|
10
|
+
* tangent-space texels too, before the frame turns them into the world.
|
|
11
|
+
*
|
|
12
|
+
* **Every layer present is read, whatever its share.** A read whose level is implicit is legal only
|
|
13
|
+
* in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
|
|
14
|
+
* uniform, and never skips on a share, which is the pixel's own.
|
|
15
|
+
*
|
|
16
|
+
* **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
|
|
17
|
+
* it keeps its id. Compiled out, its two vectors are not declared and its calls are constants.
|
|
18
|
+
*/
|
|
19
|
+
export declare function layeredGlsl(on: boolean): string;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A material blended from layers by a mask: `SurfaceMaterial.layers`, packed into `uLayers` by
|
|
3
|
+
* `surfaceLayers.ts`.
|
|
4
|
+
*
|
|
5
|
+
* **Layer `i` is layer `i` of the material's arrays**, each read at the mesh's coordinates times its
|
|
6
|
+
* own repeat; the mask is layer 0 of the map a shading model would read, at the mesh's coordinates.
|
|
7
|
+
* Each channel lays a layer over everything before it — red layer 1, green 2, blue 3, alpha 4 — so a
|
|
8
|
+
* layer's share is its channel times one less each later channel, and the base keeps what none of
|
|
9
|
+
* them took. Colour, roughness and occlusion are blended by those shares, and the normal map's
|
|
10
|
+
* tangent-space texels too, before the frame turns them into the world.
|
|
11
|
+
*
|
|
12
|
+
* **Every layer present is read, whatever its share.** A read whose level is implicit is legal only
|
|
13
|
+
* in uniform control flow (AGENTS.md 2026-08-07), so the loop is bounded by the layer count, a
|
|
14
|
+
* uniform, and never skips on a share, which is the pixel's own.
|
|
15
|
+
*
|
|
16
|
+
* **A lit switch, `LAYERED`**, off until a material first asks, declared last so every switch before
|
|
17
|
+
* it keeps its id. Compiled out, its two vectors are not declared and its calls are constants.
|
|
18
|
+
*/
|
|
19
|
+
export function layeredGlsl(on) {
|
|
20
|
+
if (!on) {
|
|
21
|
+
return /* glsl */ `
|
|
22
|
+
const bool LAYERED = false; // wgsl:override
|
|
23
|
+
bool layered() { return false; }
|
|
24
|
+
void layeredBegin() {}
|
|
25
|
+
vec4 layeredAlbedo() { return vec4(1.0); }
|
|
26
|
+
vec3 layeredOrm() { return vec3(1.0); }
|
|
27
|
+
vec3 layeredTexel() { return vec3(0.0, 0.0, 1.0); }
|
|
28
|
+
bool layeredGlows() { return false; }
|
|
29
|
+
vec3 layeredEmissive() { return vec3(0.0); }
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
return /* glsl */ `
|
|
33
|
+
/* Whether this program blends a material's layers. Off but where one has asked: layered.ts. */
|
|
34
|
+
const bool LAYERED = true; // wgsl:override
|
|
35
|
+
/* The five repeats, base first (x y z w, then x), the count (y) and the glowing layer, or -1 (z). */
|
|
36
|
+
uniform vec4 uLayers[2]; // wgsl:material
|
|
37
|
+
|
|
38
|
+
/* The mask's channels that lay a layer, zero past the count: read once, in layeredBegin. */
|
|
39
|
+
vec4 lMask;
|
|
40
|
+
|
|
41
|
+
bool layered() {
|
|
42
|
+
return uLayers[1].y > 0.5;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* The mask, at the mesh's coordinates, where a model's map is. Under a branch on uniforms. */
|
|
46
|
+
void layeredBegin() {
|
|
47
|
+
vec4 m = texture(uModelMap, vec3(vUv.xy, 0.0));
|
|
48
|
+
float n = uLayers[1].y;
|
|
49
|
+
lMask = vec4(n > 1.5 ? m.r : 0.0, n > 2.5 ? m.g : 0.0, n > 3.5 ? m.b : 0.0, n > 4.5 ? m.a : 0.0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Layer i's share of this point: its channel, less every later layer's. */
|
|
53
|
+
float layerShare(int i) {
|
|
54
|
+
float keep = 1.0;
|
|
55
|
+
for (int j = 3; j >= 0; j--) {
|
|
56
|
+
if (j + 1 == i) return lMask[j] * keep;
|
|
57
|
+
keep *= 1.0 - lMask[j];
|
|
58
|
+
}
|
|
59
|
+
return keep;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
float layerRepeat(int i) {
|
|
63
|
+
return i < 4 ? uLayers[0][i] : uLayers[1].x;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
vec3 layerAt(int i) {
|
|
67
|
+
return vec3(vUv.xy * layerRepeat(i), float(i));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Colour by the shares, and the base layer's coverage, which a cutout reads. */
|
|
71
|
+
vec4 layeredAlbedo() {
|
|
72
|
+
vec4 sum = vec4(0.0);
|
|
73
|
+
for (int i = 0; i < 5; i++) {
|
|
74
|
+
if (float(i) >= uLayers[1].y) break;
|
|
75
|
+
vec4 t = texture(uAlbedo, layerAt(i));
|
|
76
|
+
sum.rgb += t.rgb * layerShare(i);
|
|
77
|
+
if (i == 0) sum.a = t.a;
|
|
78
|
+
}
|
|
79
|
+
return sum;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
vec3 layeredOrm() {
|
|
83
|
+
vec3 sum = vec3(0.0);
|
|
84
|
+
for (int i = 0; i < 5; i++) {
|
|
85
|
+
if (float(i) >= uLayers[1].y) break;
|
|
86
|
+
sum += texture(uOrmMap, layerAt(i)).rgb * layerShare(i);
|
|
87
|
+
}
|
|
88
|
+
return sum;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* The tangent-space texels blended, each with its z rebuilt where a two-channel map stored none. */
|
|
92
|
+
vec3 layeredTexel() {
|
|
93
|
+
vec3 sum = vec3(0.0);
|
|
94
|
+
for (int i = 0; i < 5; i++) {
|
|
95
|
+
if (float(i) >= uLayers[1].y) break;
|
|
96
|
+
vec3 t = texture(uNormalMap, layerAt(i)).xyz * 2.0 - 1.0;
|
|
97
|
+
t.z = t.z > 0.0 ? t.z : sqrt(max(0.0, 1.0 - dot(t.xy, t.xy)));
|
|
98
|
+
sum += t * layerShare(i);
|
|
99
|
+
}
|
|
100
|
+
float len = length(sum);
|
|
101
|
+
return len > 1e-5 ? sum / len : vec3(0.0, 0.0, 1.0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Whether the emissive map belongs to one layer rather than to the whole surface. */
|
|
105
|
+
bool layeredGlows() {
|
|
106
|
+
return uLayers[1].z > -0.5;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* The emissive map at its layer's place, glowing by that layer's share. */
|
|
110
|
+
vec3 layeredEmissive() {
|
|
111
|
+
int glow = int(uLayers[1].z + 0.5);
|
|
112
|
+
return texture(uEmissiveMap, layerAt(glow)).rgb * layerShare(glow);
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
}
|