@driftengine/core 4.4.2 → 4.5.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 +46 -0
- package/README.md +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -0
- package/dist/render/backend/api.d.ts +17 -11
- package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
- package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
- package/dist/render/backend/webgl2/renderer.d.ts +79 -8
- package/dist/render/backend/webgl2/renderer.js +360 -105
- package/dist/render/backend/webgpu/buffers.d.ts +19 -1
- package/dist/render/backend/webgpu/buffers.js +27 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
- package/dist/render/backend/webgpu/depthPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +2 -0
- package/dist/render/backend/webgpu/flatPass.js +20 -1
- package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
- package/dist/render/backend/webgpu/glassTintPass.js +205 -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/instanced.d.ts +12 -1
- package/dist/render/backend/webgpu/instanced.js +20 -1
- package/dist/render/backend/webgpu/latePass.d.ts +26 -0
- package/dist/render/backend/webgpu/latePass.js +133 -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 +2 -12
- package/dist/render/backend/webgpu/renderer.d.ts +171 -54
- package/dist/render/backend/webgpu/renderer.js +944 -390
- package/dist/render/backend/webgpu/scatterPass.js +2 -1
- 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 +5 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.js +1 -1
- 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/lightBudget.d.ts +17 -5
- package/dist/render/lightBudget.js +17 -5
- package/dist/render/pointGlassTint.d.ts +59 -0
- package/dist/render/pointGlassTint.js +198 -0
- 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/recon/changeFrames.d.ts +15 -0
- package/dist/render/recon/changeFrames.js +21 -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/renderQuality.d.ts +35 -0
- package/dist/render/renderQuality.js +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/sceneTarget.d.ts +7 -1
- package/dist/render/sceneTarget.js +58 -12
- package/dist/render/shaders/depth.d.ts +16 -1
- package/dist/render/shaders/depth.js +85 -9
- package/dist/render/shaders/flat/directionalShadow.js +91 -6
- 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 +4 -0
- 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 +115 -15
- 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 +21 -6
- package/dist/render/shaders/generated/depth.wgsl.d.ts +227 -4
- package/dist/render/shaders/generated/depth.wgsl.js +227 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +360 -312
- package/dist/render/shaders/generated/flat.wgsl.js +376 -328
- 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 +4 -14
- 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/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 +44 -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/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/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +15 -1
- package/package.json +6 -6
- package/src/index.ts +10 -0
- package/src/render/backend/api.ts +15 -9
- package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
- package/src/render/backend/webgl2/renderer.ts +401 -108
- package/src/render/backend/webgpu/buffers.ts +50 -2
- package/src/render/backend/webgpu/depthPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +22 -1
- package/src/render/backend/webgpu/glassTintPass.ts +244 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
- package/src/render/backend/webgpu/instanced.ts +21 -1
- package/src/render/backend/webgpu/latePass.ts +152 -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 +1108 -421
- package/src/render/backend/webgpu/scatterPass.ts +2 -1
- 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 +1 -1
- 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/lightBudget.ts +19 -5
- package/src/render/pointGlassTint.ts +250 -0
- package/src/render/pointShadowArray.ts +188 -22
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +12 -0
- package/src/render/sceneTarget.ts +58 -11
- package/src/render/shaders/depth.ts +109 -9
- package/src/render/shaders/flat/directionalShadow.ts +97 -6
- package/src/render/shaders/flat/glassTint.ts +25 -0
- package/src/render/shaders/flat/index.ts +17 -0
- package/src/render/shaders/flat/lampGlass.ts +185 -0
- package/src/render/shaders/flat/main.ts +115 -15
- package/src/render/shaders/flat/pointShadow.ts +2 -0
- package/src/render/shaders/flat/preamble.ts +21 -6
- package/src/render/shaders/generated/depth.wgsl.ts +234 -4
- package/src/render/shaders/generated/flat.wgsl.ts +376 -328
- package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
- package/src/render/shaders/generated/lightVolume.wgsl.ts +4 -14
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
- 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 +47 -0
- package/src/render/shaders/recon/motion.wgsl.ts +84 -0
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/translucentQueue.ts +20 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sun through glass for the device: `gpudriven/sunGlass.ts`'s `glassTintAt`, term for term, as
|
|
3
|
+
* the text the shading pass and the parity entry point both include.
|
|
4
|
+
*
|
|
5
|
+
* **The reads are the including module's**, as `SHADE_SHADOW_WGSL`'s are: `glassDepthAt(u, v)` the
|
|
6
|
+
* nearest pane's depth, `glassTintTexel(u, v)` the tint at the finest level, and
|
|
7
|
+
* `glassTintAround(u, v, radius)` the tint averaged over a spread of that radius. The shading pass
|
|
8
|
+
* answers the last from the tint's mip chain; the parity entry answers it with the reference's own
|
|
9
|
+
* box average, so everything around the reads is checked as it stands. Every constant is the
|
|
10
|
+
* reference's, interpolated rather than restated.
|
|
11
|
+
*/
|
|
12
|
+
import { FROST_RADIUS_CAP, FROST_SPREAD } from '../../glassShadow.ts';
|
|
13
|
+
import {
|
|
14
|
+
SHADOW_DEPTH_BIAS,
|
|
15
|
+
SHADOW_PCF_OFFSETS,
|
|
16
|
+
SHADOW_TEXEL_SCALE,
|
|
17
|
+
} from '../../gpudriven/shadow.ts';
|
|
18
|
+
import { SHADE_SHADOW_WGSL } from './shadow.wgsl.ts';
|
|
19
|
+
|
|
20
|
+
export const SUN_GLASS_WGSL = /* wgsl */ `
|
|
21
|
+
struct SunGlassSettings {
|
|
22
|
+
mapSize: f32,
|
|
23
|
+
depthSpan: f32,
|
|
24
|
+
uvPerMetre: f32,
|
|
25
|
+
taps: f32,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* A coarse texel with the open ground's white taken back out, by how milky the pane at the
|
|
30
|
+
* receiver is: the pane's colour and its share of the texel. glassShadow.ts's unmixTint.
|
|
31
|
+
*/
|
|
32
|
+
fn sunGlassUnmix(mip: vec4<f32>, centreClarity: f32) -> vec4<f32> {
|
|
33
|
+
if (centreClarity >= 1.0) { return vec4<f32>(mip.xyz, 1.0); }
|
|
34
|
+
let share = clamp((1.0 - mip.w) / (1.0 - centreClarity), 0.0, 1.0);
|
|
35
|
+
if (share <= 0.0) { return vec4<f32>(1.0, 1.0, 1.0, 0.0); }
|
|
36
|
+
let colour = clamp((mip.xyz - vec3<f32>(1.0 - share)) / share, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
37
|
+
return vec4<f32>(colour, share);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* What the sun keeps through glass at map position (u, v) and light depth "depth". */
|
|
41
|
+
fn sunGlass(u: f32, v: f32, depth: f32, settings: SunGlassSettings) -> vec3<f32> {
|
|
42
|
+
if (u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0) { return vec3<f32>(1.0); }
|
|
43
|
+
let texel = ${SHADOW_TEXEL_SCALE.toFixed(4)} / settings.mapSize;
|
|
44
|
+
let bias = ${SHADOW_DEPTH_BIAS.toFixed(4)} / settings.depthSpan;
|
|
45
|
+
let taps = min(u32(settings.taps), ${SHADOW_PCF_OFFSETS.length}u);
|
|
46
|
+
let clarity = glassTintTexel(u, v).w;
|
|
47
|
+
let behind = max(depth - glassDepthAt(u, v), 0.0) * settings.depthSpan;
|
|
48
|
+
let spread = (1.0 - clarity) * ${FROST_SPREAD.toFixed(6)} * behind * settings.uvPerMetre;
|
|
49
|
+
let radius = min(max(texel, spread), texel * ${FROST_RADIUS_CAP.toFixed(1)});
|
|
50
|
+
|
|
51
|
+
var cover = 0.0;
|
|
52
|
+
var colour = vec3<f32>(0.0);
|
|
53
|
+
var found = 0.0;
|
|
54
|
+
for (var i = 0u; i < taps; i = i + 1u) {
|
|
55
|
+
let offset = SHADOW_TAPS[i];
|
|
56
|
+
/* The outline: a tap counts the pane only where the receiver is behind it, by the bias. */
|
|
57
|
+
if (depth > glassDepthAt(u + offset.x * texel, v + offset.y * texel) + bias) {
|
|
58
|
+
cover = cover + 1.0;
|
|
59
|
+
}
|
|
60
|
+
/* The colour: the spread's taps, each an average, unmixed and weighed by the pane's share. */
|
|
61
|
+
let pane = sunGlassUnmix(glassTintAround(u + offset.x * radius, v + offset.y * radius, radius), clarity);
|
|
62
|
+
colour = colour + pane.xyz * pane.w;
|
|
63
|
+
found = found + pane.w;
|
|
64
|
+
}
|
|
65
|
+
let mixed = select(vec3<f32>(1.0), colour / max(found, 1e-6), found > 0.0);
|
|
66
|
+
return mix(vec3<f32>(1.0), mixed, cover / f32(max(taps, 1u)));
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `sunGlass` over maps held in storage buffers, read as the reference reads them, so the whole
|
|
72
|
+
* lookup can be compared with `glassTintAt` rather than only the arithmetic between the reads.
|
|
73
|
+
*
|
|
74
|
+
* Four floats a case in — u, v, the receiver's depth, one spare — and four out, the tint and one
|
|
75
|
+
* spare. The config is the map's size, the depth span, map units a metre, and the tap count.
|
|
76
|
+
*/
|
|
77
|
+
export const SUN_GLASS_PARITY_WGSL = /* wgsl */ `
|
|
78
|
+
@group(0) @binding(0) var<storage, read> depths: array<f32>;
|
|
79
|
+
@group(0) @binding(1) var<storage, read> tints: array<f32>;
|
|
80
|
+
@group(0) @binding(2) var<storage, read> cases: array<f32>;
|
|
81
|
+
@group(0) @binding(3) var<storage, read> config: array<f32>;
|
|
82
|
+
@group(0) @binding(4) var<storage, read_write> results: array<f32>;
|
|
83
|
+
|
|
84
|
+
/* The opaque lookup's own read, which this entry never calls: included only for its tap table. */
|
|
85
|
+
fn shadowDepthAt(u: f32, v: f32) -> f32 { return 1.0; }
|
|
86
|
+
${SHADE_SHADOW_WGSL}
|
|
87
|
+
|
|
88
|
+
fn glassIndex(u: f32, v: f32) -> u32 {
|
|
89
|
+
let size = config[0];
|
|
90
|
+
let x = u32(clamp(floor(u * size), 0.0, size - 1.0));
|
|
91
|
+
let y = u32(clamp(floor(v * size), 0.0, size - 1.0));
|
|
92
|
+
return y * u32(size) + x;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn glassDepthAt(u: f32, v: f32) -> f32 {
|
|
96
|
+
return depths[glassIndex(u, v)];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
|
|
100
|
+
let at = glassIndex(u, v) * 4u;
|
|
101
|
+
return vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* The reference's coarse read: the average of every texel within the radius. */
|
|
105
|
+
fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
|
|
106
|
+
let size = config[0];
|
|
107
|
+
let reach = radius * size;
|
|
108
|
+
let x0 = u32(max(0.0, floor(u * size - reach)));
|
|
109
|
+
let x1 = u32(min(size - 1.0, floor(u * size + reach)));
|
|
110
|
+
let y0 = u32(max(0.0, floor(v * size - reach)));
|
|
111
|
+
let y1 = u32(min(size - 1.0, floor(v * size + reach)));
|
|
112
|
+
var sum = vec4<f32>(0.0);
|
|
113
|
+
var n = 0.0;
|
|
114
|
+
for (var y = y0; y <= y1; y = y + 1u) {
|
|
115
|
+
for (var x = x0; x <= x1; x = x + 1u) {
|
|
116
|
+
let at = (y * u32(size) + x) * 4u;
|
|
117
|
+
sum = sum + vec4<f32>(tints[at], tints[at + 1u], tints[at + 2u], tints[at + 3u]);
|
|
118
|
+
n = n + 1.0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return sum / max(n, 1.0);
|
|
122
|
+
}
|
|
123
|
+
${SUN_GLASS_WGSL}
|
|
124
|
+
|
|
125
|
+
@compute @workgroup_size(64)
|
|
126
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
127
|
+
if (id.x * 4u + 3u >= arrayLength(&cases)) { return; }
|
|
128
|
+
var settings: SunGlassSettings;
|
|
129
|
+
settings.mapSize = config[0];
|
|
130
|
+
settings.depthSpan = config[1];
|
|
131
|
+
settings.uvPerMetre = config[2];
|
|
132
|
+
settings.taps = config[3];
|
|
133
|
+
let at = id.x * 4u;
|
|
134
|
+
let tint = sunGlass(cases[at], cases[at + 1u], cases[at + 2u], settings);
|
|
135
|
+
results[at] = tint.x;
|
|
136
|
+
results[at + 1u] = tint.y;
|
|
137
|
+
results[at + 2u] = tint.z;
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
* halves of one frame disagreeing about the same light.
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
|
+
import { SUN_DYNAMIC_LAYER, SUN_PEELED_LAYER, SUN_STATIC_LAYER } from '../shadowMap.ts';
|
|
50
51
|
import { resolveConditionals } from './conditionals.ts';
|
|
51
52
|
|
|
52
53
|
export const LIGHT_VOLUME_VERT = `#version 300 es
|
|
@@ -159,9 +160,8 @@ uniform vec3 uDustOffset;
|
|
|
159
160
|
uniform float uSunShadow;
|
|
160
161
|
uniform mat4 uLightViewProj;
|
|
161
162
|
uniform float uShadowMapSize;
|
|
162
|
-
|
|
163
|
-
uniform
|
|
164
|
-
uniform sampler2D uDynamicShadowMap;
|
|
163
|
+
/* The sun's static, moving and peeled maps, as layers of one array: see shadowMap.ts. */
|
|
164
|
+
uniform highp sampler2DArray uSunShadows;
|
|
165
165
|
uniform int uPeeledShadowEnabled;
|
|
166
166
|
#endif
|
|
167
167
|
|
|
@@ -324,11 +324,11 @@ float sunReach(vec3 worldPos) {
|
|
|
324
324
|
if (edgeFade <= 0.0) return 1.0;
|
|
325
325
|
|
|
326
326
|
float compare = p.z - BIAS;
|
|
327
|
-
float blocked = occlusion(textureLod(
|
|
327
|
+
float blocked = occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_STATIC_LAYER}.0), 0.0).r, compare);
|
|
328
328
|
if (uPeeledShadowEnabled != 0) {
|
|
329
|
-
blocked = max(blocked, occlusion(textureLod(
|
|
329
|
+
blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_PEELED_LAYER}.0), 0.0).r, compare));
|
|
330
330
|
}
|
|
331
|
-
blocked = max(blocked, occlusion(textureLod(
|
|
331
|
+
blocked = max(blocked, occlusion(textureLod(uSunShadows, vec3(p.xy, ${SUN_DYNAMIC_LAYER}.0), 0.0).r, compare));
|
|
332
332
|
return mix(1.0, 1.0 - blocked, uSunShadow * edgeFade);
|
|
333
333
|
}
|
|
334
334
|
#endif
|
|
@@ -12,6 +12,30 @@ void main() {
|
|
|
12
12
|
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
|
|
13
13
|
}`;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Which cube face owns this octahedral texel, and where in that face it looks: `d`, `forward` and
|
|
17
|
+
* `faceUv`, with every texel another face owns discarded. **One text for both resolves**, depth
|
|
18
|
+
* and tint, because the tie-breaking has to agree with itself as well as with the CPU: a sliver
|
|
19
|
+
* of texels given to one face's depth and another face's colour is a tinted seam.
|
|
20
|
+
*/
|
|
21
|
+
const FACE_REGION = ` vec3 d = octDecode(gl_FragCoord.xy / uEdge);
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* Which face owns this texel. The tie-breaking is x, then y, then z, and it has to match the
|
|
25
|
+
* CPU's exactly or a sliver of texels along a boundary belongs to two faces or to none.
|
|
26
|
+
*/
|
|
27
|
+
vec3 a = abs(d);
|
|
28
|
+
int face;
|
|
29
|
+
if (a.x >= a.y && a.x >= a.z) face = d.x >= 0.0 ? 0 : 1;
|
|
30
|
+
else if (a.y >= a.z) face = d.y >= 0.0 ? 2 : 3;
|
|
31
|
+
else face = d.z >= 0.0 ? 4 : 5;
|
|
32
|
+
if (face != uFaceIndex) discard;
|
|
33
|
+
|
|
34
|
+
/* lookAt looks down -z, so a direction inside this face has a negative z here. */
|
|
35
|
+
vec3 v = uFaceRotation * d;
|
|
36
|
+
float forward = -v.z;
|
|
37
|
+
vec2 faceUv = (v.xy / forward) * 0.5 + 0.5;`;
|
|
38
|
+
|
|
15
39
|
/**
|
|
16
40
|
* One cube face into its region of an octahedral map, as linear radial distance.
|
|
17
41
|
*
|
|
@@ -46,23 +70,7 @@ uniform float uEdge;
|
|
|
46
70
|
${OCTAHEDRAL_GLSL}
|
|
47
71
|
|
|
48
72
|
void main() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/*
|
|
52
|
-
* Which face owns this texel. The tie-breaking is x, then y, then z, and it has to match the
|
|
53
|
-
* CPU's exactly or a sliver of texels along a boundary belongs to two faces or to none.
|
|
54
|
-
*/
|
|
55
|
-
vec3 a = abs(d);
|
|
56
|
-
int face;
|
|
57
|
-
if (a.x >= a.y && a.x >= a.z) face = d.x >= 0.0 ? 0 : 1;
|
|
58
|
-
else if (a.y >= a.z) face = d.y >= 0.0 ? 2 : 3;
|
|
59
|
-
else face = d.z >= 0.0 ? 4 : 5;
|
|
60
|
-
if (face != uFaceIndex) discard;
|
|
61
|
-
|
|
62
|
-
/* lookAt looks down -z, so a direction inside this face has a negative z here. */
|
|
63
|
-
vec3 v = uFaceRotation * d;
|
|
64
|
-
float forward = -v.z;
|
|
65
|
-
vec2 faceUv = (v.xy / forward) * 0.5 + 0.5;
|
|
73
|
+
${FACE_REGION}
|
|
66
74
|
|
|
67
75
|
/*
|
|
68
76
|
* textureLod at level zero rather than plain texture. The scratch carries one storage level and
|
|
@@ -81,3 +89,28 @@ void main() {
|
|
|
81
89
|
/* d is a unit vector, so forward is its cosine to the axis and this is the true radius. */
|
|
82
90
|
gl_FragDepth = clamp((faceLocalZ / forward) / uFar, 0.0, 1.0);
|
|
83
91
|
}`;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* One face of a lamp's glass tint into its region of the tint layer: the depth resolve's region,
|
|
95
|
+
* and a colour copied rather than a depth decoded.
|
|
96
|
+
*
|
|
97
|
+
* **Nearest, at level zero**, like the depth beside it: the tint's outline has to land on the
|
|
98
|
+
* glass depth's texels, and a filtered copy would smear a pane's colour a texel past its edge.
|
|
99
|
+
*/
|
|
100
|
+
export const OCTAHEDRAL_RESOLVE_TINT_FRAG = `#version 300 es
|
|
101
|
+
precision highp float;
|
|
102
|
+
|
|
103
|
+
/** The face the bake just tinted, as colour. */
|
|
104
|
+
uniform highp sampler2D uFace;
|
|
105
|
+
uniform mat3 uFaceRotation;
|
|
106
|
+
uniform int uFaceIndex;
|
|
107
|
+
uniform float uEdge;
|
|
108
|
+
|
|
109
|
+
out vec4 outTint;
|
|
110
|
+
|
|
111
|
+
${OCTAHEDRAL_GLSL}
|
|
112
|
+
|
|
113
|
+
void main() {
|
|
114
|
+
${FACE_REGION}
|
|
115
|
+
outTint = textureLod(uFace, faceUv, 0.0);
|
|
116
|
+
}`;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The render's depth, taken up to the output size for the draws that land after the upscale.
|
|
3
|
+
*
|
|
4
|
+
* **The nearest of the four render texels around each output pixel**, so a translucent draw is
|
|
5
|
+
* never let through an opaque edge the render did cover. What it gives up: where a translucent
|
|
6
|
+
* surface crosses an opaque silhouette, the edge steps at the render's resolution.
|
|
7
|
+
*
|
|
8
|
+
* Hand-written, and built by concatenation rather than a template literal: the reconstruction's
|
|
9
|
+
* passes have no WebGL2 twin (the AGENTS.md exception for them), and a `${}` inside WGSL source is
|
|
10
|
+
* the thing that rule forbids.
|
|
11
|
+
*/
|
|
12
|
+
import { REVERSED_DEPTH } from '../../depthConvention.ts';
|
|
13
|
+
|
|
14
|
+
/** The nearer of two stored depths: the larger in a reversed buffer. */
|
|
15
|
+
const NEARER = REVERSED_DEPTH ? 'max' : 'min';
|
|
16
|
+
/** Where the search for the nearest starts: the far plane. */
|
|
17
|
+
const FARTHEST = REVERSED_DEPTH ? '0.0' : '1.0';
|
|
18
|
+
|
|
19
|
+
export const LATE_DEPTH_WGSL =
|
|
20
|
+
'@group(0) @binding(0) var source: texture_depth_2d;\n' +
|
|
21
|
+
'@group(0) @binding(1) var<uniform> sizes: vec4<f32>;\n' +
|
|
22
|
+
'\n' +
|
|
23
|
+
'@vertex\n' +
|
|
24
|
+
'fn lateDepthVert(@builtin(vertex_index) index: u32) -> @builtin(position) vec4<f32> {\n' +
|
|
25
|
+
' let x = f32((index << 1u) & 2u);\n' +
|
|
26
|
+
' let y = f32(index & 2u);\n' +
|
|
27
|
+
' return vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0);\n' +
|
|
28
|
+
'}\n' +
|
|
29
|
+
'\n' +
|
|
30
|
+
'@fragment\n' +
|
|
31
|
+
'fn lateDepthFrag(@builtin(position) at: vec4<f32>) -> @builtin(frag_depth) f32 {\n' +
|
|
32
|
+
' let centre = at.xy * sizes.xy / sizes.zw - vec2<f32>(0.5);\n' +
|
|
33
|
+
' let base = vec2<i32>(floor(centre));\n' +
|
|
34
|
+
' let top = vec2<i32>(sizes.xy) - vec2<i32>(1);\n' +
|
|
35
|
+
' var nearest = ' +
|
|
36
|
+
FARTHEST +
|
|
37
|
+
';\n' +
|
|
38
|
+
' for (var y = 0; y < 2; y += 1) {\n' +
|
|
39
|
+
' for (var x = 0; x < 2; x += 1) {\n' +
|
|
40
|
+
' let texel = clamp(base + vec2<i32>(x, y), vec2<i32>(0), top);\n' +
|
|
41
|
+
' nearest = ' +
|
|
42
|
+
NEARER +
|
|
43
|
+
'(nearest, textureLoad(source, texel, 0));\n' +
|
|
44
|
+
' }\n' +
|
|
45
|
+
' }\n' +
|
|
46
|
+
' return nearest;\n' +
|
|
47
|
+
'}\n';
|
|
@@ -88,6 +88,90 @@ fn motionUv(clip: vec4<f32>) -> vec2<f32> {
|
|
|
88
88
|
return clip.xy / clip.w * 0.5 + vec2<f32>(0.5);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/*
|
|
92
|
+
* The skinned stage: the joints this frame and last frame, read from two palette textures of the
|
|
93
|
+
* frame's ring. The same four weighted products in the same order as the scene's own skinning, so
|
|
94
|
+
* the depth this stage produces is the depth the scene wrote.
|
|
95
|
+
*/
|
|
96
|
+
@group(1) @binding(0) var palette: texture_2d<f32>;
|
|
97
|
+
@group(1) @binding(1) var previousPalette: texture_2d<f32>;
|
|
98
|
+
|
|
99
|
+
fn jointOf(source: texture_2d<f32>, index: i32) -> mat4x4<f32> {
|
|
100
|
+
let x = index * 4;
|
|
101
|
+
return mat4x4<f32>(
|
|
102
|
+
textureLoad(source, vec2<i32>(x, 0), 0),
|
|
103
|
+
textureLoad(source, vec2<i32>(x + 1, 0), 0),
|
|
104
|
+
textureLoad(source, vec2<i32>(x + 2, 0), 0),
|
|
105
|
+
textureLoad(source, vec2<i32>(x + 3, 0), 0));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fn skinOf(source: texture_2d<f32>, joints: vec4<f32>, weights: vec4<f32>) -> mat4x4<f32> {
|
|
109
|
+
return jointOf(source, i32(joints.x)) * weights.x
|
|
110
|
+
+ jointOf(source, i32(joints.y)) * weights.y
|
|
111
|
+
+ jointOf(source, i32(joints.z)) * weights.z
|
|
112
|
+
+ jointOf(source, i32(joints.w)) * weights.w;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@vertex
|
|
116
|
+
fn motionSkinnedVert(
|
|
117
|
+
@location(0) position: vec3<f32>,
|
|
118
|
+
@location(11) joints: vec4<f32>,
|
|
119
|
+
@location(12) weights: vec4<f32>,
|
|
120
|
+
) -> Varyings {
|
|
121
|
+
let world = draw.model * (skinOf(palette, joints, weights) * vec4<f32>(position, 1.0));
|
|
122
|
+
let wasWorld =
|
|
123
|
+
draw.previousModel * (skinOf(previousPalette, joints, weights) * vec4<f32>(position, 1.0));
|
|
124
|
+
var out: Varyings;
|
|
125
|
+
out.clip = frame.raster * world;
|
|
126
|
+
out.now = frame.viewProj * world;
|
|
127
|
+
out.was = frame.previousViewProj * wasWorld;
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* The rewritten stage: a mesh whose vertices were rewritten this frame reads last frame's rows from
|
|
133
|
+
* a second buffer of the same stride, so each vertex carries both of its positions.
|
|
134
|
+
*/
|
|
135
|
+
@vertex
|
|
136
|
+
fn motionDynamicVert(
|
|
137
|
+
@location(0) position: vec3<f32>,
|
|
138
|
+
@location(1) previousPosition: vec3<f32>,
|
|
139
|
+
) -> Varyings {
|
|
140
|
+
let world = draw.model * vec4<f32>(position, 1.0);
|
|
141
|
+
let wasWorld = draw.previousModel * vec4<f32>(previousPosition, 1.0);
|
|
142
|
+
var out: Varyings;
|
|
143
|
+
out.clip = frame.raster * world;
|
|
144
|
+
out.now = frame.viewProj * world;
|
|
145
|
+
out.was = frame.previousViewProj * wasWorld;
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/*
|
|
150
|
+
* The instanced stage: each instance's matrix this frame and last frame, read from the batch's
|
|
151
|
+
* placement and the copy of last frame's it kept. Slot for slot, so an instance is paired with
|
|
152
|
+
* itself; the per-draw matrices are not read.
|
|
153
|
+
*/
|
|
154
|
+
@vertex
|
|
155
|
+
fn motionInstancedVert(
|
|
156
|
+
@location(0) position: vec3<f32>,
|
|
157
|
+
@location(2) m0: vec4<f32>,
|
|
158
|
+
@location(3) m1: vec4<f32>,
|
|
159
|
+
@location(4) m2: vec4<f32>,
|
|
160
|
+
@location(5) m3: vec4<f32>,
|
|
161
|
+
@location(6) p0: vec4<f32>,
|
|
162
|
+
@location(7) p1: vec4<f32>,
|
|
163
|
+
@location(8) p2: vec4<f32>,
|
|
164
|
+
@location(9) p3: vec4<f32>,
|
|
165
|
+
) -> Varyings {
|
|
166
|
+
let world = mat4x4<f32>(m0, m1, m2, m3) * vec4<f32>(position, 1.0);
|
|
167
|
+
let wasWorld = mat4x4<f32>(p0, p1, p2, p3) * vec4<f32>(position, 1.0);
|
|
168
|
+
var out: Varyings;
|
|
169
|
+
out.clip = frame.raster * world;
|
|
170
|
+
out.now = frame.viewProj * world;
|
|
171
|
+
out.was = frame.previousViewProj * wasWorld;
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
91
175
|
@fragment
|
|
92
176
|
fn motionFrag(in: Varyings) -> @location(0) vec4<f32> {
|
|
93
177
|
/*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveGlass, type GlassOptions, type ResolvedGlass } from './glass.ts';
|
|
1
2
|
import type { ReadonlyMat4 } from 'gl-matrix';
|
|
2
3
|
import type { InstanceData } from './instancedMesh.ts';
|
|
3
4
|
import type { InstancedHandle, MeshHandle, ScatterHandle } from './backend/api.ts';
|
|
@@ -41,7 +42,33 @@ import type { SurfaceTextureHandle } from './backend/api.ts';
|
|
|
41
42
|
* outwards, so a required parameter added in a minor stops every consumer's sink and every test
|
|
42
43
|
* double compiling. A sink that ignores it behaves exactly as it did.
|
|
43
44
|
*/
|
|
44
|
-
export type SceneCasterMaterial =
|
|
45
|
+
export type SceneCasterMaterial =
|
|
46
|
+
| (SurfaceMaterial<SurfaceTextureHandle> & {
|
|
47
|
+
/**
|
|
48
|
+
* The caster is glass: it lets light through, so it writes no depth into any shadow map and a
|
|
49
|
+
* lamp behind it lights what is beyond. The colour replay into a mirror or a probe still draws
|
|
50
|
+
* it. With `RenderQuality.glassShadows` on it casts a coloured shadow instead: see
|
|
51
|
+
* `glassShadow.ts`.
|
|
52
|
+
*/
|
|
53
|
+
readonly glass?: GlassOptions;
|
|
54
|
+
})
|
|
55
|
+
| null;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether a caster writes depth into a shadow map: everything but glass. One line in each depth
|
|
59
|
+
* sink, so the answer is the same in every shadow a backend draws.
|
|
60
|
+
*/
|
|
61
|
+
export function castsDepth(material: SceneCasterMaterial | undefined): boolean {
|
|
62
|
+
return (material?.glass?.transmission ?? 0) <= 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The caster's glass, resolved into `out`, and whether it is glass at all — the rule `castsDepth`
|
|
67
|
+
* states from the other side, so a caster is exactly one of the two.
|
|
68
|
+
*/
|
|
69
|
+
export function glassOf(material: SceneCasterMaterial | undefined, out: ResolvedGlass): boolean {
|
|
70
|
+
return resolveGlass(material?.glass, out);
|
|
71
|
+
}
|
|
45
72
|
|
|
46
73
|
export interface ShadowCasterSink {
|
|
47
74
|
/** A rigid mesh at a model transform: the world, a prop, a static piece of scenery. */
|