@driftengine/core 4.8.5 → 4.8.7
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 +4392 -4250
- package/README.md +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +12 -2
- package/dist/render/ambientHarmonics.d.ts +46 -0
- package/dist/render/ambientHarmonics.js +80 -0
- package/dist/render/anisotropicLobe.d.ts +10 -0
- package/dist/render/anisotropicLobe.js +19 -0
- package/dist/render/areaLights.d.ts +54 -0
- package/dist/render/areaLights.js +55 -0
- package/dist/render/backend/api.d.ts +43 -2
- package/dist/render/backend/webgl2/instanced.d.ts +2 -0
- package/dist/render/backend/webgl2/instanced.js +11 -2
- package/dist/render/backend/webgl2/renderer.d.ts +120 -11
- package/dist/render/backend/webgl2/renderer.js +356 -53
- package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
- package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
- package/dist/render/backend/webgl2/skinScatter.d.ts +14 -0
- package/dist/render/backend/webgl2/skinScatter.js +88 -26
- package/dist/render/backend/webgpu/buffers.js +2 -1
- package/dist/render/backend/webgpu/clusterBinner.js +3 -2
- package/dist/render/backend/webgpu/flatPass.d.ts +7 -5
- package/dist/render/backend/webgpu/flatPass.js +15 -13
- package/dist/render/backend/webgpu/particlePass.d.ts +37 -4
- package/dist/render/backend/webgpu/particlePass.js +81 -12
- package/dist/render/backend/webgpu/postPass.d.ts +6 -1
- package/dist/render/backend/webgpu/postPass.js +7 -2
- package/dist/render/backend/webgpu/renderer.d.ts +93 -8
- package/dist/render/backend/webgpu/renderer.js +483 -93
- 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/shaders/clusterBin.wgsl.js +41 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +40 -28
- package/dist/render/backend/webgpu/skinPaletteRing.js +69 -32
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +10 -2
- package/dist/render/backend/webgpu/skinScatterPass.js +59 -9
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +45 -5
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/bloomChain.d.ts +44 -0
- package/dist/render/bloomChain.js +28 -0
- package/dist/render/bloomPass.d.ts +3 -1
- package/dist/render/bloomPass.js +16 -2
- package/dist/render/clusteredLights.d.ts +78 -6
- package/dist/render/clusteredLights.js +214 -13
- 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/fixtureAtlas.js +1 -1
- package/dist/render/gi/bounceLights.d.ts +3 -2
- package/dist/render/gi/bounceLights.js +8 -3
- package/dist/render/instanceCull.js +12 -0
- package/dist/render/instances.d.ts +47 -11
- package/dist/render/instances.js +24 -9
- package/dist/render/lightBudget.d.ts +38 -2
- package/dist/render/lightBudget.js +48 -5
- package/dist/render/lightmap.d.ts +116 -0
- package/dist/render/lightmap.js +140 -0
- package/dist/render/mesh.js +2 -1
- package/dist/render/particleBatch.d.ts +59 -3
- package/dist/render/particleBatch.js +53 -2
- package/dist/render/particleMaterial.d.ts +6 -1
- package/dist/render/particleMaterial.js +10 -2
- package/dist/render/particlePool.d.ts +32 -0
- package/dist/render/particlePool.js +9 -0
- package/dist/render/particleSort.d.ts +34 -0
- package/dist/render/particleSort.js +96 -0
- package/dist/render/pointLightSelection.d.ts +13 -0
- package/dist/render/pointLightSelection.js +3 -1
- package/dist/render/renderQuality.d.ts +8 -7
- 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 +8 -1
- package/dist/render/screenSpaceReflection.d.ts +27 -1
- package/dist/render/screenSpaceReflection.js +9 -0
- package/dist/render/shaders/bloom.d.ts +8 -4
- package/dist/render/shaders/bloom.js +20 -3
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +7 -1
- package/dist/render/shaders/depth.js +11 -0
- 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 +10 -0
- package/dist/render/shaders/flat/areaLight.js +142 -0
- package/dist/render/shaders/flat/glassTint.d.ts +3 -2
- package/dist/render/shaders/flat/glassTint.js +3 -1
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +46 -6
- 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 +158 -121
- package/dist/render/shaders/flat/models.d.ts +21 -6
- package/dist/render/shaders/flat/models.js +161 -17
- package/dist/render/shaders/flat/normalMap.d.ts +10 -0
- package/dist/render/shaders/flat/normalMap.js +25 -0
- package/dist/render/shaders/flat/preamble.js +84 -40
- package/dist/render/shaders/flat/skin.js +6 -5
- package/dist/render/shaders/generated/bloom.wgsl.d.ts +13 -3
- package/dist/render/shaders/generated/bloom.wgsl.js +13 -3
- 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/depth.wgsl.d.ts +4 -4
- package/dist/render/shaders/generated/depth.wgsl.js +4 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1647 -2044
- package/dist/render/shaders/generated/flat.wgsl.js +1685 -2082
- package/dist/render/shaders/generated/particle.wgsl.d.ts +115 -1
- package/dist/render/shaders/generated/particle.wgsl.js +115 -1
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/skinBlur.wgsl.js +12 -2
- package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +11 -6
- package/dist/render/shaders/generated/ssrTrace.wgsl.js +11 -6
- 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/particle.d.ts +17 -1
- package/dist/render/shaders/particle.js +133 -1
- 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/skinBlur.js +25 -3
- package/dist/render/shaders/ssrTrace.js +20 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -3
- package/dist/render/skinBlur.d.ts +8 -5
- package/dist/render/skinBlur.js +8 -5
- package/dist/render/skinScatter.d.ts +3 -1
- package/dist/render/skinScatter.js +3 -1
- package/dist/render/ssrPass.js +1 -0
- package/dist/render/surfaceModel.d.ts +49 -8
- package/dist/render/surfaceModel.js +54 -8
- package/dist/render/surfaceTexture.d.ts +38 -1
- package/dist/render/surfaceTexture.js +37 -2
- package/package.json +6 -6
- package/src/index.ts +26 -3
- package/src/render/ambientHarmonics.ts +92 -0
- package/src/render/anisotropicLobe.ts +29 -0
- package/src/render/areaLights.ts +97 -0
- package/src/render/backend/api.ts +61 -1
- package/src/render/backend/webgl2/instanced.ts +12 -2
- package/src/render/backend/webgl2/renderer.ts +470 -59
- package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
- package/src/render/backend/webgl2/skinScatter.ts +120 -43
- package/src/render/backend/webgpu/buffers.ts +2 -1
- package/src/render/backend/webgpu/clusterBinner.ts +3 -1
- package/src/render/backend/webgpu/flatPass.ts +18 -13
- package/src/render/backend/webgpu/particlePass.ts +119 -12
- package/src/render/backend/webgpu/postPass.ts +7 -2
- package/src/render/backend/webgpu/renderer.ts +589 -113
- package/src/render/backend/webgpu/sceneCaptureTarget.ts +63 -0
- package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +41 -1
- package/src/render/backend/webgpu/skinPaletteRing.ts +65 -33
- package/src/render/backend/webgpu/skinScatterPass.ts +59 -9
- package/src/render/backend/webgpu/surfaceTexturePass.ts +57 -6
- package/src/render/bloomChain.ts +69 -0
- package/src/render/bloomPass.ts +26 -2
- package/src/render/clusteredLights.ts +259 -12
- package/src/render/driftLight/bake.ts +3 -1
- package/src/render/driftLight/falloff.ts +13 -2
- package/src/render/fixtureAtlas.ts +1 -1
- package/src/render/gi/bounceLights.ts +12 -3
- package/src/render/instanceCull.ts +9 -0
- package/src/render/instances.ts +61 -12
- package/src/render/lightBudget.ts +88 -4
- package/src/render/lightmap.ts +243 -0
- package/src/render/mesh.ts +2 -1
- package/src/render/particleBatch.ts +95 -4
- package/src/render/particleMaterial.ts +11 -1
- package/src/render/particlePool.ts +36 -0
- package/src/render/particleSort.ts +133 -0
- package/src/render/pointLightSelection.ts +20 -1
- package/src/render/renderQuality.ts +8 -7
- 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 +18 -1
- package/src/render/screenSpaceReflection.ts +33 -1
- package/src/render/shaders/bloom.ts +20 -3
- package/src/render/shaders/bolt.ts +7 -1
- package/src/render/shaders/depth.ts +11 -0
- package/src/render/shaders/flat/anisotropic.ts +37 -3
- package/src/render/shaders/flat/areaLight.ts +142 -0
- package/src/render/shaders/flat/glassTint.ts +9 -2
- package/src/render/shaders/flat/index.ts +51 -6
- package/src/render/shaders/flat/lobes.ts +50 -43
- package/src/render/shaders/flat/main.ts +158 -121
- package/src/render/shaders/flat/models.ts +170 -21
- package/src/render/shaders/flat/normalMap.ts +25 -0
- package/src/render/shaders/flat/preamble.ts +84 -40
- package/src/render/shaders/flat/skin.ts +6 -5
- package/src/render/shaders/generated/bloom.wgsl.ts +13 -3
- package/src/render/shaders/generated/bolt.wgsl.ts +1 -1
- package/src/render/shaders/generated/depth.wgsl.ts +4 -4
- package/src/render/shaders/generated/flat.wgsl.ts +1685 -2082
- package/src/render/shaders/generated/particle.wgsl.ts +116 -1
- package/src/render/shaders/generated/skinBlur.wgsl.ts +12 -2
- package/src/render/shaders/generated/ssrTrace.wgsl.ts +11 -6
- package/src/render/shaders/generated/water.wgsl.ts +23 -16
- package/src/render/shaders/gi/probeBake.wgsl.ts +9 -5
- package/src/render/shaders/particle.ts +134 -1
- package/src/render/shaders/recon/motion.wgsl.ts +13 -2
- package/src/render/shaders/skinBlur.ts +25 -3
- package/src/render/shaders/ssrTrace.ts +20 -1
- package/src/render/shaders/water.ts +12 -3
- package/src/render/skinBlur.ts +8 -5
- package/src/render/skinScatter.ts +3 -1
- package/src/render/ssrPass.ts +1 -0
- package/src/render/surfaceModel.ts +82 -10
- package/src/render/surfaceTexture.ts +101 -3
|
@@ -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
|
+
}
|
|
@@ -5,14 +5,19 @@
|
|
|
5
5
|
*
|
|
6
6
|
* **Drawn as it goes, not kept**: this backend issues a draw when it is asked for, and the state a
|
|
7
7
|
* skin draw reads — its joint palette, its uniforms — is rewritten by the draw after it. So the
|
|
8
|
-
* renderer draws each skin
|
|
9
|
-
* this target,
|
|
8
|
+
* renderer draws each skin three times in place: the frame's half, then at once the diffuse's light
|
|
9
|
+
* alone into this target and its colour alone into the other, both sharing the frame's depth and
|
|
10
|
+
* testing for equality against it. The blur spreads the light and multiplies it by the colour.
|
|
10
11
|
*
|
|
11
12
|
* **The units it reads are its own** — `SKIN_BLUR_TEXTURE_UNIT` and the one after — past every
|
|
12
13
|
* unit a lit program binds, because it runs in the middle of a frame and the draws after it must
|
|
13
14
|
* find their textures where they left them.
|
|
14
15
|
*/
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
SKIN_BLUR_ALBEDO_UNIT,
|
|
18
|
+
SKIN_BLUR_DEPTH_UNIT,
|
|
19
|
+
SKIN_BLUR_TEXTURE_UNIT,
|
|
20
|
+
} from '../../lightBudget.ts';
|
|
16
21
|
import { blendKeeping } from '../../sceneCoverage.ts';
|
|
17
22
|
import type { SceneTarget } from '../../sceneTarget.ts';
|
|
18
23
|
import { compileProgram, uniformLocations } from '../../shader.ts';
|
|
@@ -33,9 +38,13 @@ export class GlSkinScatter {
|
|
|
33
38
|
private readonly depthToViewZ = new Float32Array(4);
|
|
34
39
|
private diffuse: WebGLTexture | null = null;
|
|
35
40
|
private across: WebGLTexture | null = null;
|
|
41
|
+
private albedo: WebGLTexture | null = null;
|
|
36
42
|
private multisampled: WebGLRenderbuffer | null = null;
|
|
43
|
+
private albedoMultisampled: WebGLRenderbuffer | null = null;
|
|
37
44
|
private drawFramebuffer: WebGLFramebuffer | null = null;
|
|
38
45
|
private resolveFramebuffer: WebGLFramebuffer | null = null;
|
|
46
|
+
private albedoFramebuffer: WebGLFramebuffer | null = null;
|
|
47
|
+
private albedoResolveFramebuffer: WebGLFramebuffer | null = null;
|
|
39
48
|
private acrossFramebuffer: WebGLFramebuffer | null = null;
|
|
40
49
|
private width = 0;
|
|
41
50
|
private height = 0;
|
|
@@ -44,6 +53,7 @@ export class GlSkinScatter {
|
|
|
44
53
|
/** Refused once and for good: a driver that will not render to half floats. */
|
|
45
54
|
private unavailable = false;
|
|
46
55
|
private cleared = false;
|
|
56
|
+
private albedoCleared = false;
|
|
47
57
|
private drawn = false;
|
|
48
58
|
|
|
49
59
|
constructor(gl: WebGL2RenderingContext) {
|
|
@@ -115,6 +125,17 @@ export class GlSkinScatter {
|
|
|
115
125
|
this.drawn = true;
|
|
116
126
|
}
|
|
117
127
|
|
|
128
|
+
/** Bind the target for the same skin's colour half, cleared the first time a frame does. */
|
|
129
|
+
beginAlbedo(): void {
|
|
130
|
+
const { gl } = this;
|
|
131
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.albedoFramebuffer);
|
|
132
|
+
gl.viewport(0, 0, this.width, this.height);
|
|
133
|
+
if (!this.albedoCleared) {
|
|
134
|
+
gl.clearBufferfv(gl.COLOR, 0, CLEAR);
|
|
135
|
+
this.albedoCleared = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
/**
|
|
119
140
|
* Across into the second target, then down and added into the frame, which `scene` binds. `depth`
|
|
120
141
|
* is the frame's depth as a single-sampled texture, or null where none could be had — and then
|
|
@@ -129,20 +150,8 @@ export class GlSkinScatter {
|
|
|
129
150
|
): void {
|
|
130
151
|
const { gl } = this;
|
|
131
152
|
if (this.multisampled !== null) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
gl.blitFramebuffer(
|
|
135
|
-
0,
|
|
136
|
-
0,
|
|
137
|
-
this.width,
|
|
138
|
-
this.height,
|
|
139
|
-
0,
|
|
140
|
-
0,
|
|
141
|
-
this.width,
|
|
142
|
-
this.height,
|
|
143
|
-
gl.COLOR_BUFFER_BIT,
|
|
144
|
-
gl.NEAREST,
|
|
145
|
-
);
|
|
153
|
+
this.resolve(this.drawFramebuffer, this.resolveFramebuffer);
|
|
154
|
+
this.resolve(this.albedoFramebuffer, this.albedoResolveFramebuffer);
|
|
146
155
|
}
|
|
147
156
|
gl.disable(gl.DEPTH_TEST);
|
|
148
157
|
gl.disable(gl.CULL_FACE);
|
|
@@ -153,6 +162,9 @@ export class GlSkinScatter {
|
|
|
153
162
|
const u = this.uniforms;
|
|
154
163
|
gl.uniform1i(u['uSkin'] ?? null, SKIN_BLUR_TEXTURE_UNIT);
|
|
155
164
|
gl.uniform1i(u['uDepth'] ?? null, SKIN_BLUR_DEPTH_UNIT);
|
|
165
|
+
gl.uniform1i(u['uAlbedo'] ?? null, SKIN_BLUR_ALBEDO_UNIT);
|
|
166
|
+
gl.activeTexture(gl.TEXTURE0 + SKIN_BLUR_ALBEDO_UNIT);
|
|
167
|
+
gl.bindTexture(gl.TEXTURE_2D, this.albedo ?? empty);
|
|
156
168
|
/* The four terms that carry a depth back to view-space metres: the occlusion blur's own. */
|
|
157
169
|
this.depthToViewZ[0] = (inverse[10] as number) ?? 0;
|
|
158
170
|
this.depthToViewZ[1] = (inverse[14] as number) ?? 0;
|
|
@@ -175,6 +187,8 @@ export class GlSkinScatter {
|
|
|
175
187
|
this.step[0] = 1 / this.width;
|
|
176
188
|
this.step[1] = 0;
|
|
177
189
|
gl.uniform2fv(u['uStep'] ?? null, this.step);
|
|
190
|
+
/* The light spreads on both axes; the colour is applied once, on the one adding into the frame. */
|
|
191
|
+
gl.uniform1f(u['uApplyAlbedo'] ?? null, 0);
|
|
178
192
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
179
193
|
|
|
180
194
|
scene.bind();
|
|
@@ -182,6 +196,7 @@ export class GlSkinScatter {
|
|
|
182
196
|
this.step[0] = 0;
|
|
183
197
|
this.step[1] = 1 / this.height;
|
|
184
198
|
gl.uniform2fv(u['uStep'] ?? null, this.step);
|
|
199
|
+
gl.uniform1f(u['uApplyAlbedo'] ?? null, 1);
|
|
185
200
|
/* Added: its colour onto the frame's, the frame's alpha kept. */
|
|
186
201
|
gl.enable(gl.BLEND);
|
|
187
202
|
gl.blendEquation(gl.FUNC_ADD);
|
|
@@ -199,9 +214,29 @@ export class GlSkinScatter {
|
|
|
199
214
|
/** Spent at the frame's start: what was drawn into the target was last frame's. */
|
|
200
215
|
reset(): void {
|
|
201
216
|
this.cleared = false;
|
|
217
|
+
this.albedoCleared = false;
|
|
202
218
|
this.drawn = false;
|
|
203
219
|
}
|
|
204
220
|
|
|
221
|
+
/** A multisampled target into its single-sampled texture. */
|
|
222
|
+
private resolve(from: WebGLFramebuffer | null, to: WebGLFramebuffer | null): void {
|
|
223
|
+
const { gl } = this;
|
|
224
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, from);
|
|
225
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, to);
|
|
226
|
+
gl.blitFramebuffer(
|
|
227
|
+
0,
|
|
228
|
+
0,
|
|
229
|
+
this.width,
|
|
230
|
+
this.height,
|
|
231
|
+
0,
|
|
232
|
+
0,
|
|
233
|
+
this.width,
|
|
234
|
+
this.height,
|
|
235
|
+
gl.COLOR_BUFFER_BIT,
|
|
236
|
+
gl.NEAREST,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
205
240
|
dispose(): void {
|
|
206
241
|
const { gl } = this;
|
|
207
242
|
this.release();
|
|
@@ -226,19 +261,59 @@ export class GlSkinScatter {
|
|
|
226
261
|
this.sharedDepth = depthRenderbuffer ?? depthTexture;
|
|
227
262
|
this.diffuse = this.halfFloatTexture(width, height);
|
|
228
263
|
this.across = this.halfFloatTexture(width, height);
|
|
264
|
+
this.albedo = this.halfFloatTexture(width, height);
|
|
229
265
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
266
|
+
const multisampled = samples > 1 && depthRenderbuffer !== null;
|
|
267
|
+
const diffuse = this.drawTarget(this.diffuse, multisampled, depthTexture, depthRenderbuffer);
|
|
268
|
+
this.drawFramebuffer = diffuse.framebuffer;
|
|
269
|
+
this.multisampled = diffuse.multisampled;
|
|
270
|
+
this.resolveFramebuffer = diffuse.resolve;
|
|
271
|
+
const albedo = this.drawTarget(this.albedo, multisampled, depthTexture, depthRenderbuffer);
|
|
272
|
+
this.albedoFramebuffer = albedo.framebuffer;
|
|
273
|
+
this.albedoMultisampled = albedo.multisampled;
|
|
274
|
+
this.albedoResolveFramebuffer = albedo.resolve;
|
|
275
|
+
|
|
276
|
+
this.acrossFramebuffer = gl.createFramebuffer();
|
|
277
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this.acrossFramebuffer);
|
|
278
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.across, 0);
|
|
279
|
+
const acrossReady = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
|
|
280
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
281
|
+
if (diffuse.ready && albedo.ready && acrossReady) return true;
|
|
282
|
+
this.release();
|
|
283
|
+
this.refuse();
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* A framebuffer a skin half draws into against the frame's depth: the texture itself, or a
|
|
289
|
+
* multisampled renderbuffer and the framebuffer that resolves it into the texture.
|
|
290
|
+
*/
|
|
291
|
+
private drawTarget(
|
|
292
|
+
texture: WebGLTexture | null,
|
|
293
|
+
multisampled: boolean,
|
|
294
|
+
depthTexture: WebGLTexture | null,
|
|
295
|
+
depthRenderbuffer: WebGLRenderbuffer | null,
|
|
296
|
+
): {
|
|
297
|
+
framebuffer: WebGLFramebuffer | null;
|
|
298
|
+
multisampled: WebGLRenderbuffer | null;
|
|
299
|
+
resolve: WebGLFramebuffer | null;
|
|
300
|
+
ready: boolean;
|
|
301
|
+
} {
|
|
302
|
+
const { gl } = this;
|
|
303
|
+
const framebuffer = gl.createFramebuffer();
|
|
304
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
305
|
+
let samples: WebGLRenderbuffer | null = null;
|
|
306
|
+
if (multisampled && depthRenderbuffer !== null) {
|
|
307
|
+
samples = gl.createRenderbuffer();
|
|
308
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, samples);
|
|
309
|
+
gl.renderbufferStorageMultisample(
|
|
239
310
|
gl.RENDERBUFFER,
|
|
240
|
-
this.
|
|
311
|
+
this.samples,
|
|
312
|
+
gl.RGBA16F,
|
|
313
|
+
this.width,
|
|
314
|
+
this.height,
|
|
241
315
|
);
|
|
316
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, samples);
|
|
242
317
|
gl.framebufferRenderbuffer(
|
|
243
318
|
gl.FRAMEBUFFER,
|
|
244
319
|
gl.DEPTH_ATTACHMENT,
|
|
@@ -246,25 +321,17 @@ export class GlSkinScatter {
|
|
|
246
321
|
depthRenderbuffer,
|
|
247
322
|
);
|
|
248
323
|
} else {
|
|
249
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,
|
|
324
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
250
325
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
|
|
251
326
|
}
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER,
|
|
257
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,
|
|
327
|
+
const ready = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
|
|
328
|
+
let resolve: WebGLFramebuffer | null = null;
|
|
329
|
+
if (samples !== null) {
|
|
330
|
+
resolve = gl.createFramebuffer();
|
|
331
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, resolve);
|
|
332
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
258
333
|
}
|
|
259
|
-
|
|
260
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, this.acrossFramebuffer);
|
|
261
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.across, 0);
|
|
262
|
-
const acrossReady = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
|
|
263
|
-
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
264
|
-
if (drawReady && acrossReady) return true;
|
|
265
|
-
this.release();
|
|
266
|
-
this.refuse();
|
|
267
|
-
return false;
|
|
334
|
+
return { framebuffer, multisampled: samples, resolve, ready };
|
|
268
335
|
}
|
|
269
336
|
|
|
270
337
|
private refuse(): void {
|
|
@@ -294,16 +361,26 @@ export class GlSkinScatter {
|
|
|
294
361
|
const { gl } = this;
|
|
295
362
|
if (this.drawFramebuffer !== null) gl.deleteFramebuffer(this.drawFramebuffer);
|
|
296
363
|
if (this.resolveFramebuffer !== null) gl.deleteFramebuffer(this.resolveFramebuffer);
|
|
364
|
+
if (this.albedoFramebuffer !== null) gl.deleteFramebuffer(this.albedoFramebuffer);
|
|
365
|
+
if (this.albedoResolveFramebuffer !== null) {
|
|
366
|
+
gl.deleteFramebuffer(this.albedoResolveFramebuffer);
|
|
367
|
+
}
|
|
297
368
|
if (this.acrossFramebuffer !== null) gl.deleteFramebuffer(this.acrossFramebuffer);
|
|
298
369
|
if (this.multisampled !== null) gl.deleteRenderbuffer(this.multisampled);
|
|
370
|
+
if (this.albedoMultisampled !== null) gl.deleteRenderbuffer(this.albedoMultisampled);
|
|
299
371
|
if (this.diffuse !== null) gl.deleteTexture(this.diffuse);
|
|
300
372
|
if (this.across !== null) gl.deleteTexture(this.across);
|
|
373
|
+
if (this.albedo !== null) gl.deleteTexture(this.albedo);
|
|
301
374
|
this.drawFramebuffer = null;
|
|
302
375
|
this.resolveFramebuffer = null;
|
|
376
|
+
this.albedoFramebuffer = null;
|
|
377
|
+
this.albedoResolveFramebuffer = null;
|
|
303
378
|
this.acrossFramebuffer = null;
|
|
304
379
|
this.multisampled = null;
|
|
380
|
+
this.albedoMultisampled = null;
|
|
305
381
|
this.diffuse = null;
|
|
306
382
|
this.across = null;
|
|
383
|
+
this.albedo = null;
|
|
307
384
|
this.sharedDepth = null;
|
|
308
385
|
}
|
|
309
386
|
}
|
|
@@ -766,7 +766,8 @@ const INSTANCE_ATTRIBUTES: GPUVertexAttribute[] = [
|
|
|
766
766
|
{ shaderLocation: 12, offset: 16, format: 'float32x4' },
|
|
767
767
|
{ shaderLocation: 13, offset: 32, format: 'float32x4' },
|
|
768
768
|
{ shaderLocation: 14, offset: 48, format: 'float32x4' },
|
|
769
|
-
|
|
769
|
+
/* The tint and, in w, the opacity. See `INSTANCE_FLOATS`. */
|
|
770
|
+
{ shaderLocation: 15, offset: 64, format: 'float32x4' },
|
|
770
771
|
];
|
|
771
772
|
|
|
772
773
|
/** The locations above, as the set the base layout must stand clear of on an instanced draw. */
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
TABLE_HEIGHT,
|
|
6
6
|
TABLE_WIDTH,
|
|
7
7
|
type ClusterLightSet,
|
|
8
|
+
clusteredLightTotal,
|
|
8
9
|
writeLightRecord,
|
|
9
10
|
} from '../../clusteredLights.ts';
|
|
10
11
|
import { MAX_POINT_LIGHTS } from '../../lightBudget.ts';
|
|
@@ -167,7 +168,8 @@ export class ClusterBinner {
|
|
|
167
168
|
if (frame === null || device === null || pipeline === null || group === null) return;
|
|
168
169
|
if (params === null || lightBuffer === null) return;
|
|
169
170
|
|
|
170
|
-
|
|
171
|
+
/* The lamps and the clustered rectangles after them. See `ClusterLightSet.areas`. */
|
|
172
|
+
const count = clusteredLightTotal(frame.lights);
|
|
171
173
|
|
|
172
174
|
/*
|
|
173
175
|
* The records, by the function `buildLightClusters` writes them with, because the shader
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SURFACE_MODEL_SWITCH } from '../../surfaceModel.ts';
|
|
2
2
|
import type { SurfaceModelKind } from '../../surfaceModel.ts';
|
|
3
|
-
import type
|
|
3
|
+
import { SKIN_HALF_SWITCH, type SkinHalf } from '../../shaders/flat/models.ts';
|
|
4
4
|
import { DEPTH_COMPARE, DEPTH_FORMAT, depthOffsetForLayer } from '../../depthConvention.ts';
|
|
5
5
|
import {
|
|
6
6
|
FLAT_BINDINGS,
|
|
@@ -153,8 +153,8 @@ export function flatVertexBindings(
|
|
|
153
153
|
const PLAIN_VERTEX = flatVertexBindings(false);
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
|
-
* A vertex stage's constants, keyed by each override's **id** as the fragment's are: `SKIN_EIGHT`
|
|
157
|
-
* a skinned stage, nothing in any other. Every override a stage declares is set, and one this does
|
|
156
|
+
* A vertex stage's constants, keyed by each override's **id** as the fragment's are: `SKIN_EIGHT` and
|
|
157
|
+
* `CLOTH_BOUND` in a skinned stage, `LIGHTMAP_REGIONS` in an instanced one, nothing in any other. Every override a stage declares is set, and one this does
|
|
158
158
|
* not know is refused here rather than defaulted. Shared with the shadow and glass-tint casters,
|
|
159
159
|
* whose skinned stages declare the same switch.
|
|
160
160
|
*/
|
|
@@ -162,11 +162,14 @@ export function vertexConstants(
|
|
|
162
162
|
bindings: StageBindings,
|
|
163
163
|
skinEight: boolean,
|
|
164
164
|
cloth = false,
|
|
165
|
+
/** Whether an instanced stage reads its tint lane as a lightmap region. See `lightmap.ts`. */
|
|
166
|
+
lightmapRegions = false,
|
|
165
167
|
): Record<string, number> {
|
|
166
168
|
const constants: Record<string, number> = {};
|
|
167
169
|
for (const [name, id] of Object.entries(bindings.overrides ?? {})) {
|
|
168
170
|
if (name === 'SKIN_EIGHT') constants[String(id)] = skinEight ? 1 : 0;
|
|
169
171
|
else if (name === 'CLOTH_BOUND') constants[String(id)] = cloth ? 1 : 0;
|
|
172
|
+
else if (name === 'LIGHTMAP_REGIONS') constants[String(id)] = lightmapRegions ? 1 : 0;
|
|
170
173
|
else throw new Error(`flatPass: a vertex stage declares a switch "${name}" nothing sets`);
|
|
171
174
|
}
|
|
172
175
|
return constants;
|
|
@@ -263,13 +266,9 @@ function flatFragmentConstants(
|
|
|
263
266
|
constants[String(id)] = name === modelSwitch ? 1 : 0;
|
|
264
267
|
continue;
|
|
265
268
|
}
|
|
266
|
-
/* Skin's
|
|
267
|
-
if (name === 'SKIN_SCREEN' || name === 'SKIN_DIFFUSE') {
|
|
268
|
-
constants[String(id)] =
|
|
269
|
-
(name === 'SKIN_SCREEN' && skinPass === 'scene') ||
|
|
270
|
-
(name === 'SKIN_DIFFUSE' && skinPass === 'diffuse')
|
|
271
|
-
? 1
|
|
272
|
-
: 0;
|
|
269
|
+
/* Skin's halves under the screen-space blur, set from the key as a model's switch is. */
|
|
270
|
+
if (name === 'SKIN_SCREEN' || name === 'SKIN_DIFFUSE' || name === 'SKIN_ALBEDO') {
|
|
271
|
+
constants[String(id)] = skinPass !== 'whole' && name === SKIN_HALF_SWITCH[skinPass] ? 1 : 0;
|
|
273
272
|
continue;
|
|
274
273
|
}
|
|
275
274
|
if (!(name in cache.litSwitches)) {
|
|
@@ -608,7 +607,7 @@ export function flatPipeline(
|
|
|
608
607
|
cloth = false,
|
|
609
608
|
/** Which shading model its fragment stage shades by, null the standard. The key must carry it. */
|
|
610
609
|
model: SurfaceModelKind | null = null,
|
|
611
|
-
/** Which half of a skin it draws. The key must carry it: `|ss` or `|
|
|
610
|
+
/** Which half of a skin it draws. The key must carry it: `|ss`, `|sd` or `|sa`. See `SkinHalf`. */
|
|
612
611
|
skinPass: SkinHalf = 'whole',
|
|
613
612
|
): GPURenderPipeline {
|
|
614
613
|
return cache.get(
|
|
@@ -768,7 +767,8 @@ function flatDescriptor(
|
|
|
768
767
|
skinPass: SkinHalf = 'whole',
|
|
769
768
|
): GPURenderPipelineDescriptor {
|
|
770
769
|
const offset = depthOffsetForLayer(depthLayer);
|
|
771
|
-
|
|
770
|
+
/* The diffuse and colour halves are the same surface again, into the blur's targets. */
|
|
771
|
+
const diffuseAlone = skinPass === 'diffuse' || skinPass === 'albedo';
|
|
772
772
|
return {
|
|
773
773
|
label: key,
|
|
774
774
|
layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
|
|
@@ -784,7 +784,12 @@ function flatDescriptor(
|
|
|
784
784
|
}),
|
|
785
785
|
entryPoint: 'main',
|
|
786
786
|
buffers: vertexBufferLayouts(present, instanced),
|
|
787
|
-
constants: vertexConstants(
|
|
787
|
+
constants: vertexConstants(
|
|
788
|
+
flatVertexBindings(skinned, morphed, instanced),
|
|
789
|
+
skinEight,
|
|
790
|
+
cloth,
|
|
791
|
+
model === 'lightmap',
|
|
792
|
+
),
|
|
788
793
|
},
|
|
789
794
|
fragment: {
|
|
790
795
|
module: shaderModule(device, {
|