@driftengine/core 4.4.1 → 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 +72 -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 +82 -8
- package/dist/render/backend/webgl2/renderer.js +373 -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 +21 -15
- package/dist/render/backend/webgpu/postPass.js +17 -4
- package/dist/render/backend/webgpu/renderer.d.ts +181 -54
- package/dist/render/backend/webgpu/renderer.js +1011 -394
- 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/flameLight.js +15 -2
- 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/pointShadowBudget.js +51 -41
- 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/disocclusion.d.ts +36 -3
- package/dist/render/recon/disocclusion.js +56 -4
- 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.js +95 -12
- 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 +9 -1
- package/dist/render/sceneTarget.js +59 -13
- 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/generated/temporalResolve.wgsl.d.ts +31 -6
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +31 -6
- 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/shaders/recon/resolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/resolve.wgsl.js +112 -8
- package/dist/render/shaders/temporalResolve.js +133 -5
- 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/temporalAa.d.ts +145 -0
- package/dist/render/temporalAa.js +190 -0
- package/dist/render/temporalPass.d.ts +16 -14
- package/dist/render/temporalPass.js +59 -14
- 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 +422 -109
- 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/postPass.ts +34 -4
- package/src/render/backend/webgpu/renderer.ts +1178 -425
- 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/flameLight.ts +15 -2
- 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/pointShadowBudget.ts +49 -39
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/disocclusion.ts +54 -3
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/recon/resolve.ts +137 -10
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +12 -0
- package/src/render/sceneTarget.ts +66 -12
- 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/generated/temporalResolve.wgsl.ts +31 -6
- 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/shaders/recon/resolve.wgsl.ts +112 -8
- package/src/render/shaders/temporalResolve.ts +141 -5
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/temporalAa.ts +227 -0
- package/src/render/temporalPass.ts +88 -12
- package/src/render/translucentQueue.ts +20 -1
|
@@ -38,8 +38,10 @@ struct Material {
|
|
|
38
38
|
maps: vec4<f32>,
|
|
39
39
|
/** Roughness scale, metallic scale, the alpha cutoff, and non-zero where this one blends. */
|
|
40
40
|
orm: vec4<f32>,
|
|
41
|
-
/** The blended opacity, and
|
|
41
|
+
/** The blended opacity, the glass's transmission and frost, and one spare. */
|
|
42
42
|
extra: vec4<f32>,
|
|
43
|
+
/** The glass's tint, white where the material is not glass, and one spare. */
|
|
44
|
+
glassTint: vec4<f32>,
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const NO_PROGRAM: u32 = ${DECODE_NO_PROGRAM}u;
|
|
@@ -8,6 +8,7 @@ import { MATERIAL_SLOTS, MATERIAL_TABLE_WGSL } from './materialTable.wgsl.ts';
|
|
|
8
8
|
import { MESH_TRANSFORM_WGSL } from './meshTransform.wgsl.ts';
|
|
9
9
|
import { ENVIRONMENT_WGSL } from './environment.wgsl.ts';
|
|
10
10
|
import { SHADE_SHADOW_WGSL } from './shadow.wgsl.ts';
|
|
11
|
+
import { SUN_GLASS_WGSL } from './sunGlass.wgsl.ts';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Rebuilding a pixel's surface from the triangle it recorded, on the device.
|
|
@@ -514,6 +515,14 @@ struct Job {
|
|
|
514
515
|
@group(0) @binding(12) var environmentMap: texture_2d_array<f32>;
|
|
515
516
|
@group(0) @binding(13) var environmentSampler: sampler;
|
|
516
517
|
${decodeResourcesWgsl({ group: 0, latents: 14, clampSampler: 15, repeatSampler: 16, nodes: 17, weights: 18 })}
|
|
518
|
+
/*
|
|
519
|
+
* **What the sun keeps through glass: the nearest pane's depth and what the panes let through**,
|
|
520
|
+
* which the pass draws from the sun after its opaque map. Where no material is glass the depth is
|
|
521
|
+
* the opaque map again and the tint a single white texel, which sunGlassAt reads as none.
|
|
522
|
+
*/
|
|
523
|
+
@group(0) @binding(19) var glassDepthMap: texture_depth_2d;
|
|
524
|
+
@group(0) @binding(20) var glassTints: texture_2d<f32>;
|
|
525
|
+
@group(0) @binding(21) var glassSampler: sampler;
|
|
517
526
|
|
|
518
527
|
fn decodeLatentSize() -> f32 {
|
|
519
528
|
return frame.size.w;
|
|
@@ -545,6 +554,45 @@ fn shadowDepthAt(u: f32, v: f32) -> f32 {
|
|
|
545
554
|
return textureLoad(shadowMap, vec2<i32>(x, y), 0);
|
|
546
555
|
}
|
|
547
556
|
${SHADE_SHADOW_WGSL}
|
|
557
|
+
|
|
558
|
+
/* sunGlass.wgsl.ts's three reads, as the opaque map is read: nearest by integer coordinate. */
|
|
559
|
+
fn glassDepthAt(u: f32, v: f32) -> f32 {
|
|
560
|
+
let size = frame.shadow.y;
|
|
561
|
+
let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
|
|
562
|
+
let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
|
|
563
|
+
return textureLoad(glassDepthMap, vec2<i32>(x, y), 0);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
fn glassTintTexel(u: f32, v: f32) -> vec4<f32> {
|
|
567
|
+
let size = f32(textureDimensions(glassTints, 0).x);
|
|
568
|
+
let x = i32(clamp(floor(u * size), 0.0, size - 1.0));
|
|
569
|
+
let y = i32(clamp(floor(v * size), 0.0, size - 1.0));
|
|
570
|
+
return textureLoad(glassTints, vec2<i32>(x, y), 0);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* The tint over a spread, from the chain: the level whose texel is the spread's width. */
|
|
574
|
+
fn glassTintAround(u: f32, v: f32, radius: f32) -> vec4<f32> {
|
|
575
|
+
let size = f32(textureDimensions(glassTints, 0).x);
|
|
576
|
+
return textureSampleLevel(glassTints, glassSampler, vec2<f32>(u, v), log2(max(radius * size, 1.0)));
|
|
577
|
+
}
|
|
578
|
+
${SUN_GLASS_WGSL}
|
|
579
|
+
|
|
580
|
+
/*
|
|
581
|
+
* The sun's colour at this receiver after the panes between it and the sun: white where no glass
|
|
582
|
+
* cast, and faded with the opaque shadow's own strength. The map's scale in metres comes off the
|
|
583
|
+
* light's matrix, which is orthographic: a compute invocation has no derivatives to take it from.
|
|
584
|
+
*/
|
|
585
|
+
fn sunGlassAt(lightPos: vec3<f32>) -> vec3<f32> {
|
|
586
|
+
if (textureDimensions(glassTints, 0).x <= 1u || frame.shadow.x <= 0.0) { return vec3<f32>(1.0); }
|
|
587
|
+
let m = frame.lightViewProj;
|
|
588
|
+
var settings: SunGlassSettings;
|
|
589
|
+
settings.mapSize = frame.shadow.y;
|
|
590
|
+
settings.depthSpan = frame.shadow.z;
|
|
591
|
+
settings.uvPerMetre = 0.5 * length(vec3<f32>(m[0][0], m[1][0], m[2][0]));
|
|
592
|
+
settings.taps = frame.shadowLimits.y;
|
|
593
|
+
let tint = sunGlass(lightPos.x * 0.5 + 0.5, lightPos.y * 0.5 + 0.5, lightPos.z, settings);
|
|
594
|
+
return mix(vec3<f32>(1.0), tint, frame.shadow.x);
|
|
595
|
+
}
|
|
548
596
|
${ENVIRONMENT_WGSL}
|
|
549
597
|
${FOG_WGSL}
|
|
550
598
|
|
|
@@ -737,7 +785,8 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
737
785
|
|
|
738
786
|
var room: LitEnvironment;
|
|
739
787
|
room.lightDir = frame.lightDir.xyz;
|
|
740
|
-
|
|
788
|
+
/* The sun's colour through whatever glass stands between it and here, as flat/main.ts's is. */
|
|
789
|
+
room.lightColour = frame.lightColour.xyz * sunGlassAt(lightPos);
|
|
741
790
|
room.sky = frame.sky.xyz;
|
|
742
791
|
room.ground = frame.ground.xyz;
|
|
743
792
|
/*
|
|
@@ -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
|
/*
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
* and the uniform `recon: ReconParams`, whose struct this module declares.
|
|
40
40
|
*/
|
|
41
41
|
import { wgslSceneDepthToNdc } from '../../depthConvention.ts';
|
|
42
|
+
import { PLANAR_FROM, PLANAR_TO } from '../../recon/disocclusion.ts';
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
45
|
* The parameters one resolve reads, as `ResolveFrame` minus its images.
|
|
@@ -97,6 +98,8 @@ export const RECON_HISTORY_FORMAT: GPUTextureFormat = 'rgba16float';
|
|
|
97
98
|
export const RECON_RESOLVE_CORE_WGSL = /* wgsl */ `
|
|
98
99
|
const RECON_SAMPLE_SPREAD: f32 = ${RECON_SAMPLE_SPREAD};
|
|
99
100
|
const RECON_CONFIDENT_WEIGHT: f32 = ${RECON_CONFIDENT_WEIGHT}.0;
|
|
101
|
+
const RECON_PLANAR_FROM: f32 = ${PLANAR_FROM};
|
|
102
|
+
const RECON_PLANAR_TO: f32 = ${PLANAR_TO};
|
|
100
103
|
|
|
101
104
|
fn reconClampTexel(value: i32, size: i32) -> i32 {
|
|
102
105
|
return clamp(value, 0, size - 1);
|
|
@@ -328,10 +331,11 @@ fn reconDisocclusion(
|
|
|
328
331
|
histDepth: f32,
|
|
329
332
|
motionLength: f32,
|
|
330
333
|
normalDot: f32,
|
|
334
|
+
slope: f32,
|
|
331
335
|
) -> f32 {
|
|
332
336
|
if (!(currDepth > 0.0) || !(histDepth > 0.0) || !(motionLength >= 0.0)) { return 0.0; }
|
|
333
337
|
let disagreement = abs(currDepth - histDepth) / currDepth;
|
|
334
|
-
let tolerance = recon.depthTolerance + recon.motionScale * motionLength;
|
|
338
|
+
let tolerance = recon.depthTolerance + recon.motionScale * motionLength + slope;
|
|
335
339
|
let depth = 1.0 - reconSmoothstep(tolerance, 2.0 * tolerance, disagreement);
|
|
336
340
|
let normal = reconSmoothstep(recon.normalFloor, recon.normalCeiling, normalDot);
|
|
337
341
|
return depth * normal;
|
|
@@ -392,6 +396,74 @@ fn reconNormalAt(previous: bool, x: i32, y: i32) -> ReconNormal {
|
|
|
392
396
|
return reconNormalFrom(centre.position, right.position, up.position, eye);
|
|
393
397
|
}
|
|
394
398
|
|
|
399
|
+
/* resolve.ts's viewDepthAt. */
|
|
400
|
+
fn reconViewDepthAt(previous: bool, x: i32, y: i32) -> f32 {
|
|
401
|
+
let w = i32(recon.renderSize.x);
|
|
402
|
+
let h = i32(recon.renderSize.y);
|
|
403
|
+
if (x < 0 || y < 0 || x >= w || y >= h) { return 0.0; }
|
|
404
|
+
var jitter = recon.jitter;
|
|
405
|
+
var m = recon.inverseViewProj;
|
|
406
|
+
var z = 0.0;
|
|
407
|
+
if (previous) {
|
|
408
|
+
jitter = recon.previousJitter;
|
|
409
|
+
m = recon.previousInverseViewProj;
|
|
410
|
+
z = reconPreviousDepth(x, y);
|
|
411
|
+
} else {
|
|
412
|
+
z = reconDepth(x, y);
|
|
413
|
+
}
|
|
414
|
+
let u = (f32(x) + 0.5 - jitter.x) / f32(w);
|
|
415
|
+
let v = (f32(y) + 0.5 - jitter.y) / f32(h);
|
|
416
|
+
let cw = m[0][3] * (u * 2.0 - 1.0) + m[1][3] * (v * 2.0 - 1.0) + m[2][3] * z + m[3][3];
|
|
417
|
+
if (!(abs(cw) > 1e-12)) { return 0.0; }
|
|
418
|
+
return 1.0 / cw;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* disocclusion.ts's planarity. */
|
|
422
|
+
fn reconPlanarity(before: f32, centre: f32, after: f32) -> f32 {
|
|
423
|
+
if (!(before > 0.0) || !(centre > 0.0) || !(after > 0.0)) { return 1.0; }
|
|
424
|
+
let a = 1.0 / after - 1.0 / centre;
|
|
425
|
+
let b = 1.0 / before - 1.0 / centre;
|
|
426
|
+
let spread = abs(a) + abs(b);
|
|
427
|
+
if (!(spread > 0.0)) { return 1.0; }
|
|
428
|
+
return 1.0 - reconSmoothstep(RECON_PLANAR_FROM, RECON_PLANAR_TO, abs(a + b) / spread);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/* disocclusion.ts's surfaceSlope. */
|
|
432
|
+
fn reconSurfaceSlope(before: f32, centre: f32, after: f32) -> f32 {
|
|
433
|
+
let hasAfter = after > 0.0;
|
|
434
|
+
let hasBefore = before > 0.0;
|
|
435
|
+
if (!hasAfter) {
|
|
436
|
+
if (!hasBefore) { return 0.0; }
|
|
437
|
+
return abs(before - centre) / centre;
|
|
438
|
+
}
|
|
439
|
+
if (!hasBefore) { return abs(after - centre) / centre; }
|
|
440
|
+
let a = after - centre;
|
|
441
|
+
let b = before - centre;
|
|
442
|
+
if (a * b > 0.0) { return 0.0; }
|
|
443
|
+
return min(abs(a), abs(b)) / centre;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
struct ReconSurface {
|
|
447
|
+
planar: f32,
|
|
448
|
+
slope: f32,
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* resolve.ts's surfaceAt. */
|
|
452
|
+
fn reconSurfaceAt(previous: bool, x: i32, y: i32, centre: f32) -> ReconSurface {
|
|
453
|
+
var out: ReconSurface;
|
|
454
|
+
out.planar = 1.0;
|
|
455
|
+
out.slope = 0.0;
|
|
456
|
+
for (var axis = 0; axis < 2; axis = axis + 1) {
|
|
457
|
+
let ax = 1 - axis;
|
|
458
|
+
let ay = axis;
|
|
459
|
+
let after = reconViewDepthAt(previous, x + ax, y + ay);
|
|
460
|
+
let before = reconViewDepthAt(previous, x - ax, y - ay);
|
|
461
|
+
out.planar = out.planar * reconPlanarity(before, centre, after);
|
|
462
|
+
out.slope = max(out.slope, reconSurfaceSlope(before, centre, after));
|
|
463
|
+
}
|
|
464
|
+
return out;
|
|
465
|
+
}
|
|
466
|
+
|
|
395
467
|
struct ReconHistory {
|
|
396
468
|
weight: f32,
|
|
397
469
|
colour: vec4<f32>,
|
|
@@ -439,14 +511,46 @@ fn reconHistoryWeight(u: f32, v: f32, dx: i32, dy: i32) -> ReconHistory {
|
|
|
439
511
|
pu * f32(recon.outputSize.x) - 0.5,
|
|
440
512
|
pv * f32(recon.outputSize.y) - 0.5,
|
|
441
513
|
);
|
|
442
|
-
|
|
443
|
-
let
|
|
444
|
-
let
|
|
514
|
+
/* Last frame's depth, searched around where the dilated texel was: see resolve.ts. */
|
|
515
|
+
let su = (f32(dx) + 0.5 - recon.jitter.x) / rw + mu;
|
|
516
|
+
let sv = (f32(dy) + 0.5 - recon.jitter.y) / rh + mv;
|
|
517
|
+
let cx = reconClampTexel(i32(reconRound(su * rw + recon.previousJitter.x - 0.5)), i32(rw));
|
|
518
|
+
let cy = reconClampTexel(i32(reconRound(sv * rh + recon.previousJitter.y - 0.5)), i32(rh));
|
|
519
|
+
var held = reconViewDepthAt(true, cx, cy);
|
|
520
|
+
var px = cx;
|
|
521
|
+
var py = cy;
|
|
522
|
+
if (!(held > 0.0 && abs(held - expected) <= recon.depthTolerance * expected)) {
|
|
523
|
+
held = 0.0;
|
|
524
|
+
var nearest = 3.4e38;
|
|
525
|
+
for (var j = -1; j <= 1; j = j + 1) {
|
|
526
|
+
for (var i = -1; i <= 1; i = i + 1) {
|
|
527
|
+
let tx = reconClampTexel(cx + i, i32(rw));
|
|
528
|
+
let ty = reconClampTexel(cy + j, i32(rh));
|
|
529
|
+
let depth = reconViewDepthAt(true, tx, ty);
|
|
530
|
+
if (!(depth > 0.0)) { continue; }
|
|
531
|
+
let off = abs(depth - expected);
|
|
532
|
+
if (off < nearest) {
|
|
533
|
+
nearest = off;
|
|
534
|
+
held = depth;
|
|
535
|
+
px = tx;
|
|
536
|
+
py = ty;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
let here = reconSurfaceAt(false, dx, dy, reconViewDepthAt(false, dx, dy));
|
|
543
|
+
var planar = here.planar;
|
|
544
|
+
if (planar > 0.0) { planar = planar * reconSurfaceAt(true, px, py, held).planar; }
|
|
445
545
|
var normalDot = 1.0;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
546
|
+
if (planar > 0.0) {
|
|
547
|
+
let hereNormal = reconNormalAt(false, dx, dy);
|
|
548
|
+
let thereNormal = reconNormalAt(true, px, py);
|
|
549
|
+
if (hereNormal.ok && thereNormal.ok) {
|
|
550
|
+
normalDot = 1.0 - planar * (1.0 - dot(hereNormal.normal, thereNormal.normal));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
let trust = reconDisocclusion(expected, held, length(vec2<f32>(mu, mv)), normalDot, here.slope);
|
|
450
554
|
out.weight = out.colour.w * trust;
|
|
451
555
|
return out;
|
|
452
556
|
}
|