@driftengine/core 4.8.6 → 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 +71 -0
- package/README.md +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -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/backend/api.d.ts +33 -3
- package/dist/render/backend/webgl2/renderer.d.ts +50 -14
- package/dist/render/backend/webgl2/renderer.js +141 -30
- package/dist/render/backend/webgl2/sceneCaptureTarget.d.ts +29 -0
- package/dist/render/backend/webgl2/sceneCaptureTarget.js +96 -0
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/renderer.d.ts +35 -1
- package/dist/render/backend/webgpu/renderer.js +155 -16
- 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/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/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/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/screenSpaceReflection.d.ts +27 -1
- package/dist/render/screenSpaceReflection.js +9 -0
- 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 +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 +3 -1
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +16 -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 +57 -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/preamble.js +10 -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 +16 -0
- package/dist/render/shaders/generated/flat.wgsl.js +54 -38
- 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/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +13 -2
- 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/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 +29 -8
- package/dist/render/surfaceModel.js +33 -9
- package/dist/render/surfaceTexture.d.ts +25 -1
- package/dist/render/surfaceTexture.js +27 -5
- package/package.json +6 -6
- package/src/index.ts +6 -2
- package/src/render/anisotropicLobe.ts +29 -0
- package/src/render/areaLights.ts +58 -0
- package/src/render/backend/api.ts +49 -2
- package/src/render/backend/webgl2/renderer.ts +192 -38
- package/src/render/backend/webgl2/sceneCaptureTarget.ts +130 -0
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/renderer.ts +194 -19
- 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/driftLight/bake.ts +3 -1
- package/src/render/driftLight/falloff.ts +13 -2
- 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/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/screenSpaceReflection.ts +33 -1
- 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 +46 -0
- package/src/render/shaders/flat/glassTint.ts +9 -2
- package/src/render/shaders/flat/index.ts +21 -2
- package/src/render/shaders/flat/lobes.ts +50 -43
- package/src/render/shaders/flat/main.ts +57 -22
- package/src/render/shaders/flat/models.ts +100 -16
- package/src/render/shaders/flat/preamble.ts +10 -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 +54 -38
- 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/recon/motion.wgsl.ts +13 -2
- package/src/render/shaders/ssrTrace.ts +20 -1
- package/src/render/shaders/water.ts +12 -3
- package/src/render/skinScatter.ts +3 -1
- package/src/render/ssrPass.ts +1 -0
- package/src/render/surfaceModel.ts +47 -10
- package/src/render/surfaceTexture.ts +69 -9
|
@@ -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
|
+
}
|
|
@@ -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' },
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
FACE_COUNT,
|
|
130
130
|
createResolvedPointShadows,
|
|
131
131
|
} from '../../pointShadowImage.ts';
|
|
132
|
-
import { MAX_AREA_LIGHTS, type AreaLightSource } from '../../areaLights.ts';
|
|
132
|
+
import { MAX_AREA_LIGHTS, packAreaSizesAndDoors, type AreaLightSource } from '../../areaLights.ts';
|
|
133
133
|
import {
|
|
134
134
|
areaShadowLayerCount,
|
|
135
135
|
castingRange,
|
|
@@ -175,11 +175,18 @@ import {
|
|
|
175
175
|
import type { TextStyle } from '../../textLayout.ts';
|
|
176
176
|
import { deviceSnappedCellSize, deviceSnappedOrigin } from '../../textLayout.ts';
|
|
177
177
|
import { GpuSurfaceTexture } from './surfaceTexturePass.ts';
|
|
178
|
+
import { GpuSceneCaptureTarget } from './sceneCaptureTarget.ts';
|
|
179
|
+
import { sceneCaptureTexels } from '../../sceneCapture.ts';
|
|
178
180
|
import { gpuCompressedFormats } from './compressedUpload.ts';
|
|
179
181
|
import { GpuClothBinding, GpuClothParticles, clothStandIn } from './clothTextures.ts';
|
|
180
182
|
import type { ClothViews } from './clothTextures.ts';
|
|
181
183
|
import type { ComputeHost } from './computeHost.ts';
|
|
182
|
-
import {
|
|
184
|
+
import {
|
|
185
|
+
MODEL_PARAM_FLOATS,
|
|
186
|
+
eyeAxisInWorld,
|
|
187
|
+
packModel,
|
|
188
|
+
skinProfileDistance,
|
|
189
|
+
} from '../../surfaceModel.ts';
|
|
183
190
|
import type { SurfaceModel } from '../../surfaceModel.ts';
|
|
184
191
|
import { validateClothBinding } from '../../clothBindingData.ts';
|
|
185
192
|
import type { ClothBindingData } from '../../clothBindingData.ts';
|
|
@@ -337,7 +344,7 @@ import type { LineSegments } from '../../linePoints.ts';
|
|
|
337
344
|
import { buildPlumeGeometry } from '../../plumeGeometry.ts';
|
|
338
345
|
import type { ParticleMaterial } from '../../particleMaterial.ts';
|
|
339
346
|
import { facingCode, type ParticleBatchOptions } from '../../particleBatch.ts';
|
|
340
|
-
import type { ParticleInstances } from '../../particlePool.ts';
|
|
347
|
+
import type { DeviceParticles, ParticleInstances } from '../../particlePool.ts';
|
|
341
348
|
import { PARTICLE_INDICES } from '../../shaders/particle.ts';
|
|
342
349
|
import type { PlumeOptions, PlumePlacement } from '../../plumeRenderer.ts';
|
|
343
350
|
import type { InstanceData } from '../../instancedMesh.ts';
|
|
@@ -2948,6 +2955,110 @@ export class WebGPURenderer implements RendererApi {
|
|
|
2948
2955
|
});
|
|
2949
2956
|
}
|
|
2950
2957
|
|
|
2958
|
+
/**
|
|
2959
|
+
* A texture the scene can be drawn into, for a material to show. See `RendererApi` and
|
|
2960
|
+
* `sceneCapture.ts`. At the world's own format, which under `hdrScene` is half floats.
|
|
2961
|
+
*/
|
|
2962
|
+
createSceneCapture(width: number, height: number): GpuSurfaceTexture {
|
|
2963
|
+
const texture = new GpuSurfaceTexture(
|
|
2964
|
+
this.surface.device,
|
|
2965
|
+
this.pipelines,
|
|
2966
|
+
sceneCaptureTexels(width, height, this.quality.hdrScene),
|
|
2967
|
+
{ wrap: 'clamp', mipmap: false },
|
|
2968
|
+
);
|
|
2969
|
+
this.captureTargets.set(texture, new GpuSceneCaptureTarget(this.surface.device, width, height));
|
|
2970
|
+
return texture;
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
/** Each capture's attachments, beside the texture a material binds. */
|
|
2974
|
+
private readonly captureTargets = new WeakMap<GpuSurfaceTexture, GpuSceneCaptureTarget>();
|
|
2975
|
+
/**
|
|
2976
|
+
* Whether a scene capture is being drawn: an off-screen pass as a probe bake is, so the frame's
|
|
2977
|
+
* camera, jitter, motion, refraction copy, skin's spread and late routing are left alone, but
|
|
2978
|
+
* lit by the probes and DriftLight as the frame is. See `captureScene`.
|
|
2979
|
+
*/
|
|
2980
|
+
private capturePassActive = false;
|
|
2981
|
+
|
|
2982
|
+
/**
|
|
2983
|
+
* Draw the scene into a capture from `camera`. See `RendererApi.captureScene`.
|
|
2984
|
+
*
|
|
2985
|
+
* **Its own encoder, as a probe bake's**: the frame's pass is set aside and restored, the rings
|
|
2986
|
+
* are marked and rewound around the submit, and the frame graph is flushed at both boundaries so
|
|
2987
|
+
* no recorded draw crosses one. **Radiance**: the output transform and exposure are held off.
|
|
2988
|
+
*/
|
|
2989
|
+
captureScene(
|
|
2990
|
+
capture: GpuSurfaceTexture,
|
|
2991
|
+
camera: Camera,
|
|
2992
|
+
clearColor: Vec3,
|
|
2993
|
+
draw: (camera: Camera) => void,
|
|
2994
|
+
): boolean {
|
|
2995
|
+
if (this.surface.lost) return false;
|
|
2996
|
+
const target = this.captureTargets.get(capture);
|
|
2997
|
+
const resolve = capture.layerView();
|
|
2998
|
+
if (target === undefined || resolve === null) return false;
|
|
2999
|
+
camera.updateMatrices(target.width / target.height);
|
|
3000
|
+
const { device } = this.surface;
|
|
3001
|
+
const { depth, colorMsaa } = target.attachments(this.samples, this.pipelines.format);
|
|
3002
|
+
|
|
3003
|
+
const savedPass = this.pass;
|
|
3004
|
+
if (this.quality.frameGraph) this.flushGraph();
|
|
3005
|
+
const savedEncoder = this.encoder;
|
|
3006
|
+
this.markRings();
|
|
3007
|
+
const skinMark = this.skinPalettes.mark();
|
|
3008
|
+
const frameEpoch = this.encoderEpoch;
|
|
3009
|
+
this.encoderEpoch = ++this.encoderEpochs;
|
|
3010
|
+
const encoder = device.createCommandEncoder({ label: 'capture' });
|
|
3011
|
+
this.encoder = encoder;
|
|
3012
|
+
this.capturePassActive = true;
|
|
3013
|
+
const heldGrade = this.perFrameInts[this.materialField('uOutputTransform')] ?? 0;
|
|
3014
|
+
const heldExposure = this.perFrameFloats[this.materialField('uOutputExposure')] ?? 1;
|
|
3015
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = 0;
|
|
3016
|
+
this.perFrameFloats[this.materialField('uOutputExposure')] = 1;
|
|
3017
|
+
this.materials.dirty();
|
|
3018
|
+
const pass = encoder.beginRenderPass({
|
|
3019
|
+
label: 'capture',
|
|
3020
|
+
colorAttachments: [
|
|
3021
|
+
{
|
|
3022
|
+
view: colorMsaa ?? resolve,
|
|
3023
|
+
resolveTarget: colorMsaa === null ? undefined : resolve,
|
|
3024
|
+
loadOp: 'clear',
|
|
3025
|
+
storeOp: resolvedStoreOp(
|
|
3026
|
+
colorMsaa !== null,
|
|
3027
|
+
true,
|
|
3028
|
+
this.quality.discardResolvedAttachments,
|
|
3029
|
+
),
|
|
3030
|
+
clearValue: { r: clearColor[0], g: clearColor[1], b: clearColor[2], a: 1 },
|
|
3031
|
+
},
|
|
3032
|
+
],
|
|
3033
|
+
depthStencilAttachment: {
|
|
3034
|
+
view: depth,
|
|
3035
|
+
depthClearValue: DEPTH_CLEAR,
|
|
3036
|
+
depthLoadOp: 'clear',
|
|
3037
|
+
depthStoreOp: 'discard',
|
|
3038
|
+
},
|
|
3039
|
+
});
|
|
3040
|
+
this.pass = pass;
|
|
3041
|
+
try {
|
|
3042
|
+
draw(camera);
|
|
3043
|
+
/* The callback's draws replayed into this pass before it ends: see `bakeProbe`. */
|
|
3044
|
+
if (this.quality.frameGraph) this.flushGraph();
|
|
3045
|
+
} finally {
|
|
3046
|
+
pass.end();
|
|
3047
|
+
this.pass = null;
|
|
3048
|
+
this.flushRings();
|
|
3049
|
+
device.queue.submit([encoder.finish()]);
|
|
3050
|
+
this.rewindRings(skinMark);
|
|
3051
|
+
this.encoderEpoch = frameEpoch;
|
|
3052
|
+
this.encoder = savedEncoder;
|
|
3053
|
+
this.pass = savedPass;
|
|
3054
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = heldGrade;
|
|
3055
|
+
this.perFrameFloats[this.materialField('uOutputExposure')] = heldExposure;
|
|
3056
|
+
this.materials.dirty();
|
|
3057
|
+
this.capturePassActive = false;
|
|
3058
|
+
}
|
|
3059
|
+
return true;
|
|
3060
|
+
}
|
|
3061
|
+
|
|
2951
3062
|
/**
|
|
2952
3063
|
* GPU textures an `updateSurfaceTexture` replaced, destroyed when the next frame begins.
|
|
2953
3064
|
*
|
|
@@ -2996,6 +3107,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
2996
3107
|
if (this.modelMap === texture) this.modelMap = null;
|
|
2997
3108
|
this.forgetBindingsOf(texture);
|
|
2998
3109
|
texture.dispose();
|
|
3110
|
+
this.captureTargets.get(texture)?.dispose();
|
|
3111
|
+
this.captureTargets.delete(texture);
|
|
2999
3112
|
}
|
|
3000
3113
|
|
|
3001
3114
|
/**
|
|
@@ -3207,9 +3320,9 @@ export class WebGPURenderer implements RendererApi {
|
|
|
3207
3320
|
if (model?.kind === 'skin' && this.skinScatter !== null) {
|
|
3208
3321
|
this.skinScatter.setProfile(
|
|
3209
3322
|
model.profile,
|
|
3210
|
-
model
|
|
3211
|
-
model
|
|
3212
|
-
model
|
|
3323
|
+
skinProfileDistance(model, 0),
|
|
3324
|
+
skinProfileDistance(model, 1),
|
|
3325
|
+
skinProfileDistance(model, 2),
|
|
3213
3326
|
);
|
|
3214
3327
|
}
|
|
3215
3328
|
this.material((f, i) => {
|
|
@@ -3259,7 +3372,14 @@ export class WebGPURenderer implements RendererApi {
|
|
|
3259
3372
|
f[emissive + 1] = asked?.[1] ?? 1;
|
|
3260
3373
|
f[emissive + 2] = asked?.[2] ?? 1;
|
|
3261
3374
|
/* The model's numbers and whether its map is bound. See `packModel`. */
|
|
3262
|
-
packModel(
|
|
3375
|
+
packModel(
|
|
3376
|
+
material?.model ?? null,
|
|
3377
|
+
modelMap !== null,
|
|
3378
|
+
this.modelParams,
|
|
3379
|
+
material?.physicalSpecular === true,
|
|
3380
|
+
);
|
|
3381
|
+
/* The first physical highlight asked for is when the lit pipelines start carrying one. */
|
|
3382
|
+
if (material?.physicalSpecular === true) this.enableLit('PHYSICAL_SPECULAR');
|
|
3263
3383
|
f.set(this.modelParams, this.materialField('uModelParams'));
|
|
3264
3384
|
});
|
|
3265
3385
|
/*
|
|
@@ -4175,7 +4295,43 @@ export class WebGPURenderer implements RendererApi {
|
|
|
4175
4295
|
|
|
4176
4296
|
const device = this.surface.device;
|
|
4177
4297
|
device.queue.writeBuffer(batch.instances, 0, batch.staging, 0, live * PARTICLE_INSTANCE_FLOATS);
|
|
4298
|
+
this.drawParticleInstances(batch, batch.instances, live, camera, env, timeSeconds);
|
|
4299
|
+
}
|
|
4178
4300
|
|
|
4301
|
+
/**
|
|
4302
|
+
* Draw particles a caller's own compute wrote, where they lie. See `DeviceParticles`.
|
|
4303
|
+
*
|
|
4304
|
+
* **The pool's draw with its instance stream swapped**: the same material, blend, flipbook, soft
|
|
4305
|
+
* edge and fog, reading the caller's buffer in place of the one the pool uploads into — so nothing
|
|
4306
|
+
* crosses back to the CPU. Not sorted, and a count past what the buffer holds is cut to it rather
|
|
4307
|
+
* than handed to a draw the device would refuse with the frame.
|
|
4308
|
+
*/
|
|
4309
|
+
drawDeviceParticles(
|
|
4310
|
+
batch: GpuParticles,
|
|
4311
|
+
particles: DeviceParticles,
|
|
4312
|
+
camera: Camera,
|
|
4313
|
+
env: Environment,
|
|
4314
|
+
timeSeconds: number,
|
|
4315
|
+
): void {
|
|
4316
|
+
const fits = Math.floor(particles.buffer.size / (PARTICLE_INSTANCE_FLOATS * 4));
|
|
4317
|
+
const live = Math.min(Math.max(0, Math.floor(particles.count)), fits);
|
|
4318
|
+
/* Not above zero covers a NaN as well: a count or a size that is no number draws nothing. */
|
|
4319
|
+
if (!this.canDraw() || !(live > 0)) return;
|
|
4320
|
+
if (batch.drawnInEncoder === this.encoderEpoch) return;
|
|
4321
|
+
batch.drawnInEncoder = this.encoderEpoch;
|
|
4322
|
+
this.drawParticleInstances(batch, particles.buffer, live, camera, env, timeSeconds);
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
/** A pool's uniforms for this view, and its draw from `instances`: both entry points' tail. */
|
|
4326
|
+
private drawParticleInstances(
|
|
4327
|
+
batch: GpuParticles,
|
|
4328
|
+
instances: GPUBuffer,
|
|
4329
|
+
live: number,
|
|
4330
|
+
camera: Camera,
|
|
4331
|
+
env: Environment,
|
|
4332
|
+
timeSeconds: number,
|
|
4333
|
+
): void {
|
|
4334
|
+
const device = this.surface.device;
|
|
4179
4335
|
const v = batch.vertFloats;
|
|
4180
4336
|
const atV = (name: string): number => (PARTICLE_VERT_FIELDS[name]?.offset ?? -4) / 4;
|
|
4181
4337
|
mat4.multiply(this.correctedViewProj, CLIP_CORRECTION, camera.viewProjection);
|
|
@@ -4255,7 +4411,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
4255
4411
|
particleCommand.pipeline = particlePipe;
|
|
4256
4412
|
particleCommand.bindGroup = group;
|
|
4257
4413
|
particleCommand.vertexBuffers[0] = batch.corners;
|
|
4258
|
-
particleCommand.vertexBuffers[1] =
|
|
4414
|
+
particleCommand.vertexBuffers[1] = instances;
|
|
4259
4415
|
particleCommand.vertexCount = 2;
|
|
4260
4416
|
particleCommand.indexBuffer = batch.indexBuffer;
|
|
4261
4417
|
particleCommand.indexed = true;
|
|
@@ -4267,7 +4423,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
4267
4423
|
pass.setPipeline(particlePipe);
|
|
4268
4424
|
pass.setBindGroup(0, group);
|
|
4269
4425
|
pass.setVertexBuffer(0, batch.corners);
|
|
4270
|
-
pass.setVertexBuffer(1,
|
|
4426
|
+
pass.setVertexBuffer(1, instances);
|
|
4271
4427
|
pass.setIndexBuffer(batch.indexBuffer, 'uint32');
|
|
4272
4428
|
pass.drawIndexed(PARTICLE_INDICES, live);
|
|
4273
4429
|
}
|
|
@@ -4286,7 +4442,12 @@ export class WebGPURenderer implements RendererApi {
|
|
|
4286
4442
|
const fields = batch.fields;
|
|
4287
4443
|
const atF = (name: string): number => (fields[name]?.offset ?? -4) / 4;
|
|
4288
4444
|
let depth: GPUTextureView | null = null;
|
|
4289
|
-
if (
|
|
4445
|
+
if (
|
|
4446
|
+
batch.softDepth > 0 &&
|
|
4447
|
+
!this.reflectionPassActive &&
|
|
4448
|
+
!this.probePassActive &&
|
|
4449
|
+
!this.capturePassActive
|
|
4450
|
+
) {
|
|
4290
4451
|
if (this.openPass() !== null && this.takeVolumeDepth()) depth = this.resolvedDepthView;
|
|
4291
4452
|
if (depth === null && !this.warnedSpriteDepth) {
|
|
4292
4453
|
this.warnedSpriteDepth = true;
|
|
@@ -4660,6 +4821,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
4660
4821
|
scatterInto(f, WATER_FRAG_FIELDS['uLightRadius'], lights.radii, 1);
|
|
4661
4822
|
scatterInto(f, WATER_FRAG_FIELDS['uLightSourceRadius'], lights.sourceRadii, 1);
|
|
4662
4823
|
scatterInto(f, WATER_FRAG_FIELDS['uLightWeight'], lights.weights, 1);
|
|
4824
|
+
scatterInto(f, WATER_FRAG_FIELDS['uLightCone'], lights.conesAndFalloffs, 4);
|
|
4663
4825
|
|
|
4664
4826
|
const medium = resolveAtmosphere(
|
|
4665
4827
|
env,
|
|
@@ -5617,8 +5779,11 @@ export class WebGPURenderer implements RendererApi {
|
|
|
5617
5779
|
cookies: new Float32Array(0),
|
|
5618
5780
|
heldSourceRadii: new Float32Array(MAX_POINT_LIGHTS),
|
|
5619
5781
|
axesAndChannels: new Float32Array(MAX_POINT_LIGHTS * 4),
|
|
5782
|
+
conesAndFalloffs: new Float32Array(MAX_POINT_LIGHTS * 4),
|
|
5620
5783
|
heldWeights: new Float32Array(MAX_POINT_LIGHTS),
|
|
5621
5784
|
};
|
|
5785
|
+
/** The fixed arm's rectangles as `uAreaLightSize` holds them. See `packAreaSizesAndDoors`. */
|
|
5786
|
+
private readonly areaSizesAndDoors = new Float32Array(MAX_AREA_LIGHTS * 4);
|
|
5622
5787
|
/** Refilled per frame rather than allocated; see `resolveAtmosphere`. */
|
|
5623
5788
|
private readonly medium: ResolvedAtmosphere = {
|
|
5624
5789
|
fogColor: new Float32Array(3),
|
|
@@ -8217,7 +8382,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8217
8382
|
* the viewer sees, and bounding it through a mirrored camera puts it in the wrong half of the
|
|
8218
8383
|
* screen.
|
|
8219
8384
|
*/
|
|
8220
|
-
if (!this.reflectionPassActive) {
|
|
8385
|
+
if (!this.reflectionPassActive && !this.capturePassActive) {
|
|
8221
8386
|
mat4.copy(this.frameRawViewProj, camera.viewProjection);
|
|
8222
8387
|
/* The eye in world space, which the resolve's normals are turned to face. */
|
|
8223
8388
|
this.reconEye.set(camera.position);
|
|
@@ -8251,7 +8416,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8251
8416
|
* second temporal frame stepped the sequence twice a frame, so the world saw every other
|
|
8252
8417
|
* position and the anti-flicker's period never started.
|
|
8253
8418
|
*/
|
|
8254
|
-
|
|
8419
|
+
/* A capture has no resolve to undo a jitter and is no frame of the sequence. */
|
|
8420
|
+
if (this.framePresented || this.capturePassActive) this.viewProj = this.correctedViewProj;
|
|
8255
8421
|
else this.jitterFrame();
|
|
8256
8422
|
/*
|
|
8257
8423
|
* The frustum, once a frame, and from the **uncorrected** matrix.
|
|
@@ -8593,7 +8759,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8593
8759
|
* uniform added on one backend is bound on both in the same change.
|
|
8594
8760
|
*/
|
|
8595
8761
|
scatterInto(f, this.fragment.fields['uLightDir'], lights.directions, 3);
|
|
8596
|
-
|
|
8762
|
+
/* The cone and, in z, the light's own falloff exponent. See `conesAndFalloffs`. */
|
|
8763
|
+
scatterInto(f, this.fragment.fields['uLightCone'], lights.conesAndFalloffs, 4);
|
|
8597
8764
|
scatterInto(f, this.fragment.fields['uLightIesProfile'], lights.iesProfiles, 1);
|
|
8598
8765
|
/* The azimuth and, in w, the light's channels. See `axesAndChannels`. */
|
|
8599
8766
|
scatterInto(f, this.fragment.fields['uLightIesAxis'], lights.axesAndChannels, 4);
|
|
@@ -8615,7 +8782,9 @@ export class WebGPURenderer implements RendererApi {
|
|
|
8615
8782
|
scatterInto(f, this.fragment.fields['uAreaLightColor'], area.colors, 3);
|
|
8616
8783
|
scatterInto(f, this.fragment.fields['uAreaLightRight'], area.right, 3);
|
|
8617
8784
|
scatterInto(f, this.fragment.fields['uAreaLightUp'], area.up, 3);
|
|
8618
|
-
|
|
8785
|
+
/* The half extents and, in zw, the barn doors. See `packAreaSizesAndDoors`. */
|
|
8786
|
+
packAreaSizesAndDoors(area, this.areaSizesAndDoors);
|
|
8787
|
+
scatterInto(f, this.fragment.fields['uAreaLightSize'], this.areaSizesAndDoors, 4);
|
|
8619
8788
|
scatterInto(f, this.fragment.fields['uAreaLightTwoSided'], area.twoSided, 1);
|
|
8620
8789
|
}
|
|
8621
8790
|
|
|
@@ -11723,7 +11892,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
11723
11892
|
routesLate(
|
|
11724
11893
|
this.reconstructing,
|
|
11725
11894
|
this.reflectionPassActive,
|
|
11726
|
-
this.probePassActive,
|
|
11895
|
+
this.probePassActive || this.capturePassActive,
|
|
11727
11896
|
this.framePresented,
|
|
11728
11897
|
)
|
|
11729
11898
|
);
|
|
@@ -11803,7 +11972,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
11803
11972
|
return tracksMotion(
|
|
11804
11973
|
this.reconstructing,
|
|
11805
11974
|
this.reflectionPassActive,
|
|
11806
|
-
this.probePassActive,
|
|
11975
|
+
this.probePassActive || this.capturePassActive,
|
|
11807
11976
|
this.framePresented,
|
|
11808
11977
|
);
|
|
11809
11978
|
}
|
|
@@ -12260,6 +12429,8 @@ export class WebGPURenderer implements RendererApi {
|
|
|
12260
12429
|
f.set(surface.axis, base + at('uSsrAxis'));
|
|
12261
12430
|
f.set(surface.tint, base + at('uSsrTint'));
|
|
12262
12431
|
f[base + at('uSsrStrength')] = surface.strength;
|
|
12432
|
+
f[base + at('uSsrFresnel')] = surface.fresnel ? 1 : 0;
|
|
12433
|
+
f[base + at('uSsrFresnel') + 1] = surface.roughness;
|
|
12263
12434
|
f[base + at('uSsrFacingCos')] = surface.facingCos;
|
|
12264
12435
|
f[base + at('uSsrReach')] = surface.reachM;
|
|
12265
12436
|
f[base + at('uSsrThickness')] = surface.thicknessM;
|
|
@@ -12963,7 +13134,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
12963
13134
|
* glass, and a frame that refracts nothing breaks no pass at all.
|
|
12964
13135
|
*/
|
|
12965
13136
|
private takeRefractSnapshot(): boolean {
|
|
12966
|
-
if (this.reflectionPassActive || this.probePassActive) return false;
|
|
13137
|
+
if (this.reflectionPassActive || this.probePassActive || this.capturePassActive) return false;
|
|
12967
13138
|
if (this.refractSnapshotTaken) return true;
|
|
12968
13139
|
/* A late draw refracts the reconstructed picture, which does not exist until the resolve has
|
|
12969
13140
|
run; `runLate` takes the copy then, once, before any late draw is replayed. */
|
|
@@ -13044,6 +13215,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13044
13215
|
!this.skinScattered &&
|
|
13045
13216
|
!this.reflectionPassActive &&
|
|
13046
13217
|
!this.probePassActive &&
|
|
13218
|
+
!this.capturePassActive &&
|
|
13047
13219
|
!this.framePresented &&
|
|
13048
13220
|
!this.overlayActive &&
|
|
13049
13221
|
this.oitMode === 'none'
|
|
@@ -13133,6 +13305,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13133
13305
|
this.skinScattered = true;
|
|
13134
13306
|
if (!skin.pending) return;
|
|
13135
13307
|
if (this.reflectionPassActive || this.probePassActive || this.oitReplaying) return;
|
|
13308
|
+
if (this.capturePassActive) return;
|
|
13136
13309
|
const encoder = this.encoder;
|
|
13137
13310
|
const depth = this.depthView;
|
|
13138
13311
|
const resolved = this.resolvedDepthView;
|
|
@@ -13201,7 +13374,7 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13201
13374
|
* own terms: `resolvedDepthView` holds the *frame's* depth, and clamping a mirrored beam
|
|
13202
13375
|
* against it would stop it at geometry that is not in front of it.
|
|
13203
13376
|
*/
|
|
13204
|
-
if (this.reflectionPassActive) return false;
|
|
13377
|
+
if (this.reflectionPassActive || this.capturePassActive) return false;
|
|
13205
13378
|
if (this.resolvedDepthView === null) return false;
|
|
13206
13379
|
if (this.volumeDepthTaken) return true;
|
|
13207
13380
|
const encoder = this.encoder;
|
|
@@ -13761,7 +13934,9 @@ export class WebGPURenderer implements RendererApi {
|
|
|
13761
13934
|
* any future branch added to one belongs in the other.
|
|
13762
13935
|
*/
|
|
13763
13936
|
private targetPipelines(): PipelineCache {
|
|
13764
|
-
if (this.probePassActive || this.reflectionPassActive
|
|
13937
|
+
if (this.probePassActive || this.reflectionPassActive || this.capturePassActive) {
|
|
13938
|
+
return this.pipelines;
|
|
13939
|
+
}
|
|
13765
13940
|
return this.overlayActive || this.framePresented ? this.overlayPipelines : this.pipelines;
|
|
13766
13941
|
}
|
|
13767
13942
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DEPTH_FORMAT } from '../../depthConvention.ts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A scene capture's attachments on WebGPU: the depth and, above one sample, the multisampled colour
|
|
5
|
+
* its pass draws into and resolves from — the capture's own texture being the resolve, since **a
|
|
6
|
+
* texture cannot be both multisampled and sampled**. At the world's sample count and format, because
|
|
7
|
+
* a capture draws the world with the world's pipelines: a pipeline whose count or format disagrees
|
|
8
|
+
* with its attachment is rejected at `finish` and takes the whole capture with it. Remade only if
|
|
9
|
+
* either has changed since. See `sceneCapture.ts` for what a capture is.
|
|
10
|
+
*/
|
|
11
|
+
export class GpuSceneCaptureTarget {
|
|
12
|
+
private depth: GPUTexture | null = null;
|
|
13
|
+
private depthView: GPUTextureView | null = null;
|
|
14
|
+
private colorMsaa: GPUTexture | null = null;
|
|
15
|
+
private colorMsaaView: GPUTextureView | null = null;
|
|
16
|
+
private key = '';
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly device: GPUDevice,
|
|
20
|
+
readonly width: number,
|
|
21
|
+
readonly height: number,
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
attachments(
|
|
25
|
+
samples: number,
|
|
26
|
+
format: GPUTextureFormat,
|
|
27
|
+
): { depth: GPUTextureView; colorMsaa: GPUTextureView | null } {
|
|
28
|
+
const key = `${samples}:${format}`;
|
|
29
|
+
if (this.depthView === null || key !== this.key) {
|
|
30
|
+
this.dispose();
|
|
31
|
+
this.key = key;
|
|
32
|
+
this.depth = this.device.createTexture({
|
|
33
|
+
label: 'capture.depth',
|
|
34
|
+
size: [this.width, this.height],
|
|
35
|
+
format: DEPTH_FORMAT,
|
|
36
|
+
sampleCount: samples,
|
|
37
|
+
usage: 0x10, // RENDER_ATTACHMENT
|
|
38
|
+
});
|
|
39
|
+
this.depthView = this.depth.createView();
|
|
40
|
+
this.colorMsaa =
|
|
41
|
+
samples > 1
|
|
42
|
+
? this.device.createTexture({
|
|
43
|
+
label: 'capture.colorMsaa',
|
|
44
|
+
size: [this.width, this.height],
|
|
45
|
+
format,
|
|
46
|
+
sampleCount: samples,
|
|
47
|
+
usage: 0x10, // RENDER_ATTACHMENT
|
|
48
|
+
})
|
|
49
|
+
: null;
|
|
50
|
+
this.colorMsaaView = this.colorMsaa?.createView() ?? null;
|
|
51
|
+
}
|
|
52
|
+
return { depth: this.depthView as GPUTextureView, colorMsaa: this.colorMsaaView };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
dispose(): void {
|
|
56
|
+
this.depth?.destroy();
|
|
57
|
+
this.colorMsaa?.destroy();
|
|
58
|
+
this.depth = null;
|
|
59
|
+
this.depthView = null;
|
|
60
|
+
this.colorMsaa = null;
|
|
61
|
+
this.colorMsaaView = null;
|
|
62
|
+
}
|
|
63
|
+
}
|