@driftengine/core 4.8.6 → 4.9.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 +132 -0
- package/README.md +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +8 -1
- package/dist/render/anisotropicLobe.d.ts +10 -0
- package/dist/render/anisotropicLobe.js +19 -0
- package/dist/render/areaLights.d.ts +35 -0
- package/dist/render/areaLights.js +35 -0
- package/dist/render/atmosphere.d.ts +13 -0
- package/dist/render/atmosphere.js +9 -1
- package/dist/render/backend/api.d.ts +41 -3
- package/dist/render/backend/createRenderer.d.ts +6 -0
- package/dist/render/backend/createRenderer.js +4 -1
- package/dist/render/backend/webgl2/renderer.d.ts +140 -16
- package/dist/render/backend/webgl2/renderer.js +436 -44
- package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
- package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
- package/dist/render/backend/webgpu/device.d.ts +7 -1
- package/dist/render/backend/webgpu/device.js +31 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +16 -1
- package/dist/render/backend/webgpu/flatPass.js +58 -26
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/postPass.d.ts +51 -9
- package/dist/render/backend/webgpu/postPass.js +16 -2
- package/dist/render/backend/webgpu/reflectionSurfacePass.d.ts +30 -0
- package/dist/render/backend/webgpu/reflectionSurfacePass.js +100 -0
- package/dist/render/backend/webgpu/renderer.d.ts +166 -3
- package/dist/render/backend/webgpu/renderer.js +738 -83
- package/dist/render/backend/webgpu/sceneCaptureTarget.d.ts +24 -0
- package/dist/render/backend/webgpu/sceneCaptureTarget.js +59 -0
- package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +1 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +34 -8
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/clusteredLights.d.ts +23 -5
- package/dist/render/clusteredLights.js +35 -8
- package/dist/render/displayRange.d.ts +31 -0
- package/dist/render/displayRange.js +47 -0
- package/dist/render/driftLight/bake.d.ts +2 -0
- package/dist/render/driftLight/bake.js +1 -1
- package/dist/render/driftLight/falloff.d.ts +4 -2
- package/dist/render/driftLight/falloff.js +8 -2
- package/dist/render/filmicCurve.d.ts +74 -0
- package/dist/render/filmicCurve.js +203 -0
- package/dist/render/fog.d.ts +4 -1
- package/dist/render/fog.js +12 -2
- package/dist/render/frame/resources.d.ts +2 -2
- package/dist/render/frame/resources.js +6 -0
- package/dist/render/frameReflections.d.ts +40 -0
- package/dist/render/frameReflections.js +48 -0
- package/dist/render/gi/bounceLights.d.ts +3 -2
- package/dist/render/gi/bounceLights.js +8 -3
- package/dist/render/instanceCull.js +5 -0
- package/dist/render/instances.d.ts +19 -5
- package/dist/render/instances.js +9 -3
- package/dist/render/lightBudget.d.ts +12 -1
- package/dist/render/lightBudget.js +23 -3
- package/dist/render/lightmap.d.ts +23 -9
- package/dist/render/lightmap.js +40 -18
- package/dist/render/particlePool.d.ts +21 -0
- package/dist/render/particlePool.js +7 -0
- package/dist/render/pass.d.ts +49 -0
- package/dist/render/pointLightSelection.d.ts +13 -0
- package/dist/render/pointLightSelection.js +3 -1
- package/dist/render/reflectionSurfaceTargets.d.ts +28 -0
- package/dist/render/reflectionSurfaceTargets.js +99 -0
- package/dist/render/renderQuality.d.ts +47 -15
- package/dist/render/renderQuality.js +4 -0
- package/dist/render/rendererHarness.js +3 -0
- package/dist/render/rgb9e5.d.ts +22 -0
- package/dist/render/rgb9e5.js +47 -0
- package/dist/render/sceneCapture.d.ts +29 -0
- package/dist/render/sceneCapture.js +36 -0
- package/dist/render/sceneTarget.d.ts +5 -0
- package/dist/render/sceneTarget.js +24 -1
- package/dist/render/screenSpaceReflection.d.ts +32 -1
- package/dist/render/screenSpaceReflection.js +14 -0
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +7 -1
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/depth.js +11 -0
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/filmLook.js +2 -1
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/flat/anisotropic.d.ts +1 -1
- package/dist/render/shaders/flat/anisotropic.js +37 -3
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +46 -0
- package/dist/render/shaders/flat/glassTint.d.ts +3 -2
- package/dist/render/shaders/flat/glassTint.js +5 -1
- package/dist/render/shaders/flat/index.d.ts +15 -0
- package/dist/render/shaders/flat/index.js +22 -2
- package/dist/render/shaders/flat/lobes.d.ts +6 -0
- package/dist/render/shaders/flat/lobes.js +49 -43
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +85 -22
- package/dist/render/shaders/flat/models.d.ts +5 -2
- package/dist/render/shaders/flat/models.js +100 -16
- package/dist/render/shaders/flat/overlay.d.ts +16 -0
- package/dist/render/shaders/flat/overlay.js +117 -0
- package/dist/render/shaders/flat/pointShadow.js +1 -1
- package/dist/render/shaders/flat/preamble.js +10 -3
- package/dist/render/shaders/flat/reflectionSurface.d.ts +21 -0
- package/dist/render/shaders/flat/reflectionSurface.js +61 -0
- package/dist/render/shaders/fog.d.ts +1 -1
- package/dist/render/shaders/fog.js +9 -2
- package/dist/render/shaders/fringe.d.ts +29 -0
- package/dist/render/shaders/fringe.js +55 -0
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/bolt.wgsl.js +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/caustics.wgsl.js +1 -1
- package/dist/render/shaders/generated/depth.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/depth.wgsl.js +4 -4
- package/dist/render/shaders/generated/film.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/film.wgsl.js +1 -1
- package/dist/render/shaders/generated/fire.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/fire.wgsl.js +1 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +192 -16
- package/dist/render/shaders/generated/flat.wgsl.js +230 -54
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/particle.wgsl.js +4 -4
- package/dist/render/shaders/generated/rush.wgsl.d.ts +56 -26
- package/dist/render/shaders/generated/rush.wgsl.js +56 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/scatter.wgsl.js +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +1 -1
- package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/ssrResolve.wgsl.js +29 -0
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +32 -7
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +32 -7
- package/dist/render/shaders/generated/water.wgsl.d.ts +23 -16
- package/dist/render/shaders/generated/water.wgsl.js +23 -16
- package/dist/render/shaders/gi/probeBake.wgsl.js +9 -5
- package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +2 -2
- package/dist/render/shaders/gpudriven/fog.wgsl.js +11 -3
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +13 -2
- package/dist/render/shaders/rush.js +54 -11
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/ssrResolve.d.ts +17 -0
- package/dist/render/shaders/ssrResolve.js +51 -0
- package/dist/render/shaders/ssrTrace.js +46 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -3
- package/dist/render/skinScatter.d.ts +3 -1
- package/dist/render/skinScatter.js +3 -1
- package/dist/render/ssrPass.d.ts +16 -0
- package/dist/render/ssrPass.js +107 -1
- package/dist/render/surfaceModel.d.ts +29 -8
- package/dist/render/surfaceModel.js +33 -9
- package/dist/render/surfaceOverlay.d.ts +132 -0
- package/dist/render/surfaceOverlay.js +85 -0
- package/dist/render/surfaceTexture.d.ts +44 -1
- package/dist/render/surfaceTexture.js +96 -5
- package/dist/render/temporalAa.d.ts +14 -0
- package/dist/render/temporalAa.js +20 -0
- package/dist/render/vertexDefaults.d.ts +17 -0
- package/dist/render/vertexDefaults.js +24 -0
- package/package.json +6 -6
- package/src/index.ts +22 -2
- package/src/render/anisotropicLobe.ts +29 -0
- package/src/render/areaLights.ts +58 -0
- package/src/render/atmosphere.ts +22 -1
- package/src/render/backend/api.ts +58 -2
- package/src/render/backend/createRenderer.ts +18 -1
- package/src/render/backend/webgl2/renderer.ts +548 -50
- package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
- package/src/render/backend/webgpu/device.ts +42 -3
- package/src/render/backend/webgpu/flatPass.ts +63 -26
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +18 -0
- package/src/render/backend/webgpu/reflectionSurfacePass.ts +114 -0
- package/src/render/backend/webgpu/renderer.ts +927 -100
- package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +44 -14
- package/src/render/clusteredLights.ts +41 -8
- package/src/render/displayRange.ts +61 -0
- package/src/render/driftLight/bake.ts +3 -1
- package/src/render/driftLight/falloff.ts +13 -2
- package/src/render/filmicCurve.ts +229 -0
- package/src/render/fog.ts +19 -3
- package/src/render/frame/resources.ts +6 -0
- package/src/render/frameReflections.ts +72 -0
- package/src/render/gi/bounceLights.ts +12 -3
- package/src/render/instanceCull.ts +4 -0
- package/src/render/instances.ts +26 -6
- package/src/render/lightBudget.ts +40 -2
- package/src/render/lightmap.ts +64 -23
- package/src/render/particlePool.ts +23 -0
- package/src/render/pass.ts +53 -1
- package/src/render/pointLightSelection.ts +20 -1
- package/src/render/reflectionSurfaceTargets.ts +105 -0
- package/src/render/renderQuality.ts +52 -15
- package/src/render/rendererHarness.ts +3 -0
- package/src/render/rgb9e5.ts +52 -0
- package/src/render/sceneCapture.ts +56 -0
- package/src/render/sceneTarget.ts +30 -2
- package/src/render/screenSpaceReflection.ts +38 -1
- package/src/render/shaders/bolt.ts +7 -1
- package/src/render/shaders/depth.ts +11 -0
- package/src/render/shaders/filmLook.ts +2 -1
- package/src/render/shaders/flat/anisotropic.ts +37 -3
- package/src/render/shaders/flat/areaLight.ts +46 -0
- package/src/render/shaders/flat/glassTint.ts +13 -2
- package/src/render/shaders/flat/index.ts +37 -2
- package/src/render/shaders/flat/lobes.ts +50 -43
- package/src/render/shaders/flat/main.ts +85 -22
- package/src/render/shaders/flat/models.ts +100 -16
- package/src/render/shaders/flat/overlay.ts +117 -0
- package/src/render/shaders/flat/pointShadow.ts +1 -1
- package/src/render/shaders/flat/preamble.ts +10 -3
- package/src/render/shaders/flat/reflectionSurface.ts +61 -0
- package/src/render/shaders/fog.ts +9 -2
- package/src/render/shaders/fringe.ts +59 -0
- package/src/render/shaders/generated/arcane.wgsl.ts +1 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/caustics.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +4 -4
- package/src/render/shaders/generated/film.wgsl.ts +1 -1
- package/src/render/shaders/generated/fire.wgsl.ts +1 -1
- package/src/render/shaders/generated/flat.wgsl.ts +230 -54
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +4 -4
- package/src/render/shaders/generated/rush.wgsl.ts +56 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +1 -1
- package/src/render/shaders/generated/smoke.wgsl.ts +1 -1
- package/src/render/shaders/generated/ssrResolve.wgsl.ts +30 -0
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +32 -7
- package/src/render/shaders/generated/water.wgsl.ts +23 -16
- package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
- package/src/render/shaders/gpudriven/fog.wgsl.ts +11 -3
- package/src/render/shaders/recon/motion.wgsl.ts +13 -2
- package/src/render/shaders/rush.ts +54 -11
- package/src/render/shaders/ssrResolve.ts +52 -0
- package/src/render/shaders/ssrTrace.ts +46 -1
- package/src/render/shaders/water.ts +12 -3
- package/src/render/skinScatter.ts +3 -1
- package/src/render/ssrPass.ts +139 -1
- package/src/render/surfaceModel.ts +47 -10
- package/src/render/surfaceOverlay.ts +195 -0
- package/src/render/surfaceTexture.ts +136 -9
- package/src/render/temporalAa.ts +20 -0
- package/src/render/vertexDefaults.ts +28 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { glSceneDepthFormat } from '../../depthConvention.ts';
|
|
2
|
+
import type { SurfaceTexture } from '../../surfaceTexture.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A scene capture's framebuffers on WebGL2: the capture's own texture as the colour a pass resolves
|
|
6
|
+
* into, and a depth of its own, at the capture's size. See `sceneCapture.ts` for what a capture is.
|
|
7
|
+
*
|
|
8
|
+
* **At the frame's sample count, as WebGPU's is**, so a capture's edges are antialiased exactly as
|
|
9
|
+
* the frame's are: drawn into multisampled renderbuffers and blitted into the texture at the end,
|
|
10
|
+
* since a texture layer cannot be multisampled and sampled both. A count the driver refuses falls
|
|
11
|
+
* back to one, as the scene target's does, rather than drawing nothing.
|
|
12
|
+
*/
|
|
13
|
+
export class GlSceneCaptureTarget {
|
|
14
|
+
/** Where the capture resolves: its texture's layer, and a depth when it is drawn into directly. */
|
|
15
|
+
private readonly resolveFramebuffer: WebGLFramebuffer;
|
|
16
|
+
private readonly resolveDepth: WebGLRenderbuffer;
|
|
17
|
+
/** Where it is drawn above one sample, or null. */
|
|
18
|
+
private multisampleFramebuffer: WebGLFramebuffer | null = null;
|
|
19
|
+
private multisampleColor: WebGLRenderbuffer | null = null;
|
|
20
|
+
private multisampleDepth: WebGLRenderbuffer | null = null;
|
|
21
|
+
/** False where the driver refused the attachment, said once by the renderer. */
|
|
22
|
+
readonly usable: boolean;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
gl: WebGL2RenderingContext,
|
|
26
|
+
texture: SurfaceTexture,
|
|
27
|
+
readonly width: number,
|
|
28
|
+
readonly height: number,
|
|
29
|
+
samples: number,
|
|
30
|
+
float: boolean,
|
|
31
|
+
) {
|
|
32
|
+
const depthFormat = glSceneDepthFormat(gl).internalFormat;
|
|
33
|
+
this.resolveFramebuffer = must(gl.createFramebuffer());
|
|
34
|
+
this.resolveDepth = must(gl.createRenderbuffer());
|
|
35
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, this.resolveDepth);
|
|
36
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, depthFormat, width, height);
|
|
37
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.resolveFramebuffer);
|
|
38
|
+
texture.attachColor(gl);
|
|
39
|
+
gl.framebufferRenderbuffer(
|
|
40
|
+
gl.FRAMEBUFFER,
|
|
41
|
+
gl.DEPTH_ATTACHMENT,
|
|
42
|
+
gl.RENDERBUFFER,
|
|
43
|
+
this.resolveDepth,
|
|
44
|
+
);
|
|
45
|
+
this.usable = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
|
|
46
|
+
|
|
47
|
+
const maximum = gl.getParameter(gl.MAX_SAMPLES) as number;
|
|
48
|
+
const count = Math.max(
|
|
49
|
+
1,
|
|
50
|
+
Math.min(Math.round(samples), Number.isFinite(maximum) ? maximum : 1),
|
|
51
|
+
);
|
|
52
|
+
if (this.usable && count > 1) {
|
|
53
|
+
const color = must(gl.createRenderbuffer());
|
|
54
|
+
const depth = must(gl.createRenderbuffer());
|
|
55
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, color);
|
|
56
|
+
gl.renderbufferStorageMultisample(
|
|
57
|
+
gl.RENDERBUFFER,
|
|
58
|
+
count,
|
|
59
|
+
float ? gl.RGBA16F : gl.RGBA8,
|
|
60
|
+
width,
|
|
61
|
+
height,
|
|
62
|
+
);
|
|
63
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, depth);
|
|
64
|
+
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, count, depthFormat, width, height);
|
|
65
|
+
const framebuffer = must(gl.createFramebuffer());
|
|
66
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
67
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, color);
|
|
68
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depth);
|
|
69
|
+
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
|
|
70
|
+
this.multisampleFramebuffer = framebuffer;
|
|
71
|
+
this.multisampleColor = color;
|
|
72
|
+
this.multisampleDepth = depth;
|
|
73
|
+
} else {
|
|
74
|
+
gl.deleteFramebuffer(framebuffer);
|
|
75
|
+
gl.deleteRenderbuffer(color);
|
|
76
|
+
gl.deleteRenderbuffer(depth);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
80
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Bind where the pass draws, size the viewport and clear: colour to `clear`, depth to `depthClear`. */
|
|
84
|
+
begin(
|
|
85
|
+
gl: WebGL2RenderingContext,
|
|
86
|
+
clear: readonly [number, number, number],
|
|
87
|
+
depthClear: number,
|
|
88
|
+
): void {
|
|
89
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.multisampleFramebuffer ?? this.resolveFramebuffer);
|
|
90
|
+
gl.viewport(0, 0, this.width, this.height);
|
|
91
|
+
gl.clearColor(clear[0], clear[1], clear[2], 1);
|
|
92
|
+
gl.clearDepth(depthClear);
|
|
93
|
+
gl.depthMask(true);
|
|
94
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Resolve the multisampled colour into the texture, where there is any. */
|
|
98
|
+
end(gl: WebGL2RenderingContext): void {
|
|
99
|
+
if (this.multisampleFramebuffer === null) return;
|
|
100
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.multisampleFramebuffer);
|
|
101
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.resolveFramebuffer);
|
|
102
|
+
gl.blitFramebuffer(
|
|
103
|
+
0,
|
|
104
|
+
0,
|
|
105
|
+
this.width,
|
|
106
|
+
this.height,
|
|
107
|
+
0,
|
|
108
|
+
0,
|
|
109
|
+
this.width,
|
|
110
|
+
this.height,
|
|
111
|
+
gl.COLOR_BUFFER_BIT,
|
|
112
|
+
gl.NEAREST,
|
|
113
|
+
);
|
|
114
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
|
|
115
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
dispose(gl: WebGL2RenderingContext): void {
|
|
119
|
+
gl.deleteFramebuffer(this.resolveFramebuffer);
|
|
120
|
+
gl.deleteRenderbuffer(this.resolveDepth);
|
|
121
|
+
if (this.multisampleFramebuffer !== null) gl.deleteFramebuffer(this.multisampleFramebuffer);
|
|
122
|
+
if (this.multisampleColor !== null) gl.deleteRenderbuffer(this.multisampleColor);
|
|
123
|
+
if (this.multisampleDepth !== null) gl.deleteRenderbuffer(this.multisampleDepth);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function must<T>(made: T | null): T {
|
|
128
|
+
if (made === null) throw new Error('GlSceneCaptureTarget: a GL object could not be created');
|
|
129
|
+
return made;
|
|
130
|
+
}
|
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
* reset the page did not cause, and a frame is wrong because of something the frame did.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { DisplayRange, DisplayRangeChoice } from '../../displayRange.ts';
|
|
11
|
+
|
|
12
|
+
/** A canvas nobody asked to extend. */
|
|
13
|
+
const STANDARD_RANGE: DisplayRangeChoice = {
|
|
14
|
+
range: 'standard',
|
|
15
|
+
reason: 'highDynamicRange was not asked for',
|
|
16
|
+
};
|
|
17
|
+
|
|
10
18
|
/** What the renderer needs from the canvas it draws into, with the API's shape absorbed. */
|
|
11
19
|
export interface GpuSurface {
|
|
12
20
|
readonly device: GPUDevice;
|
|
@@ -22,6 +30,9 @@ export interface GpuSurface {
|
|
|
22
30
|
readonly canvas: HTMLCanvasElement;
|
|
23
31
|
/** The swap chain's format, which every render pipeline has to be built against. */
|
|
24
32
|
readonly format: GPUTextureFormat;
|
|
33
|
+
/** The range the canvas was configured in, and why. See `displayRange.ts`. */
|
|
34
|
+
readonly displayRange: DisplayRange;
|
|
35
|
+
readonly displayRangeReason: string;
|
|
25
36
|
/** Whether the device has gone. Read per frame; never throws. */
|
|
26
37
|
readonly lost: boolean;
|
|
27
38
|
/** Called when the device is lost. Fires immediately if it already has been. */
|
|
@@ -51,13 +62,27 @@ export interface GpuSurface {
|
|
|
51
62
|
* consumer its GPU had failed every time it unmounted a canvas on purpose, so a disposed
|
|
52
63
|
* surface stays silent.
|
|
53
64
|
*/
|
|
54
|
-
export function createGpuSurface(
|
|
65
|
+
export function createGpuSurface(
|
|
66
|
+
canvas: HTMLCanvasElement,
|
|
67
|
+
device: GPUDevice,
|
|
68
|
+
/** The range the profile and the display allow (`chooseDisplayRange`); standard unless given. */
|
|
69
|
+
wanted: DisplayRangeChoice = STANDARD_RANGE,
|
|
70
|
+
): GpuSurface {
|
|
55
71
|
const context = canvas.getContext('webgpu') as GPUCanvasContext | null;
|
|
56
72
|
if (context === null) {
|
|
57
73
|
throw new Error('createGpuSurface: the canvas would not give a webgpu context');
|
|
58
74
|
}
|
|
59
75
|
|
|
60
|
-
|
|
76
|
+
/*
|
|
77
|
+
* **A high range is half floats with extended tone mapping**: a value of 1 is the display's
|
|
78
|
+
* paper white, and what lies above it is shown up to the display's peak instead of clipped. The
|
|
79
|
+
* colour space stays sRGB, so the composite's encoding is the one it always wrote, carried past 1.
|
|
80
|
+
*/
|
|
81
|
+
const extended = wanted.range === 'high';
|
|
82
|
+
const format: GPUTextureFormat = extended
|
|
83
|
+
? 'rgba16float'
|
|
84
|
+
: navigator.gpu.getPreferredCanvasFormat();
|
|
85
|
+
let range: DisplayRangeChoice = wanted;
|
|
61
86
|
const listeners: (() => void)[] = [];
|
|
62
87
|
let lost = false;
|
|
63
88
|
let disposed = false;
|
|
@@ -115,16 +140,30 @@ export function createGpuSurface(canvas: HTMLCanvasElement, device: GPUDevice):
|
|
|
115
140
|
* has no use for a transparent canvas, and the opaque path is the one a compositor can
|
|
116
141
|
* take without a blend.
|
|
117
142
|
*/
|
|
118
|
-
context.configure(
|
|
143
|
+
context.configure(
|
|
144
|
+
extended
|
|
145
|
+
? { device, format, alphaMode: 'opaque', toneMapping: { mode: 'extended' } }
|
|
146
|
+
: { device, format, alphaMode: 'opaque' },
|
|
147
|
+
);
|
|
119
148
|
};
|
|
120
149
|
|
|
121
150
|
configure(canvas.width, canvas.height);
|
|
151
|
+
/*
|
|
152
|
+
* **Read back, because a browser that does not know the option ignores it** and draws the
|
|
153
|
+
* standard range from an extended-range frame, clipped at paper white, which is the frame a game
|
|
154
|
+
* would grade for the standard range if it knew. So it is told.
|
|
155
|
+
*/
|
|
156
|
+
if (extended && context.getConfiguration?.()?.toneMapping?.mode !== 'extended') {
|
|
157
|
+
range = { range: 'standard', reason: 'this browser has no extended-range canvas' };
|
|
158
|
+
}
|
|
122
159
|
|
|
123
160
|
return {
|
|
124
161
|
device,
|
|
125
162
|
context,
|
|
126
163
|
canvas,
|
|
127
164
|
format,
|
|
165
|
+
displayRange: range.range,
|
|
166
|
+
displayRangeReason: range.reason,
|
|
128
167
|
get lost() {
|
|
129
168
|
return lost;
|
|
130
169
|
},
|
|
@@ -12,6 +12,7 @@ import type { LitSwitch, PipelineCache } from './pipelineCache.ts';
|
|
|
12
12
|
import type { ClothViews } from './clothTextures.ts';
|
|
13
13
|
import { shaderModule } from './shaderModules.ts';
|
|
14
14
|
import { SCENE_ALPHA_COVERS } from '../../sceneCoverage.ts';
|
|
15
|
+
import { REFLECTION_SURFACE_FORMAT } from './reflectionSurfacePass.ts';
|
|
15
16
|
|
|
16
17
|
/** The material maps the flat pass reads: `2d-array` colour, filtered, not shadow maps. */
|
|
17
18
|
const SURFACE_MAPS: ReadonlySet<string> = new Set([
|
|
@@ -232,6 +233,26 @@ export const FLAT_VERT_SIZE = Math.max(
|
|
|
232
233
|
);
|
|
233
234
|
const FLAT_VERT_BINDING = PLAIN_VERTEX.uniforms;
|
|
234
235
|
|
|
236
|
+
/**
|
|
237
|
+
* The most sampled textures and distinct samplers any lit variant carrying the environment probe
|
|
238
|
+
* binds in its fragment stage, counted from the generated bindings: what a device must allow per
|
|
239
|
+
* stage before the probe's permutation can be built. A sampler several textures share counts once,
|
|
240
|
+
* which is what `// wgsl:share` buys.
|
|
241
|
+
*/
|
|
242
|
+
export function probeStageCeilings(): { readonly textures: number; readonly samplers: number } {
|
|
243
|
+
let textures = 0;
|
|
244
|
+
let samplers = 0;
|
|
245
|
+
for (const [variant, bindings] of Object.entries(FLAT_BINDINGS.flatFrag)) {
|
|
246
|
+
if (!variant.includes('environmentProbe')) continue;
|
|
247
|
+
const listed = Object.values(
|
|
248
|
+
(bindings as { textures?: Record<string, { sampler: number }> }).textures ?? {},
|
|
249
|
+
);
|
|
250
|
+
textures = Math.max(textures, listed.length);
|
|
251
|
+
samplers = Math.max(samplers, new Set(listed.map((entry) => entry.sampler)).size);
|
|
252
|
+
}
|
|
253
|
+
return { textures, samplers };
|
|
254
|
+
}
|
|
255
|
+
|
|
235
256
|
/** Everything the generator recorded about one permutation of the fragment stage. */
|
|
236
257
|
export function flatFragmentBindings(variant: FlatVariant): StageBindings {
|
|
237
258
|
const found = FRAGMENT_BINDINGS[variant];
|
|
@@ -253,6 +274,7 @@ function flatFragmentConstants(
|
|
|
253
274
|
cache: PipelineCache,
|
|
254
275
|
model: SurfaceModelKind | null,
|
|
255
276
|
skinPass: SkinHalf = 'whole',
|
|
277
|
+
reflectionSurface = false,
|
|
256
278
|
): Record<string, number> {
|
|
257
279
|
const overrides = flatFragmentBindings(variant).overrides;
|
|
258
280
|
if (overrides?.['GLASS_SHADOWS'] === undefined) {
|
|
@@ -271,6 +293,11 @@ function flatFragmentConstants(
|
|
|
271
293
|
constants[String(id)] = skinPass !== 'whole' && name === SKIN_HALF_SWITCH[skinPass] ? 1 : 0;
|
|
272
294
|
continue;
|
|
273
295
|
}
|
|
296
|
+
/* The reflection pass's surface half, set from the key too. See `reflectionSurface.ts`. */
|
|
297
|
+
if (name === 'REFLECTION_SURFACE') {
|
|
298
|
+
constants[String(id)] = reflectionSurface ? 1 : 0;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
274
301
|
if (!(name in cache.litSwitches)) {
|
|
275
302
|
throw new Error(`flatPass: variant "${variant}" declares a switch "${name}" no cache sets`);
|
|
276
303
|
}
|
|
@@ -609,6 +636,11 @@ export function flatPipeline(
|
|
|
609
636
|
model: SurfaceModelKind | null = null,
|
|
610
637
|
/** Which half of a skin it draws. The key must carry it: `|ss`, `|sd` or `|sa`. See `SkinHalf`. */
|
|
611
638
|
skinPass: SkinHalf = 'whole',
|
|
639
|
+
/**
|
|
640
|
+
* The reflection pass's surface half: the draw again, against its own depth, into the two
|
|
641
|
+
* targets `reflectionSurfacePass.ts` holds. The key must carry it: `|rs`.
|
|
642
|
+
*/
|
|
643
|
+
reflectionSurface = false,
|
|
612
644
|
): GPURenderPipeline {
|
|
613
645
|
return cache.get(
|
|
614
646
|
key,
|
|
@@ -633,6 +665,7 @@ export function flatPipeline(
|
|
|
633
665
|
cloth,
|
|
634
666
|
model,
|
|
635
667
|
skinPass,
|
|
668
|
+
reflectionSurface,
|
|
636
669
|
),
|
|
637
670
|
true,
|
|
638
671
|
);
|
|
@@ -765,10 +798,12 @@ function flatDescriptor(
|
|
|
765
798
|
cloth = false,
|
|
766
799
|
model: SurfaceModelKind | null = null,
|
|
767
800
|
skinPass: SkinHalf = 'whole',
|
|
801
|
+
reflectionSurface = false,
|
|
768
802
|
): GPURenderPipelineDescriptor {
|
|
769
803
|
const offset = depthOffsetForLayer(depthLayer);
|
|
770
|
-
/* The diffuse and colour halves are the same surface again, into the blur's targets
|
|
771
|
-
|
|
804
|
+
/* The diffuse and colour halves are the same surface again, into the blur's targets; and so is
|
|
805
|
+
the reflection pass's surface half, into its two. */
|
|
806
|
+
const diffuseAlone = skinPass === 'diffuse' || skinPass === 'albedo' || reflectionSurface;
|
|
772
807
|
return {
|
|
773
808
|
label: key,
|
|
774
809
|
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
@@ -798,31 +833,33 @@ function flatDescriptor(
|
|
|
798
833
|
}),
|
|
799
834
|
entryPoint: 'main',
|
|
800
835
|
/* Every variant declares it, so every lit pipeline may set it: see `PipelineCache`. */
|
|
801
|
-
constants: flatFragmentConstants(variant, cache, model, skinPass),
|
|
802
|
-
targets:
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
: translucent
|
|
813
|
-
? {
|
|
814
|
-
format: cache.format,
|
|
815
|
-
blend: {
|
|
816
|
-
color: {
|
|
817
|
-
srcFactor: 'src-alpha',
|
|
818
|
-
dstFactor: 'one-minus-src-alpha',
|
|
819
|
-
operation: 'add',
|
|
836
|
+
constants: flatFragmentConstants(variant, cache, model, skinPass, reflectionSurface),
|
|
837
|
+
targets: reflectionSurface
|
|
838
|
+
? [null, { format: REFLECTION_SURFACE_FORMAT }, { format: REFLECTION_SURFACE_FORMAT }]
|
|
839
|
+
: [
|
|
840
|
+
oitTarget(oit) ??
|
|
841
|
+
(translucent === 'additive'
|
|
842
|
+
? {
|
|
843
|
+
format: cache.format,
|
|
844
|
+
blend: {
|
|
845
|
+
color: { srcFactor: 'src-alpha', dstFactor: 'one', operation: 'add' },
|
|
846
|
+
alpha: { srcFactor: 'zero', dstFactor: 'one', operation: 'add' },
|
|
820
847
|
},
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
848
|
+
}
|
|
849
|
+
: translucent
|
|
850
|
+
? {
|
|
851
|
+
format: cache.format,
|
|
852
|
+
blend: {
|
|
853
|
+
color: {
|
|
854
|
+
srcFactor: 'src-alpha',
|
|
855
|
+
dstFactor: 'one-minus-src-alpha',
|
|
856
|
+
operation: 'add',
|
|
857
|
+
},
|
|
858
|
+
alpha: SCENE_ALPHA_COVERS,
|
|
859
|
+
},
|
|
860
|
+
}
|
|
861
|
+
: { format: cache.format }),
|
|
862
|
+
],
|
|
826
863
|
},
|
|
827
864
|
primitive: { topology: 'triangle-list', cullMode: doubleSided ? 'none' : 'back' },
|
|
828
865
|
/* Coverage only where a sample count can carry it: WebGPU refuses it at one sample. */
|
|
@@ -3,6 +3,7 @@ import { particleShaders, type ParticleMaterial } from '../../particleMaterial.t
|
|
|
3
3
|
import { PARTICLE_BINDINGS } from '../../shaders/generated/particle.wgsl.ts';
|
|
4
4
|
import { PARTICLE_BLADES, PARTICLE_INDICES, PARTICLE_VERTS } from '../../shaders/particle.ts';
|
|
5
5
|
import type { ParticleInstances } from '../../particlePool.ts';
|
|
6
|
+
import { DEVICE_PARTICLE_FLOATS } from '../../particlePool.ts';
|
|
6
7
|
import { packSpriteStream, type ParticleBlend, type ParticleFacing } from '../../particleBatch.ts';
|
|
7
8
|
import { createParticleSort, type ParticleSort } from '../../particleSort.ts';
|
|
8
9
|
import { DEPTH_FORMAT } from './flatPass.ts';
|
|
@@ -58,7 +59,7 @@ const USAGE_UNIFORM_DST = 0x0040 | 0x0008;
|
|
|
58
59
|
* Floats per instance, in the order they are packed: position 3, size 1, spin 1, colour 3,
|
|
59
60
|
* alpha 1, age 1, seed 1, velocity 3, and a sprite's frame and half-height 2.
|
|
60
61
|
*/
|
|
61
|
-
const INSTANCE_FLOATS =
|
|
62
|
+
const INSTANCE_FLOATS = DEVICE_PARTICLE_FLOATS;
|
|
62
63
|
|
|
63
64
|
const INSTANCE_ATTRIBUTES: GPUVertexAttribute[] = [
|
|
64
65
|
{ shaderLocation: 2, offset: 0, format: 'float32x3' },
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
} from '../../shaders/generated/ssrTrace.wgsl.ts';
|
|
30
30
|
import {
|
|
31
31
|
SSRRESOLVE_BINDINGS as SSR_RESOLVE_BINDINGS,
|
|
32
|
+
SSR_MATERIAL_RESOLVE_FRAG_WGSL,
|
|
32
33
|
SSR_RESOLVE_FRAG_WGSL,
|
|
33
34
|
} from '../../shaders/generated/ssrResolve.wgsl.ts';
|
|
34
35
|
import {
|
|
@@ -331,6 +332,16 @@ export const REFLECTION_OVER_BLEND: GPUBlendState = {
|
|
|
331
332
|
alpha: SCENE_ALPHA_KEEPS,
|
|
332
333
|
};
|
|
333
334
|
|
|
335
|
+
/**
|
|
336
|
+
* The frame's materials' reflection, added: the found colour times the tint, less the probe's share,
|
|
337
|
+
* which is negative where the probe was brighter than what replaced it. A half-float scene takes
|
|
338
|
+
* the negative addend as the subtraction it is. Its alpha kept.
|
|
339
|
+
*/
|
|
340
|
+
export const FRAME_REFLECTION_BLEND: GPUBlendState = {
|
|
341
|
+
color: { srcFactor: 'one', dstFactor: 'one', operation: 'add' },
|
|
342
|
+
alpha: SCENE_ALPHA_KEEPS,
|
|
343
|
+
};
|
|
344
|
+
|
|
334
345
|
/**
|
|
335
346
|
* The bloom pyramid's way back up: an octave added onto a level that the blend multiplies by that
|
|
336
347
|
* level's tint first — the blend constant, which white makes `one, one` exactly. Into the pyramid's
|
|
@@ -450,6 +461,12 @@ export const SSR_FRAG_SIZE = SSR_BINDINGS.SSR_TRACE_FRAG.uniformSize;
|
|
|
450
461
|
export const SSR_UNIFORMS = SSR_BINDINGS.SSR_TRACE_FRAG.uniforms;
|
|
451
462
|
export const SSR_TEXTURES = SSR_BINDINGS.SSR_TRACE_FRAG.textures;
|
|
452
463
|
export const SSR_RESOLVE_TEXTURES = SSR_RESOLVE_BINDINGS.SSR_RESOLVE_FRAG.textures;
|
|
464
|
+
/** The material resolve's block — the blur — and its three inputs. See `frameReflections.ts`. */
|
|
465
|
+
export const SSR_MATERIAL_FIELDS: UniformFields =
|
|
466
|
+
SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.fields;
|
|
467
|
+
export const SSR_MATERIAL_SIZE = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.uniformSize;
|
|
468
|
+
export const SSR_MATERIAL_UNIFORMS = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.uniforms;
|
|
469
|
+
export const SSR_MATERIAL_TEXTURES = SSR_RESOLVE_BINDINGS.SSR_MATERIAL_RESOLVE_FRAG.textures;
|
|
453
470
|
|
|
454
471
|
/**
|
|
455
472
|
* The resolve's layout: one texture and no uniform block.
|
|
@@ -513,6 +530,7 @@ export {
|
|
|
513
530
|
DECAL_PROJECT_FRAG_WGSL,
|
|
514
531
|
SSR_TRACE_FRAG_WGSL,
|
|
515
532
|
SSR_RESOLVE_FRAG_WGSL,
|
|
533
|
+
SSR_MATERIAL_RESOLVE_FRAG_WGSL,
|
|
516
534
|
};
|
|
517
535
|
export { BLOOM_PREFILTER_FRAG_WGSL, BLOOM_DOWNSAMPLE_FRAG_WGSL, BLOOM_UPSAMPLE_FRAG_WGSL };
|
|
518
536
|
export { RUSH_UNIFORMS, RUSH_TEXTURES };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface half of a reflection traced through the frame's materials, on this backend: the
|
|
3
|
+
* frame's opaque lit draws again, against the depth they wrote, into two half-float targets — the
|
|
4
|
+
* environment as the frame shows it with the surface's roughness, and what a reflection found in the
|
|
5
|
+
* frame is multiplied by to land in its place. `shaders/flat/reflectionSurface.ts` is what the two
|
|
6
|
+
* hold and why the swap is exact; this is where they are drawn.
|
|
7
|
+
*
|
|
8
|
+
* **Why a second pass and not a second output of the frame's.** Every pipeline drawn into the
|
|
9
|
+
* frame's pass would have to declare a target it never writes — the sky, water, particles, text and
|
|
10
|
+
* every pass a consumer registers — so the frame keeps its one attachment, and the lit stage's two
|
|
11
|
+
* extra outputs land nowhere there. Here they land: the same pipelines with `REFLECTION_SURFACE` on,
|
|
12
|
+
* which leaves before the lamps, the same bind groups and ring slots, tested `equal` against the
|
|
13
|
+
* frame's depth so only what the frame kept writes.
|
|
14
|
+
*
|
|
15
|
+
* **The draws are commands, kept the way the skin's halves are** (`skinScatterPass.ts`): the frame
|
|
16
|
+
* graph's pool is spent at every flush, and these are replayed after the flush that ends the frame's
|
|
17
|
+
* pass. Each holds the ring slots its frame draw used, which stay valid until the frame's last
|
|
18
|
+
* submit, after this has run.
|
|
19
|
+
*
|
|
20
|
+
* **What it costs**: every opaque lit draw twice, the second without its lamps; two half-float
|
|
21
|
+
* targets the size of the frame. Single-sampled only, as the trace that reads them is.
|
|
22
|
+
*/
|
|
23
|
+
import { createCommandPool, resetPool, takeCommand } from './drawCommand.ts';
|
|
24
|
+
import type { CommandPool, DrawCommand } from './drawCommand.ts';
|
|
25
|
+
|
|
26
|
+
/** Both targets' format: linear light and a tint, which an eight-bit target would clip and band. */
|
|
27
|
+
export const REFLECTION_SURFACE_FORMAT: GPUTextureFormat = 'rgba16float';
|
|
28
|
+
|
|
29
|
+
const USAGE_TARGET = 0x10 | 0x4; // RENDER_ATTACHMENT | TEXTURE_BINDING
|
|
30
|
+
|
|
31
|
+
export class ReflectionSurfacePass {
|
|
32
|
+
private readonly device: GPUDevice;
|
|
33
|
+
private readonly commands: CommandPool = createCommandPool(256);
|
|
34
|
+
private probe: GPUTexture | null = null;
|
|
35
|
+
private tint: GPUTexture | null = null;
|
|
36
|
+
/** The environment as the frame shows it, and the roughness in alpha. */
|
|
37
|
+
probeView: GPUTextureView | null = null;
|
|
38
|
+
/** What a found reflection is multiplied by. */
|
|
39
|
+
tintView: GPUTextureView | null = null;
|
|
40
|
+
|
|
41
|
+
constructor(device: GPUDevice) {
|
|
42
|
+
this.device = device;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A command for one opaque lit draw's surface half, filled by the caller. */
|
|
46
|
+
take(): DrawCommand {
|
|
47
|
+
return this.commands.commands[takeCommand(this.commands)] as DrawCommand;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** How many draws the frame kept. */
|
|
51
|
+
get kept(): number {
|
|
52
|
+
return this.commands.taken;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A new frame keeps nothing yet. */
|
|
56
|
+
reset(): void {
|
|
57
|
+
resetPool(this.commands);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The two targets at the frame's size, made again only when it changes. */
|
|
61
|
+
size(width: number, height: number): void {
|
|
62
|
+
if (this.probe !== null && this.probe.width === width && this.probe.height === height) return;
|
|
63
|
+
this.release();
|
|
64
|
+
const make = (label: string): GPUTexture =>
|
|
65
|
+
this.device.createTexture({
|
|
66
|
+
label,
|
|
67
|
+
size: [width, height],
|
|
68
|
+
format: REFLECTION_SURFACE_FORMAT,
|
|
69
|
+
usage: USAGE_TARGET,
|
|
70
|
+
});
|
|
71
|
+
this.probe = make('reflection.probe');
|
|
72
|
+
this.tint = make('reflection.tint');
|
|
73
|
+
this.probeView = this.probe.createView();
|
|
74
|
+
this.tintView = this.tint.createView();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Every kept draw into the two targets against the frame's depth, which it reads and does not
|
|
79
|
+
* write; both cleared first, so a pixel no lit surface reached reflects nothing. Called with no
|
|
80
|
+
* pass open on `encoder`, and drawn even with nothing kept, since the clear is what the trace
|
|
81
|
+
* reads there.
|
|
82
|
+
*/
|
|
83
|
+
draw(
|
|
84
|
+
encoder: GPUCommandEncoder,
|
|
85
|
+
depth: GPUTextureView,
|
|
86
|
+
issue: (pass: GPURenderPassEncoder, command: DrawCommand) => void,
|
|
87
|
+
): void {
|
|
88
|
+
const probe = this.probeView;
|
|
89
|
+
const tint = this.tintView;
|
|
90
|
+
if (probe === null || tint === null) return;
|
|
91
|
+
const pass = encoder.beginRenderPass({
|
|
92
|
+
label: 'reflection.surface',
|
|
93
|
+
colorAttachments: [
|
|
94
|
+
null,
|
|
95
|
+
{ view: probe, clearValue: [0, 0, 0, 1], loadOp: 'clear', storeOp: 'store' },
|
|
96
|
+
{ view: tint, clearValue: [0, 0, 0, 0], loadOp: 'clear', storeOp: 'store' },
|
|
97
|
+
],
|
|
98
|
+
depthStencilAttachment: { view: depth, depthReadOnly: true },
|
|
99
|
+
});
|
|
100
|
+
for (let i = 0; i < this.commands.taken; i += 1) {
|
|
101
|
+
issue(pass, this.commands.commands[i] as DrawCommand);
|
|
102
|
+
}
|
|
103
|
+
pass.end();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
release(): void {
|
|
107
|
+
this.probe?.destroy();
|
|
108
|
+
this.tint?.destroy();
|
|
109
|
+
this.probe = null;
|
|
110
|
+
this.tint = null;
|
|
111
|
+
this.probeView = null;
|
|
112
|
+
this.tintView = null;
|
|
113
|
+
}
|
|
114
|
+
}
|