@multiplekex/shallot 0.2.4 → 0.3.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/package.json +1 -1
- package/src/core/component.ts +1 -1
- package/src/core/index.ts +1 -13
- package/src/core/math.ts +186 -0
- package/src/core/state.ts +1 -1
- package/src/core/xml.ts +56 -41
- package/src/extras/arrows/index.ts +3 -3
- package/src/extras/caustic.ts +37 -0
- package/src/extras/gradient/index.ts +63 -69
- package/src/extras/index.ts +3 -0
- package/src/extras/lines/index.ts +3 -3
- package/src/extras/orbit/index.ts +1 -1
- package/src/extras/skylab/index.ts +314 -0
- package/src/extras/text/font.ts +69 -14
- package/src/extras/text/index.ts +17 -69
- package/src/extras/text/sdf.ts +13 -2
- package/src/extras/water/index.ts +119 -0
- package/src/standard/defaults.ts +2 -0
- package/src/standard/index.ts +2 -0
- package/src/standard/raster/batch.ts +149 -0
- package/src/standard/raster/forward.ts +832 -0
- package/src/standard/raster/index.ts +191 -0
- package/src/standard/raster/shadow.ts +408 -0
- package/src/standard/{render → raytracing}/bvh/blas.ts +336 -88
- package/src/standard/raytracing/bvh/radix.ts +473 -0
- package/src/standard/raytracing/bvh/refit.ts +711 -0
- package/src/standard/{render → raytracing}/bvh/structs.ts +0 -55
- package/src/standard/{render → raytracing}/bvh/tlas.ts +155 -140
- package/src/standard/{render → raytracing}/bvh/traverse.ts +72 -64
- package/src/standard/{render → raytracing}/depth.ts +9 -9
- package/src/standard/raytracing/index.ts +409 -0
- package/src/standard/{render → raytracing}/instance.ts +31 -16
- package/src/standard/{render → raytracing}/ray.ts +1 -1
- package/src/standard/raytracing/shaders.ts +798 -0
- package/src/standard/{render → raytracing}/triangle.ts +1 -1
- package/src/standard/render/camera.ts +96 -106
- package/src/standard/render/data.ts +1 -1
- package/src/standard/render/index.ts +136 -220
- package/src/standard/render/indirect.ts +9 -10
- package/src/standard/render/light.ts +2 -2
- package/src/standard/render/mesh.ts +404 -0
- package/src/standard/render/overlay.ts +8 -5
- package/src/standard/render/pass.ts +1 -1
- package/src/standard/render/postprocess.ts +263 -242
- package/src/standard/render/scene.ts +28 -16
- package/src/standard/render/surface/index.ts +81 -12
- package/src/standard/render/surface/shaders.ts +511 -0
- package/src/standard/render/surface/structs.ts +23 -6
- package/src/standard/tween/tween.ts +44 -115
- package/src/standard/render/bvh/radix.ts +0 -476
- package/src/standard/render/forward/index.ts +0 -259
- package/src/standard/render/forward/raster.ts +0 -228
- package/src/standard/render/mesh/box.ts +0 -20
- package/src/standard/render/mesh/index.ts +0 -446
- package/src/standard/render/mesh/plane.ts +0 -11
- package/src/standard/render/mesh/sphere.ts +0 -40
- package/src/standard/render/mesh/unified.ts +0 -96
- package/src/standard/render/shaders.ts +0 -484
- package/src/standard/render/surface/compile.ts +0 -67
- package/src/standard/render/surface/noise.ts +0 -45
- package/src/standard/render/surface/wgsl.ts +0 -573
- /package/src/standard/{render → raytracing}/intersection.ts +0 -0
|
@@ -120,7 +120,6 @@ fn applyVignette(color: vec3f, uv: vec2f) -> vec3f {
|
|
|
120
120
|
|
|
121
121
|
fn sampleBloom(uv: vec2f) -> vec3f {
|
|
122
122
|
let texelSize = vec2f(uniforms.texelSizeX, uniforms.texelSizeY);
|
|
123
|
-
// Normalize to reference height (1080p) for resolution-independent bloom
|
|
124
123
|
let height = 1.0 / uniforms.texelSizeY;
|
|
125
124
|
let resolutionScale = height / 1080.0;
|
|
126
125
|
let spread = uniforms.bloomRadius * 4.0 * resolutionScale;
|
|
@@ -130,7 +129,6 @@ fn sampleBloom(uv: vec2f) -> vec3f {
|
|
|
130
129
|
var bloom = vec3f(0.0);
|
|
131
130
|
var totalWeight = 0.0;
|
|
132
131
|
|
|
133
|
-
// 9x9 kernel with gaussian weights
|
|
134
132
|
for (var y = -4; y <= 4; y++) {
|
|
135
133
|
for (var x = -4; x <= 4; x++) {
|
|
136
134
|
let offset = vec2f(f32(x), f32(y)) * texelSize * spread;
|
|
@@ -165,7 +163,6 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
|
165
163
|
color = select(fxaaColor, color, maskValue >= 0.5);
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
// Bloom applied before tonemapping
|
|
169
166
|
if (uniforms.flags & FLAG_BLOOM) != 0u {
|
|
170
167
|
let bloom = sampleBloom(input.uv);
|
|
171
168
|
color += bloom * uniforms.bloomIntensity;
|
|
@@ -244,12 +241,267 @@ export interface PostProcessConfig {
|
|
|
244
241
|
getRenderSize?: () => { width: number; height: number };
|
|
245
242
|
}
|
|
246
243
|
|
|
244
|
+
interface PostProcessGPU {
|
|
245
|
+
pipeline: GPURenderPipeline;
|
|
246
|
+
blitPipeline: GPURenderPipeline;
|
|
247
|
+
uniformBuffer: GPUBuffer;
|
|
248
|
+
uniformData: ArrayBuffer;
|
|
249
|
+
uniformFloats: Float32Array;
|
|
250
|
+
uniformUints: Uint32Array;
|
|
251
|
+
linearSampler: GPUSampler;
|
|
252
|
+
nearestSampler: GPUSampler;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
interface PostProcessCache {
|
|
256
|
+
mainBindGroup: GPUBindGroup | null;
|
|
257
|
+
blitBindGroup: GPUBindGroup | null;
|
|
258
|
+
inputView: GPUTextureView | null;
|
|
259
|
+
sampler: GPUSampler | null;
|
|
260
|
+
maskView: GPUTextureView | null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async function preparePostProcess(device: GPUDevice): Promise<PostProcessGPU> {
|
|
264
|
+
const format: GPUTextureFormat = "bgra8unorm";
|
|
265
|
+
|
|
266
|
+
const [mainModule, blitModule] = await Promise.all([
|
|
267
|
+
device.createShaderModule({ code: shader }),
|
|
268
|
+
device.createShaderModule({ code: blitShader }),
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
const [pipeline, blitPipeline] = await Promise.all([
|
|
272
|
+
device.createRenderPipelineAsync({
|
|
273
|
+
layout: "auto",
|
|
274
|
+
vertex: { module: mainModule, entryPoint: "vertexMain" },
|
|
275
|
+
fragment: {
|
|
276
|
+
module: mainModule,
|
|
277
|
+
entryPoint: "fragmentMain",
|
|
278
|
+
targets: [{ format }],
|
|
279
|
+
},
|
|
280
|
+
primitive: { topology: "triangle-list" },
|
|
281
|
+
}),
|
|
282
|
+
device.createRenderPipelineAsync({
|
|
283
|
+
layout: "auto",
|
|
284
|
+
vertex: { module: blitModule, entryPoint: "vertexMain" },
|
|
285
|
+
fragment: {
|
|
286
|
+
module: blitModule,
|
|
287
|
+
entryPoint: "fragmentMain",
|
|
288
|
+
targets: [{ format }],
|
|
289
|
+
},
|
|
290
|
+
primitive: { topology: "triangle-list" },
|
|
291
|
+
}),
|
|
292
|
+
]);
|
|
293
|
+
|
|
294
|
+
const uniformData = new ArrayBuffer(48);
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
pipeline,
|
|
298
|
+
blitPipeline,
|
|
299
|
+
uniformBuffer: device.createBuffer({
|
|
300
|
+
size: 48,
|
|
301
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
302
|
+
}),
|
|
303
|
+
uniformData,
|
|
304
|
+
uniformFloats: new Float32Array(uniformData),
|
|
305
|
+
uniformUints: new Uint32Array(uniformData),
|
|
306
|
+
linearSampler: device.createSampler({ magFilter: "linear", minFilter: "linear" }),
|
|
307
|
+
nearestSampler: device.createSampler({ magFilter: "nearest", minFilter: "nearest" }),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function blitToCanvas(
|
|
312
|
+
encoder: GPUCommandEncoder,
|
|
313
|
+
pipeline: GPURenderPipeline,
|
|
314
|
+
bindGroup: GPUBindGroup,
|
|
315
|
+
canvasView: GPUTextureView
|
|
316
|
+
): void {
|
|
317
|
+
const pass = encoder.beginRenderPass({
|
|
318
|
+
colorAttachments: [
|
|
319
|
+
{
|
|
320
|
+
view: canvasView,
|
|
321
|
+
loadOp: "clear" as const,
|
|
322
|
+
storeOp: "store" as const,
|
|
323
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
});
|
|
327
|
+
pass.setPipeline(pipeline);
|
|
328
|
+
pass.setBindGroup(0, bindGroup);
|
|
329
|
+
pass.draw(3);
|
|
330
|
+
pass.end();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function executeContributors(
|
|
334
|
+
contributors: { execute: (ctx: DrawContext) => void }[],
|
|
335
|
+
baseCtx: Omit<DrawContext, "inputView" | "outputView">,
|
|
336
|
+
pingAView: GPUTextureView,
|
|
337
|
+
pingBView: GPUTextureView,
|
|
338
|
+
currentInput: GPUTextureView,
|
|
339
|
+
pingPong: boolean
|
|
340
|
+
): { currentInput: GPUTextureView; pingPong: boolean } {
|
|
341
|
+
for (const contributor of contributors) {
|
|
342
|
+
const currentOutput = pingPong ? pingAView : pingBView;
|
|
343
|
+
contributor.execute({
|
|
344
|
+
...baseCtx,
|
|
345
|
+
inputView: currentInput,
|
|
346
|
+
outputView: currentOutput,
|
|
347
|
+
});
|
|
348
|
+
currentInput = currentOutput;
|
|
349
|
+
pingPong = !pingPong;
|
|
350
|
+
}
|
|
351
|
+
return { currentInput, pingPong };
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function ensureBlitBindGroup(
|
|
355
|
+
device: GPUDevice,
|
|
356
|
+
gpu: PostProcessGPU,
|
|
357
|
+
cache: PostProcessCache,
|
|
358
|
+
inputView: GPUTextureView,
|
|
359
|
+
sampler: GPUSampler
|
|
360
|
+
): GPUBindGroup {
|
|
361
|
+
if (inputView !== cache.inputView || sampler !== cache.sampler) {
|
|
362
|
+
cache.blitBindGroup = device.createBindGroup({
|
|
363
|
+
layout: gpu.blitPipeline.getBindGroupLayout(0),
|
|
364
|
+
entries: [
|
|
365
|
+
{ binding: 0, resource: inputView },
|
|
366
|
+
{ binding: 1, resource: sampler },
|
|
367
|
+
],
|
|
368
|
+
});
|
|
369
|
+
cache.inputView = inputView;
|
|
370
|
+
cache.sampler = sampler;
|
|
371
|
+
}
|
|
372
|
+
return cache.blitBindGroup!;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function executePostProcess(
|
|
376
|
+
gpu: PostProcessGPU,
|
|
377
|
+
cache: PostProcessCache,
|
|
378
|
+
ctx: ExecutionContext,
|
|
379
|
+
config: PostProcessConfig
|
|
380
|
+
): void {
|
|
381
|
+
const { device, encoder, canvasView, format, context } = ctx;
|
|
382
|
+
const width = context.canvas.width;
|
|
383
|
+
const height = context.canvas.height;
|
|
384
|
+
const colorView = ctx.getTextureView("color")!;
|
|
385
|
+
const maskView = ctx.getTextureView("mask")!;
|
|
386
|
+
const zView = ctx.getTextureView("z")!;
|
|
387
|
+
const eidView = ctx.getTextureView("eid")!;
|
|
388
|
+
const pingAView = ctx.getTextureView("pingA")!;
|
|
389
|
+
const pingBView = ctx.getTextureView("pingB")!;
|
|
390
|
+
|
|
391
|
+
const renderSize = config.getRenderSize?.();
|
|
392
|
+
const isUpscaling = renderSize && (renderSize.width !== width || renderSize.height !== height);
|
|
393
|
+
const sampler = isUpscaling ? gpu.nearestSampler : gpu.linearSampler;
|
|
394
|
+
|
|
395
|
+
let currentInput = colorView;
|
|
396
|
+
let pingPong = false;
|
|
397
|
+
|
|
398
|
+
const baseCtx = {
|
|
399
|
+
device,
|
|
400
|
+
encoder,
|
|
401
|
+
format,
|
|
402
|
+
width,
|
|
403
|
+
height,
|
|
404
|
+
sceneView: colorView,
|
|
405
|
+
zView,
|
|
406
|
+
entityIdView: eidView,
|
|
407
|
+
maskView,
|
|
408
|
+
canvasView,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
const beforePostProcess = getDrawsByPass(config.state, Pass.BeforePost);
|
|
412
|
+
({ currentInput, pingPong } = executeContributors(
|
|
413
|
+
beforePostProcess,
|
|
414
|
+
baseCtx,
|
|
415
|
+
pingAView,
|
|
416
|
+
pingBView,
|
|
417
|
+
currentInput,
|
|
418
|
+
pingPong
|
|
419
|
+
));
|
|
420
|
+
|
|
421
|
+
const postProcessContributors = getDrawsByPass(config.state, Pass.Post);
|
|
422
|
+
const hasBuiltinEffects =
|
|
423
|
+
config.uniforms.tonemap ||
|
|
424
|
+
config.uniforms.fxaa ||
|
|
425
|
+
config.uniforms.vignetteStrength > 0 ||
|
|
426
|
+
config.uniforms.bloomIntensity > 0 ||
|
|
427
|
+
config.uniforms.quantize > 0;
|
|
428
|
+
|
|
429
|
+
if (hasBuiltinEffects || postProcessContributors.length > 0) {
|
|
430
|
+
({ currentInput, pingPong } = executeContributors(
|
|
431
|
+
postProcessContributors,
|
|
432
|
+
baseCtx,
|
|
433
|
+
pingAView,
|
|
434
|
+
pingBView,
|
|
435
|
+
currentInput,
|
|
436
|
+
pingPong
|
|
437
|
+
));
|
|
438
|
+
|
|
439
|
+
if (hasBuiltinEffects) {
|
|
440
|
+
let flags = 0;
|
|
441
|
+
if (config.uniforms.tonemap) flags |= FLAG_TONEMAP;
|
|
442
|
+
if (config.uniforms.fxaa) flags |= FLAG_FXAA;
|
|
443
|
+
if (config.uniforms.vignetteStrength > 0) flags |= FLAG_VIGNETTE;
|
|
444
|
+
if (config.uniforms.bloomIntensity > 0) flags |= FLAG_BLOOM;
|
|
445
|
+
if (config.uniforms.quantize > 0) flags |= FLAG_QUANTIZE;
|
|
446
|
+
|
|
447
|
+
gpu.uniformFloats[0] = config.uniforms.exposure;
|
|
448
|
+
gpu.uniformFloats[1] = config.uniforms.vignetteStrength;
|
|
449
|
+
gpu.uniformFloats[2] = config.uniforms.vignetteInner;
|
|
450
|
+
gpu.uniformFloats[3] = config.uniforms.vignetteOuter;
|
|
451
|
+
gpu.uniformFloats[4] = 1.0 / width;
|
|
452
|
+
gpu.uniformFloats[5] = 1.0 / height;
|
|
453
|
+
gpu.uniformUints[6] = flags;
|
|
454
|
+
gpu.uniformFloats[7] = config.uniforms.bloomIntensity;
|
|
455
|
+
gpu.uniformFloats[8] = config.uniforms.bloomThreshold;
|
|
456
|
+
gpu.uniformFloats[9] = config.uniforms.bloomRadius;
|
|
457
|
+
gpu.uniformFloats[10] = config.uniforms.quantize;
|
|
458
|
+
|
|
459
|
+
device.queue.writeBuffer(gpu.uniformBuffer, 0, gpu.uniformData);
|
|
460
|
+
|
|
461
|
+
if (
|
|
462
|
+
currentInput !== cache.inputView ||
|
|
463
|
+
sampler !== cache.sampler ||
|
|
464
|
+
maskView !== cache.maskView
|
|
465
|
+
) {
|
|
466
|
+
cache.mainBindGroup = device.createBindGroup({
|
|
467
|
+
layout: gpu.pipeline.getBindGroupLayout(0),
|
|
468
|
+
entries: [
|
|
469
|
+
{ binding: 0, resource: currentInput },
|
|
470
|
+
{ binding: 1, resource: sampler },
|
|
471
|
+
{ binding: 2, resource: { buffer: gpu.uniformBuffer } },
|
|
472
|
+
{ binding: 3, resource: maskView },
|
|
473
|
+
],
|
|
474
|
+
});
|
|
475
|
+
cache.inputView = currentInput;
|
|
476
|
+
cache.sampler = sampler;
|
|
477
|
+
cache.maskView = maskView;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
blitToCanvas(encoder, gpu.pipeline, cache.mainBindGroup!, canvasView);
|
|
481
|
+
} else {
|
|
482
|
+
const bindGroup = ensureBlitBindGroup(device, gpu, cache, currentInput, sampler);
|
|
483
|
+
blitToCanvas(encoder, gpu.blitPipeline, bindGroup, canvasView);
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
const bindGroup = ensureBlitBindGroup(device, gpu, cache, currentInput, sampler);
|
|
487
|
+
blitToCanvas(encoder, gpu.blitPipeline, bindGroup, canvasView);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const afterPostProcess = getDrawsByPass(config.state, Pass.AfterPost);
|
|
491
|
+
for (const contributor of afterPostProcess) {
|
|
492
|
+
contributor.execute(baseCtx);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
247
496
|
export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
248
|
-
let
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
497
|
+
let gpu: PostProcessGPU | null = null;
|
|
498
|
+
const cache: PostProcessCache = {
|
|
499
|
+
mainBindGroup: null,
|
|
500
|
+
blitBindGroup: null,
|
|
501
|
+
inputView: null,
|
|
502
|
+
sampler: null,
|
|
503
|
+
maskView: null,
|
|
504
|
+
};
|
|
253
505
|
|
|
254
506
|
return {
|
|
255
507
|
id: "postprocess",
|
|
@@ -262,243 +514,12 @@ export function createPostProcessNode(config: PostProcessConfig): ComputeNode {
|
|
|
262
514
|
outputs: [{ id: "framebuffer", access: "write" }],
|
|
263
515
|
|
|
264
516
|
async prepare(device: GPUDevice) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const [mainModule, blitModule] = await Promise.all([
|
|
268
|
-
device.createShaderModule({ code: shader }),
|
|
269
|
-
device.createShaderModule({ code: blitShader }),
|
|
270
|
-
]);
|
|
271
|
-
|
|
272
|
-
[pipeline, blitPipeline] = await Promise.all([
|
|
273
|
-
device.createRenderPipelineAsync({
|
|
274
|
-
layout: "auto",
|
|
275
|
-
vertex: { module: mainModule, entryPoint: "vertexMain" },
|
|
276
|
-
fragment: {
|
|
277
|
-
module: mainModule,
|
|
278
|
-
entryPoint: "fragmentMain",
|
|
279
|
-
targets: [{ format }],
|
|
280
|
-
},
|
|
281
|
-
primitive: { topology: "triangle-list" },
|
|
282
|
-
}),
|
|
283
|
-
device.createRenderPipelineAsync({
|
|
284
|
-
layout: "auto",
|
|
285
|
-
vertex: { module: blitModule, entryPoint: "vertexMain" },
|
|
286
|
-
fragment: {
|
|
287
|
-
module: blitModule,
|
|
288
|
-
entryPoint: "fragmentMain",
|
|
289
|
-
targets: [{ format }],
|
|
290
|
-
},
|
|
291
|
-
primitive: { topology: "triangle-list" },
|
|
292
|
-
}),
|
|
293
|
-
]);
|
|
294
|
-
|
|
295
|
-
uniformBuffer = device.createBuffer({
|
|
296
|
-
size: 48,
|
|
297
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
linearSampler = device.createSampler({
|
|
301
|
-
magFilter: "linear",
|
|
302
|
-
minFilter: "linear",
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
nearestSampler = device.createSampler({
|
|
306
|
-
magFilter: "nearest",
|
|
307
|
-
minFilter: "nearest",
|
|
308
|
-
});
|
|
517
|
+
gpu = await preparePostProcess(device);
|
|
309
518
|
},
|
|
310
519
|
|
|
311
520
|
execute(ctx: ExecutionContext) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const height = context.canvas.height;
|
|
315
|
-
const colorView = ctx.getTextureView("color")!;
|
|
316
|
-
const maskView = ctx.getTextureView("mask")!;
|
|
317
|
-
const depthView = ctx.getTextureView("depth")!;
|
|
318
|
-
const eidView = ctx.getTextureView("eid")!;
|
|
319
|
-
const pingAView = ctx.getTextureView("pingA")!;
|
|
320
|
-
const pingBView = ctx.getTextureView("pingB")!;
|
|
321
|
-
|
|
322
|
-
const renderSize = config.getRenderSize?.();
|
|
323
|
-
const isUpscaling =
|
|
324
|
-
renderSize && (renderSize.width !== width || renderSize.height !== height);
|
|
325
|
-
const sampler = isUpscaling ? nearestSampler! : linearSampler!;
|
|
326
|
-
|
|
327
|
-
let currentInput = colorView;
|
|
328
|
-
let currentOutput = pingAView;
|
|
329
|
-
let pingPong = false;
|
|
330
|
-
|
|
331
|
-
const beforePostProcess = getDrawsByPass(config.state, Pass.BeforePost);
|
|
332
|
-
for (const contributor of beforePostProcess) {
|
|
333
|
-
const passCtx: DrawContext = {
|
|
334
|
-
device,
|
|
335
|
-
encoder,
|
|
336
|
-
format,
|
|
337
|
-
width,
|
|
338
|
-
height,
|
|
339
|
-
sceneView: colorView,
|
|
340
|
-
depthView,
|
|
341
|
-
entityIdView: eidView,
|
|
342
|
-
maskView,
|
|
343
|
-
canvasView,
|
|
344
|
-
inputView: currentInput,
|
|
345
|
-
outputView: currentOutput,
|
|
346
|
-
};
|
|
347
|
-
contributor.execute(passCtx);
|
|
348
|
-
|
|
349
|
-
currentInput = currentOutput;
|
|
350
|
-
currentOutput = pingPong ? pingAView : pingBView;
|
|
351
|
-
pingPong = !pingPong;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const postProcessContributors = getDrawsByPass(config.state, Pass.Post);
|
|
355
|
-
const hasBuiltinEffects =
|
|
356
|
-
config.uniforms.tonemap ||
|
|
357
|
-
config.uniforms.fxaa ||
|
|
358
|
-
config.uniforms.vignetteStrength > 0 ||
|
|
359
|
-
config.uniforms.bloomIntensity > 0 ||
|
|
360
|
-
config.uniforms.quantize > 0;
|
|
361
|
-
|
|
362
|
-
if (hasBuiltinEffects || postProcessContributors.length > 0) {
|
|
363
|
-
for (const contributor of postProcessContributors) {
|
|
364
|
-
const passCtx: DrawContext = {
|
|
365
|
-
device,
|
|
366
|
-
encoder,
|
|
367
|
-
format,
|
|
368
|
-
width,
|
|
369
|
-
height,
|
|
370
|
-
sceneView: colorView,
|
|
371
|
-
depthView,
|
|
372
|
-
entityIdView: eidView,
|
|
373
|
-
maskView,
|
|
374
|
-
canvasView,
|
|
375
|
-
inputView: currentInput,
|
|
376
|
-
outputView: currentOutput,
|
|
377
|
-
};
|
|
378
|
-
contributor.execute(passCtx);
|
|
379
|
-
|
|
380
|
-
currentInput = currentOutput;
|
|
381
|
-
currentOutput = pingPong ? pingAView : pingBView;
|
|
382
|
-
pingPong = !pingPong;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (hasBuiltinEffects) {
|
|
386
|
-
let flags = 0;
|
|
387
|
-
if (config.uniforms.tonemap) flags |= FLAG_TONEMAP;
|
|
388
|
-
if (config.uniforms.fxaa) flags |= FLAG_FXAA;
|
|
389
|
-
if (config.uniforms.vignetteStrength > 0) flags |= FLAG_VIGNETTE;
|
|
390
|
-
if (config.uniforms.bloomIntensity > 0) flags |= FLAG_BLOOM;
|
|
391
|
-
if (config.uniforms.quantize > 0) flags |= FLAG_QUANTIZE;
|
|
392
|
-
|
|
393
|
-
const data = new ArrayBuffer(48);
|
|
394
|
-
const floats = new Float32Array(data);
|
|
395
|
-
const uints = new Uint32Array(data);
|
|
396
|
-
floats[0] = config.uniforms.exposure;
|
|
397
|
-
floats[1] = config.uniforms.vignetteStrength;
|
|
398
|
-
floats[2] = config.uniforms.vignetteInner;
|
|
399
|
-
floats[3] = config.uniforms.vignetteOuter;
|
|
400
|
-
floats[4] = 1.0 / width;
|
|
401
|
-
floats[5] = 1.0 / height;
|
|
402
|
-
uints[6] = flags;
|
|
403
|
-
floats[7] = config.uniforms.bloomIntensity;
|
|
404
|
-
floats[8] = config.uniforms.bloomThreshold;
|
|
405
|
-
floats[9] = config.uniforms.bloomRadius;
|
|
406
|
-
floats[10] = config.uniforms.quantize;
|
|
407
|
-
|
|
408
|
-
device.queue.writeBuffer(uniformBuffer!, 0, data);
|
|
409
|
-
|
|
410
|
-
const bindGroup = device.createBindGroup({
|
|
411
|
-
layout: pipeline!.getBindGroupLayout(0),
|
|
412
|
-
entries: [
|
|
413
|
-
{ binding: 0, resource: currentInput },
|
|
414
|
-
{ binding: 1, resource: sampler },
|
|
415
|
-
{ binding: 2, resource: { buffer: uniformBuffer! } },
|
|
416
|
-
{ binding: 3, resource: maskView },
|
|
417
|
-
],
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
const pass = encoder.beginRenderPass({
|
|
421
|
-
colorAttachments: [
|
|
422
|
-
{
|
|
423
|
-
view: canvasView,
|
|
424
|
-
loadOp: "clear" as const,
|
|
425
|
-
storeOp: "store" as const,
|
|
426
|
-
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
427
|
-
},
|
|
428
|
-
],
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
pass.setPipeline(pipeline!);
|
|
432
|
-
pass.setBindGroup(0, bindGroup);
|
|
433
|
-
pass.draw(3);
|
|
434
|
-
pass.end();
|
|
435
|
-
} else {
|
|
436
|
-
const bindGroup = device.createBindGroup({
|
|
437
|
-
layout: blitPipeline!.getBindGroupLayout(0),
|
|
438
|
-
entries: [
|
|
439
|
-
{ binding: 0, resource: currentInput },
|
|
440
|
-
{ binding: 1, resource: sampler },
|
|
441
|
-
],
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
const pass = encoder.beginRenderPass({
|
|
445
|
-
colorAttachments: [
|
|
446
|
-
{
|
|
447
|
-
view: canvasView,
|
|
448
|
-
loadOp: "clear" as const,
|
|
449
|
-
storeOp: "store" as const,
|
|
450
|
-
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
pass.setPipeline(blitPipeline!);
|
|
456
|
-
pass.setBindGroup(0, bindGroup);
|
|
457
|
-
pass.draw(3);
|
|
458
|
-
pass.end();
|
|
459
|
-
}
|
|
460
|
-
} else {
|
|
461
|
-
const bindGroup = device.createBindGroup({
|
|
462
|
-
layout: blitPipeline!.getBindGroupLayout(0),
|
|
463
|
-
entries: [
|
|
464
|
-
{ binding: 0, resource: currentInput },
|
|
465
|
-
{ binding: 1, resource: sampler },
|
|
466
|
-
],
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
const pass = encoder.beginRenderPass({
|
|
470
|
-
colorAttachments: [
|
|
471
|
-
{
|
|
472
|
-
view: canvasView,
|
|
473
|
-
loadOp: "clear" as const,
|
|
474
|
-
storeOp: "store" as const,
|
|
475
|
-
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
476
|
-
},
|
|
477
|
-
],
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
pass.setPipeline(blitPipeline!);
|
|
481
|
-
pass.setBindGroup(0, bindGroup);
|
|
482
|
-
pass.draw(3);
|
|
483
|
-
pass.end();
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const afterPostProcess = getDrawsByPass(config.state, Pass.AfterPost);
|
|
487
|
-
for (const contributor of afterPostProcess) {
|
|
488
|
-
const passCtx: DrawContext = {
|
|
489
|
-
device,
|
|
490
|
-
encoder,
|
|
491
|
-
format,
|
|
492
|
-
width,
|
|
493
|
-
height,
|
|
494
|
-
sceneView: colorView,
|
|
495
|
-
depthView,
|
|
496
|
-
entityIdView: eidView,
|
|
497
|
-
maskView,
|
|
498
|
-
canvasView,
|
|
499
|
-
};
|
|
500
|
-
contributor.execute(passCtx);
|
|
501
|
-
}
|
|
521
|
+
if (!gpu) return;
|
|
522
|
+
executePostProcess(gpu, cache, ctx, config);
|
|
502
523
|
},
|
|
503
524
|
};
|
|
504
525
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export const SCENE_UNIFORM_SIZE =
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
1
|
+
export const SCENE_UNIFORM_SIZE = 352;
|
|
2
|
+
export const SKY_UNIFORM_SIZE = 176;
|
|
3
|
+
export const Z_FORMAT: GPUTextureFormat = "depth24plus";
|
|
4
|
+
export const DEPTH_FORMAT: GPUTextureFormat = "r32float";
|
|
4
5
|
export const MASK_FORMAT: GPUTextureFormat = "r8unorm";
|
|
5
6
|
export const EID_FORMAT: GPUTextureFormat = "r32uint";
|
|
6
7
|
export const COLOR_FORMAT: GPUTextureFormat = "rgba8unorm";
|
|
@@ -13,6 +14,14 @@ export function createSceneBuffer(device: GPUDevice): GPUBuffer {
|
|
|
13
14
|
});
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
export function createSkyBuffer(device: GPUDevice): GPUBuffer {
|
|
18
|
+
return device.createBuffer({
|
|
19
|
+
label: "sky",
|
|
20
|
+
size: SKY_UNIFORM_SIZE,
|
|
21
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
export function ensureTextures(
|
|
17
26
|
device: GPUDevice,
|
|
18
27
|
format: GPUTextureFormat,
|
|
@@ -25,9 +34,9 @@ export function ensureTextures(
|
|
|
25
34
|
if (existing && existing.width === width && existing.height === height) return;
|
|
26
35
|
|
|
27
36
|
existing?.destroy();
|
|
28
|
-
textures.get("linear-depth")?.destroy();
|
|
29
|
-
textures.get("eid")?.destroy();
|
|
30
37
|
textures.get("depth")?.destroy();
|
|
38
|
+
textures.get("eid")?.destroy();
|
|
39
|
+
textures.get("z")?.destroy();
|
|
31
40
|
textures.get("mask")?.destroy();
|
|
32
41
|
textures.get("pingA")?.destroy();
|
|
33
42
|
textures.get("pingB")?.destroy();
|
|
@@ -42,11 +51,14 @@ export function ensureTextures(
|
|
|
42
51
|
GPUTextureUsage.TEXTURE_BINDING,
|
|
43
52
|
});
|
|
44
53
|
|
|
45
|
-
const
|
|
46
|
-
label: "
|
|
54
|
+
const depth = device.createTexture({
|
|
55
|
+
label: "depth",
|
|
47
56
|
size: { width, height },
|
|
48
|
-
format:
|
|
49
|
-
usage:
|
|
57
|
+
format: DEPTH_FORMAT,
|
|
58
|
+
usage:
|
|
59
|
+
GPUTextureUsage.STORAGE_BINDING |
|
|
60
|
+
GPUTextureUsage.RENDER_ATTACHMENT |
|
|
61
|
+
GPUTextureUsage.TEXTURE_BINDING,
|
|
50
62
|
});
|
|
51
63
|
|
|
52
64
|
const eid = device.createTexture({
|
|
@@ -59,10 +71,10 @@ export function ensureTextures(
|
|
|
59
71
|
GPUTextureUsage.TEXTURE_BINDING,
|
|
60
72
|
});
|
|
61
73
|
|
|
62
|
-
const
|
|
63
|
-
label: "
|
|
74
|
+
const z = device.createTexture({
|
|
75
|
+
label: "z",
|
|
64
76
|
size: { width, height },
|
|
65
|
-
format:
|
|
77
|
+
format: Z_FORMAT,
|
|
66
78
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
67
79
|
});
|
|
68
80
|
|
|
@@ -89,12 +101,12 @@ export function ensureTextures(
|
|
|
89
101
|
|
|
90
102
|
textures.set("color", color);
|
|
91
103
|
textureViews.set("color", color.createView());
|
|
92
|
-
textures.set("linear-depth", linearDepth);
|
|
93
|
-
textureViews.set("linear-depth", linearDepth.createView());
|
|
94
|
-
textures.set("eid", eid);
|
|
95
|
-
textureViews.set("eid", eid.createView());
|
|
96
104
|
textures.set("depth", depth);
|
|
97
105
|
textureViews.set("depth", depth.createView());
|
|
106
|
+
textures.set("eid", eid);
|
|
107
|
+
textureViews.set("eid", eid.createView());
|
|
108
|
+
textures.set("z", z);
|
|
109
|
+
textureViews.set("z", z.createView());
|
|
98
110
|
textures.set("mask", mask);
|
|
99
111
|
textureViews.set("mask", mask.createView());
|
|
100
112
|
textures.set("pingA", pingA);
|