@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.
Files changed (62) hide show
  1. package/package.json +1 -1
  2. package/src/core/component.ts +1 -1
  3. package/src/core/index.ts +1 -13
  4. package/src/core/math.ts +186 -0
  5. package/src/core/state.ts +1 -1
  6. package/src/core/xml.ts +56 -41
  7. package/src/extras/arrows/index.ts +3 -3
  8. package/src/extras/caustic.ts +37 -0
  9. package/src/extras/gradient/index.ts +63 -69
  10. package/src/extras/index.ts +3 -0
  11. package/src/extras/lines/index.ts +3 -3
  12. package/src/extras/orbit/index.ts +1 -1
  13. package/src/extras/skylab/index.ts +314 -0
  14. package/src/extras/text/font.ts +69 -14
  15. package/src/extras/text/index.ts +17 -69
  16. package/src/extras/text/sdf.ts +13 -2
  17. package/src/extras/water/index.ts +119 -0
  18. package/src/standard/defaults.ts +2 -0
  19. package/src/standard/index.ts +2 -0
  20. package/src/standard/raster/batch.ts +149 -0
  21. package/src/standard/raster/forward.ts +832 -0
  22. package/src/standard/raster/index.ts +191 -0
  23. package/src/standard/raster/shadow.ts +408 -0
  24. package/src/standard/{render → raytracing}/bvh/blas.ts +336 -88
  25. package/src/standard/raytracing/bvh/radix.ts +473 -0
  26. package/src/standard/raytracing/bvh/refit.ts +711 -0
  27. package/src/standard/{render → raytracing}/bvh/structs.ts +0 -55
  28. package/src/standard/{render → raytracing}/bvh/tlas.ts +155 -140
  29. package/src/standard/{render → raytracing}/bvh/traverse.ts +72 -64
  30. package/src/standard/{render → raytracing}/depth.ts +9 -9
  31. package/src/standard/raytracing/index.ts +409 -0
  32. package/src/standard/{render → raytracing}/instance.ts +31 -16
  33. package/src/standard/{render → raytracing}/ray.ts +1 -1
  34. package/src/standard/raytracing/shaders.ts +798 -0
  35. package/src/standard/{render → raytracing}/triangle.ts +1 -1
  36. package/src/standard/render/camera.ts +96 -106
  37. package/src/standard/render/data.ts +1 -1
  38. package/src/standard/render/index.ts +136 -220
  39. package/src/standard/render/indirect.ts +9 -10
  40. package/src/standard/render/light.ts +2 -2
  41. package/src/standard/render/mesh.ts +404 -0
  42. package/src/standard/render/overlay.ts +8 -5
  43. package/src/standard/render/pass.ts +1 -1
  44. package/src/standard/render/postprocess.ts +263 -242
  45. package/src/standard/render/scene.ts +28 -16
  46. package/src/standard/render/surface/index.ts +81 -12
  47. package/src/standard/render/surface/shaders.ts +511 -0
  48. package/src/standard/render/surface/structs.ts +23 -6
  49. package/src/standard/tween/tween.ts +44 -115
  50. package/src/standard/render/bvh/radix.ts +0 -476
  51. package/src/standard/render/forward/index.ts +0 -259
  52. package/src/standard/render/forward/raster.ts +0 -228
  53. package/src/standard/render/mesh/box.ts +0 -20
  54. package/src/standard/render/mesh/index.ts +0 -446
  55. package/src/standard/render/mesh/plane.ts +0 -11
  56. package/src/standard/render/mesh/sphere.ts +0 -40
  57. package/src/standard/render/mesh/unified.ts +0 -96
  58. package/src/standard/render/shaders.ts +0 -484
  59. package/src/standard/render/surface/compile.ts +0 -67
  60. package/src/standard/render/surface/noise.ts +0 -45
  61. package/src/standard/render/surface/wgsl.ts +0 -573
  62. /package/src/standard/{render → raytracing}/intersection.ts +0 -0
@@ -1,476 +0,0 @@
1
- import type { ComputeNode, ExecutionContext } from "../../compute";
2
-
3
- const WG_X = 16;
4
- const WG_Y = 16;
5
- const WG_SIZE = WG_X * WG_Y;
6
- const ITEMS_PER_WG = 2 * WG_SIZE;
7
-
8
- const blockSumShader = /* wgsl */ `
9
- @group(0) @binding(0) var<storage, read> input: array<u32>;
10
- @group(0) @binding(1) var<storage, read_write> localSums: array<u32>;
11
- @group(0) @binding(2) var<storage, read_write> blockSums: array<u32>;
12
-
13
- override WG_COUNT: u32;
14
- override BIT: u32;
15
- override COUNT: u32;
16
-
17
- var<workgroup> wgData: array<u32, 2 * (${WG_SIZE} + 1)>;
18
-
19
- @compute @workgroup_size(${WG_X}, ${WG_Y}, 1)
20
- fn main(
21
- @builtin(workgroup_id) wid: vec3<u32>,
22
- @builtin(num_workgroups) wdim: vec3<u32>,
23
- @builtin(local_invocation_index) tid: u32,
24
- ) {
25
- let workgroup = wid.x + wid.y * wdim.x;
26
- let base = workgroup * ${WG_SIZE}u;
27
- let gid = base + tid;
28
-
29
- let val = select(input[gid], 0u, gid >= COUNT);
30
- let bits = (val >> BIT) & 0x3;
31
-
32
- var sums = array<u32, 4>(0, 0, 0, 0);
33
- var lastThread = 0xffffffffu;
34
-
35
- if (workgroup < WG_COUNT) {
36
- lastThread = min(${WG_SIZE}u, COUNT - base) - 1;
37
- }
38
-
39
- let stride = ${WG_SIZE}u + 1;
40
- var swap = 0u;
41
- var inOff = tid;
42
- var outOff = tid + stride;
43
-
44
- for (var b = 0u; b < 4; b++) {
45
- let mask = select(0u, 1u, bits == b);
46
- wgData[inOff + 1] = mask;
47
- workgroupBarrier();
48
-
49
- var sum = 0u;
50
- for (var off = 1u; off < ${WG_SIZE}u; off *= 2) {
51
- if (tid >= off) {
52
- sum = wgData[inOff] + wgData[inOff - off];
53
- } else {
54
- sum = wgData[inOff];
55
- }
56
- wgData[outOff] = sum;
57
- outOff = inOff;
58
- swap = stride - swap;
59
- inOff = tid + swap;
60
- workgroupBarrier();
61
- }
62
-
63
- sums[b] = sum;
64
-
65
- if (tid == lastThread) {
66
- blockSums[b * WG_COUNT + workgroup] = sum + mask;
67
- }
68
-
69
- outOff = inOff;
70
- swap = stride - swap;
71
- inOff = tid + swap;
72
- }
73
-
74
- if (gid < COUNT) {
75
- localSums[gid] = sums[bits];
76
- }
77
- }
78
- `;
79
-
80
- const reorderShader = /* wgsl */ `
81
- @group(0) @binding(0) var<storage, read> inKeys: array<u32>;
82
- @group(0) @binding(1) var<storage, read_write> outKeys: array<u32>;
83
- @group(0) @binding(2) var<storage, read> localSums: array<u32>;
84
- @group(0) @binding(3) var<storage, read> blockSums: array<u32>;
85
- @group(0) @binding(4) var<storage, read> inVals: array<u32>;
86
- @group(0) @binding(5) var<storage, read_write> outVals: array<u32>;
87
-
88
- override WG_COUNT: u32;
89
- override BIT: u32;
90
- override COUNT: u32;
91
-
92
- @compute @workgroup_size(${WG_X}, ${WG_Y}, 1)
93
- fn main(
94
- @builtin(workgroup_id) wid: vec3<u32>,
95
- @builtin(num_workgroups) wdim: vec3<u32>,
96
- @builtin(local_invocation_index) tid: u32,
97
- ) {
98
- let workgroup = wid.x + wid.y * wdim.x;
99
- let gid = workgroup * ${WG_SIZE}u + tid;
100
-
101
- if (gid >= COUNT) { return; }
102
-
103
- let k = inKeys[gid];
104
- let v = inVals[gid];
105
- let bits = (k >> BIT) & 0x3;
106
- let dst = blockSums[bits * WG_COUNT + workgroup] + localSums[gid];
107
-
108
- outKeys[dst] = k;
109
- outVals[dst] = v;
110
- }
111
- `;
112
-
113
- const prefixSumShader = /* wgsl */ `
114
- @group(0) @binding(0) var<storage, read_write> data: array<u32>;
115
- @group(0) @binding(1) var<storage, read_write> blockSums: array<u32>;
116
-
117
- override COUNT: u32;
118
-
119
- var<workgroup> temp: array<u32, ${ITEMS_PER_WG * 2}>;
120
-
121
- @compute @workgroup_size(${WG_X}, ${WG_Y}, 1)
122
- fn scan(
123
- @builtin(workgroup_id) wid: vec3<u32>,
124
- @builtin(num_workgroups) wdim: vec3<u32>,
125
- @builtin(local_invocation_index) tid: u32,
126
- ) {
127
- let workgroup = wid.x + wid.y * wdim.x;
128
- let base = workgroup * ${WG_SIZE}u;
129
- let gid = base + tid;
130
- let eid = gid * 2;
131
-
132
- temp[tid * 2] = select(data[eid], 0u, eid >= COUNT);
133
- temp[tid * 2 + 1] = select(data[eid + 1], 0u, eid + 1 >= COUNT);
134
-
135
- var offset = 1u;
136
- for (var d = ${ITEMS_PER_WG}u >> 1; d > 0; d >>= 1) {
137
- workgroupBarrier();
138
- if (tid < d) {
139
- let ai = offset * (tid * 2 + 1) - 1;
140
- let bi = offset * (tid * 2 + 2) - 1;
141
- temp[bi] += temp[ai];
142
- }
143
- offset *= 2;
144
- }
145
-
146
- if (tid == 0) {
147
- blockSums[workgroup] = temp[${ITEMS_PER_WG}u - 1];
148
- temp[${ITEMS_PER_WG}u - 1] = 0;
149
- }
150
-
151
- for (var d = 1u; d < ${ITEMS_PER_WG}u; d *= 2) {
152
- offset >>= 1;
153
- workgroupBarrier();
154
- if (tid < d) {
155
- let ai = offset * (tid * 2 + 1) - 1;
156
- let bi = offset * (tid * 2 + 2) - 1;
157
- let t = temp[ai];
158
- temp[ai] = temp[bi];
159
- temp[bi] += t;
160
- }
161
- }
162
- workgroupBarrier();
163
-
164
- if (eid < COUNT) { data[eid] = temp[tid * 2]; }
165
- if (eid + 1 < COUNT) { data[eid + 1] = temp[tid * 2 + 1]; }
166
- }
167
-
168
- @compute @workgroup_size(${WG_X}, ${WG_Y}, 1)
169
- fn addBlocks(
170
- @builtin(workgroup_id) wid: vec3<u32>,
171
- @builtin(num_workgroups) wdim: vec3<u32>,
172
- @builtin(local_invocation_index) tid: u32,
173
- ) {
174
- let workgroup = wid.x + wid.y * wdim.x;
175
- let eid = (workgroup * ${WG_SIZE}u + tid) * 2;
176
-
177
- if (eid >= COUNT) { return; }
178
-
179
- let sum = blockSums[workgroup];
180
- data[eid] += sum;
181
- if (eid + 1 < COUNT) { data[eid + 1] += sum; }
182
- }
183
- `;
184
-
185
- function dispatchSize(device: GPUDevice, count: number): [number, number] {
186
- const max = device.limits.maxComputeWorkgroupsPerDimension;
187
- if (count <= max) return [count, 1];
188
- const x = Math.ceil(Math.sqrt(count));
189
- return [x, Math.ceil(count / x)];
190
- }
191
-
192
- interface PrefixPass {
193
- pipeline: GPUComputePipeline;
194
- bindGroup: GPUBindGroup;
195
- dispatch: [number, number];
196
- }
197
-
198
- class PrefixSum {
199
- private constructor(private passes: PrefixPass[]) {}
200
-
201
- static async create(device: GPUDevice, data: GPUBuffer, count: number): Promise<PrefixSum> {
202
- const passes: PrefixPass[] = [];
203
- const module = device.createShaderModule({ code: prefixSumShader });
204
- await PrefixSum.build(device, module, data, count, passes);
205
- return new PrefixSum(passes);
206
- }
207
-
208
- private static async build(
209
- device: GPUDevice,
210
- module: GPUShaderModule,
211
- data: GPUBuffer,
212
- count: number,
213
- passes: PrefixPass[]
214
- ): Promise<void> {
215
- const wgCount = Math.ceil(count / ITEMS_PER_WG);
216
- const dispatch = dispatchSize(device, wgCount);
217
-
218
- const blockSums = device.createBuffer({
219
- size: Math.max(wgCount * 4, 4),
220
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
221
- });
222
-
223
- const layout = device.createBindGroupLayout({
224
- entries: [
225
- { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
226
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
227
- ],
228
- });
229
-
230
- const bindGroup = device.createBindGroup({
231
- layout,
232
- entries: [
233
- { binding: 0, resource: { buffer: data } },
234
- { binding: 1, resource: { buffer: blockSums } },
235
- ],
236
- });
237
-
238
- const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
239
-
240
- passes.push({
241
- pipeline: await device.createComputePipelineAsync({
242
- layout: pipelineLayout,
243
- compute: { module, entryPoint: "scan", constants: { COUNT: count } },
244
- }),
245
- bindGroup,
246
- dispatch,
247
- });
248
-
249
- if (wgCount > 1) {
250
- await PrefixSum.build(device, module, blockSums, wgCount, passes);
251
-
252
- passes.push({
253
- pipeline: await device.createComputePipelineAsync({
254
- layout: pipelineLayout,
255
- compute: { module, entryPoint: "addBlocks", constants: { COUNT: count } },
256
- }),
257
- bindGroup,
258
- dispatch,
259
- });
260
- }
261
- }
262
-
263
- dispatch(pass: GPUComputePassEncoder): void {
264
- for (const p of this.passes) {
265
- pass.setPipeline(p.pipeline);
266
- pass.setBindGroup(0, p.bindGroup);
267
- pass.dispatchWorkgroups(p.dispatch[0], p.dispatch[1], 1);
268
- }
269
- }
270
- }
271
-
272
- interface RadixPass {
273
- blockSum: { pipeline: GPUComputePipeline; bindGroup: GPUBindGroup };
274
- reorder: { pipeline: GPUComputePipeline; bindGroup: GPUBindGroup };
275
- }
276
-
277
- class RadixSort {
278
- private constructor(
279
- private passes: RadixPass[],
280
- private prefixSum: PrefixSum,
281
- private workgroups: [number, number]
282
- ) {}
283
-
284
- static async create(
285
- device: GPUDevice,
286
- keys: GPUBuffer,
287
- values: GPUBuffer,
288
- count: number
289
- ): Promise<RadixSort> {
290
- const wgCount = Math.ceil(count / WG_SIZE);
291
- const workgroups = dispatchSize(device, wgCount);
292
-
293
- const tmpKeys = device.createBuffer({
294
- size: count * 4,
295
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
296
- });
297
- const tmpVals = device.createBuffer({
298
- size: count * 4,
299
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
300
- });
301
- const localSums = device.createBuffer({
302
- size: count * 4,
303
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
304
- });
305
- const blockSums = device.createBuffer({
306
- size: 4 * wgCount * 4,
307
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
308
- });
309
-
310
- const prefixSum = await PrefixSum.create(device, blockSums, 4 * wgCount);
311
-
312
- const blockSumModule = device.createShaderModule({ code: blockSumShader });
313
- const reorderModule = device.createShaderModule({ code: reorderShader });
314
-
315
- const blockSumLayout = device.createBindGroupLayout({
316
- entries: [
317
- {
318
- binding: 0,
319
- visibility: GPUShaderStage.COMPUTE,
320
- buffer: { type: "read-only-storage" },
321
- },
322
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
323
- { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
324
- ],
325
- });
326
-
327
- const reorderLayout = device.createBindGroupLayout({
328
- entries: [
329
- {
330
- binding: 0,
331
- visibility: GPUShaderStage.COMPUTE,
332
- buffer: { type: "read-only-storage" },
333
- },
334
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
335
- {
336
- binding: 2,
337
- visibility: GPUShaderStage.COMPUTE,
338
- buffer: { type: "read-only-storage" },
339
- },
340
- {
341
- binding: 3,
342
- visibility: GPUShaderStage.COMPUTE,
343
- buffer: { type: "read-only-storage" },
344
- },
345
- {
346
- binding: 4,
347
- visibility: GPUShaderStage.COMPUTE,
348
- buffer: { type: "read-only-storage" },
349
- },
350
- { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
351
- ],
352
- });
353
-
354
- const pipelinePromises: Promise<{
355
- blockSum: GPUComputePipeline;
356
- reorder: GPUComputePipeline;
357
- }>[] = [];
358
-
359
- for (let bit = 0; bit < 32; bit += 2) {
360
- pipelinePromises.push(
361
- (async () => {
362
- const [blockSumPipeline, reorderPipeline] = await Promise.all([
363
- device.createComputePipelineAsync({
364
- layout: device.createPipelineLayout({
365
- bindGroupLayouts: [blockSumLayout],
366
- }),
367
- compute: {
368
- module: blockSumModule,
369
- entryPoint: "main",
370
- constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
371
- },
372
- }),
373
- device.createComputePipelineAsync({
374
- layout: device.createPipelineLayout({
375
- bindGroupLayouts: [reorderLayout],
376
- }),
377
- compute: {
378
- module: reorderModule,
379
- entryPoint: "main",
380
- constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
381
- },
382
- }),
383
- ]);
384
- return { blockSum: blockSumPipeline, reorder: reorderPipeline };
385
- })()
386
- );
387
- }
388
-
389
- const pipelines = await Promise.all(pipelinePromises);
390
- const passes: RadixPass[] = [];
391
-
392
- for (let i = 0; i < 16; i++) {
393
- const bit = i * 2;
394
- const even = bit % 4 === 0;
395
- const inK = even ? keys : tmpKeys;
396
- const inV = even ? values : tmpVals;
397
- const outK = even ? tmpKeys : keys;
398
- const outV = even ? tmpVals : values;
399
-
400
- passes.push({
401
- blockSum: {
402
- pipeline: pipelines[i].blockSum,
403
- bindGroup: device.createBindGroup({
404
- layout: blockSumLayout,
405
- entries: [
406
- { binding: 0, resource: { buffer: inK } },
407
- { binding: 1, resource: { buffer: localSums } },
408
- { binding: 2, resource: { buffer: blockSums } },
409
- ],
410
- }),
411
- },
412
- reorder: {
413
- pipeline: pipelines[i].reorder,
414
- bindGroup: device.createBindGroup({
415
- layout: reorderLayout,
416
- entries: [
417
- { binding: 0, resource: { buffer: inK } },
418
- { binding: 1, resource: { buffer: outK } },
419
- { binding: 2, resource: { buffer: localSums } },
420
- { binding: 3, resource: { buffer: blockSums } },
421
- { binding: 4, resource: { buffer: inV } },
422
- { binding: 5, resource: { buffer: outV } },
423
- ],
424
- }),
425
- },
426
- });
427
- }
428
-
429
- return new RadixSort(passes, prefixSum, workgroups);
430
- }
431
-
432
- dispatch(pass: GPUComputePassEncoder): void {
433
- const [x, y] = this.workgroups;
434
- for (const p of this.passes) {
435
- pass.setPipeline(p.blockSum.pipeline);
436
- pass.setBindGroup(0, p.blockSum.bindGroup);
437
- pass.dispatchWorkgroups(x, y, 1);
438
-
439
- this.prefixSum.dispatch(pass);
440
-
441
- pass.setPipeline(p.reorder.pipeline);
442
- pass.setBindGroup(0, p.reorder.bindGroup);
443
- pass.dispatchWorkgroups(x, y, 1);
444
- }
445
- }
446
- }
447
-
448
- export interface RadixSortConfig {
449
- keys: GPUBuffer;
450
- values: GPUBuffer;
451
- count: number;
452
- }
453
-
454
- export function createRadixSort(device: GPUDevice, config: RadixSortConfig): Promise<RadixSort> {
455
- return RadixSort.create(device, config.keys, config.values, config.count);
456
- }
457
-
458
- export function createRadixSortNode(config: RadixSortConfig): ComputeNode {
459
- let sort: RadixSort | null = null;
460
-
461
- return {
462
- id: "radix-sort",
463
- inputs: [],
464
- outputs: [],
465
-
466
- async prepare(device: GPUDevice) {
467
- sort = await createRadixSort(device, config);
468
- },
469
-
470
- execute(ctx: ExecutionContext) {
471
- const pass = ctx.encoder.beginComputePass();
472
- sort!.dispatch(pass);
473
- pass.end();
474
- },
475
- };
476
- }