@multiplekex/shallot 0.2.3 → 0.2.5

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 (42) hide show
  1. package/package.json +1 -1
  2. package/src/extras/arrows/index.ts +3 -3
  3. package/src/extras/caustic.ts +37 -0
  4. package/src/extras/gradient/index.ts +63 -69
  5. package/src/extras/index.ts +3 -0
  6. package/src/extras/lines/index.ts +3 -3
  7. package/src/extras/skylab/index.ts +314 -0
  8. package/src/extras/text/font.ts +69 -14
  9. package/src/extras/text/index.ts +15 -7
  10. package/src/extras/text/sdf.ts +13 -2
  11. package/src/extras/water.ts +64 -0
  12. package/src/standard/defaults.ts +2 -0
  13. package/src/standard/index.ts +2 -0
  14. package/src/standard/raster/index.ts +517 -0
  15. package/src/standard/{render → raytracing}/bvh/blas.ts +3 -3
  16. package/src/standard/{render → raytracing}/bvh/tlas.ts +3 -0
  17. package/src/standard/{render → raytracing}/depth.ts +9 -9
  18. package/src/standard/raytracing/index.ts +380 -0
  19. package/src/standard/{render → raytracing}/instance.ts +3 -0
  20. package/src/standard/raytracing/shaders.ts +815 -0
  21. package/src/standard/{render → raytracing}/triangle.ts +1 -1
  22. package/src/standard/render/camera.ts +88 -80
  23. package/src/standard/render/index.ts +68 -208
  24. package/src/standard/render/indirect.ts +9 -10
  25. package/src/standard/render/mesh/index.ts +35 -166
  26. package/src/standard/render/overlay.ts +4 -4
  27. package/src/standard/render/pass.ts +1 -1
  28. package/src/standard/render/postprocess.ts +75 -50
  29. package/src/standard/render/scene.ts +28 -16
  30. package/src/standard/render/surface/compile.ts +6 -8
  31. package/src/standard/render/surface/noise.ts +15 -2
  32. package/src/standard/render/surface/shaders.ts +257 -0
  33. package/src/standard/render/surface/structs.ts +13 -6
  34. package/src/standard/render/forward/index.ts +0 -259
  35. package/src/standard/render/forward/raster.ts +0 -228
  36. package/src/standard/render/shaders.ts +0 -484
  37. package/src/standard/render/surface/wgsl.ts +0 -573
  38. /package/src/standard/{render → raytracing}/bvh/radix.ts +0 -0
  39. /package/src/standard/{render → raytracing}/bvh/structs.ts +0 -0
  40. /package/src/standard/{render → raytracing}/bvh/traverse.ts +0 -0
  41. /package/src/standard/{render → raytracing}/intersection.ts +0 -0
  42. /package/src/standard/{render → raytracing}/ray.ts +0 -0
@@ -3,7 +3,6 @@ import type { Plugin, State, System } from "../../core";
3
3
  import { MAX_ENTITIES, resource } from "../../core";
4
4
  import { Canvas, Compute, ComputePlugin } from "../compute";
5
5
  import { WorldTransform } from "../transforms";
6
- import { Activity } from "../activity";
7
6
  import {
8
7
  Camera,
9
8
  Tonemap,
@@ -23,6 +22,7 @@ import {
23
22
  Sun,
24
23
  Viewport,
25
24
  uploadCamera,
25
+ uploadSky,
26
26
  } from "./camera";
27
27
  import { AmbientLight, DirectionalLight, packLightUniforms } from "./light";
28
28
  import {
@@ -33,26 +33,13 @@ import {
33
33
  MeshPBR,
34
34
  MeshEmission,
35
35
  MeshVolumes,
36
- collectBatches,
37
- updateBatches,
38
- MAX_BATCH_SLOTS,
39
- type Batch,
40
- type MeshBuffers,
41
- type BatchEntities,
42
36
  createShapeAtlas,
43
37
  } from "./mesh";
44
- import { Surface, SurfaceIds, SurfaceType, getDefaultAllSurfaces } from "./surface";
45
- import { createSceneBuffer, ensureTextures } from "./scene";
46
- import { createIndirectBuffer } from "./indirect";
47
- import { createForwardNode } from "./forward";
48
- import { createDepthConvertNode } from "./depth";
38
+ import { Surface, SurfaceIds } from "./surface";
39
+ import { createSceneBuffer, createSkyBuffer, ensureTextures } from "./scene";
49
40
  import { createPostProcessNode, type PostProcessUniforms } from "./postprocess";
50
41
  import { createOverlayNode } from "./overlay";
51
42
  import { Draws } from "./pass";
52
- import { createBLASAtlas, type BLASAtlas } from "./bvh/blas";
53
- import { createTLASBuffers, createTLASNode, type TLASBuffers } from "./bvh/tlas";
54
- import { getMesh } from "./mesh";
55
- import { createInstanceNode } from "./instance";
56
43
  import { createDataNode } from "./data";
57
44
 
58
45
  export {
@@ -75,6 +62,9 @@ export {
75
62
  Clouds,
76
63
  Sun,
77
64
  Viewport,
65
+ getClearColor,
66
+ hasSkyComponent,
67
+ uploadSky,
78
68
  } from "./camera";
79
69
  export { AmbientLight, DirectionalLight } from "./light";
80
70
  export { Mesh, MeshShape, Volume, mesh, getMesh, clearMeshes } from "./mesh";
@@ -89,28 +79,29 @@ export type { SurfaceData } from "./surface";
89
79
 
90
80
  export { Pass, registerDraw, unregisterDraw, getDrawsByPass, Draws } from "./pass";
91
81
  export type { Draw, DrawContext, SharedPassContext } from "./pass";
92
- export { createForwardNode, compileRasterShader, compileRTShader } from "./forward";
93
- export type { ForwardConfig, ForwardNode } from "./forward";
94
- export { createDepthConvertNode } from "./depth";
95
82
  export { createPostProcessNode } from "./postprocess";
96
83
  export type { PostProcessUniforms } from "./postprocess";
97
84
  export { createOverlayNode } from "./overlay";
98
-
99
- const EntityIds = {
100
- data: new Uint32Array(MAX_ENTITIES),
101
- };
85
+ export { COLOR_FORMAT } from "./scene";
102
86
 
103
87
  const countBuffer = new Uint32Array(1);
88
+ const time = new Float32Array(1);
89
+ const ambientData = { color: 0x888888, intensity: 1.0 };
90
+ const directionalData = {
91
+ color: 0xffffff,
92
+ intensity: 1.0,
93
+ directionX: -0.5,
94
+ directionY: -1.0,
95
+ directionZ: -0.5,
96
+ };
104
97
 
105
98
  export interface Render {
106
99
  width: number;
107
100
  height: number;
108
101
  entityCount: number;
109
102
  scene: GPUBuffer;
103
+ sky: GPUBuffer;
110
104
  matrices: GPUBuffer;
111
- }
112
-
113
- interface RenderState extends Render {
114
105
  colors: GPUBuffer;
115
106
  sizes: GPUBuffer;
116
107
  pbr: GPUBuffer;
@@ -118,34 +109,21 @@ interface RenderState extends Render {
118
109
  shapes: GPUBuffer;
119
110
  surfaces: GPUBuffer;
120
111
  data: GPUBuffer;
121
- indirect: GPUBuffer;
122
- batches: (Batch | null)[];
123
- batchEntities: BatchEntities;
124
- buffers: Map<number, MeshBuffers>;
125
- postProcess: PostProcessUniforms;
112
+ entityCountBuffer: GPUBuffer;
126
113
  meshVertices: GPUBuffer;
127
114
  meshIndices: GPUBuffer;
128
115
  meshMeta: GPUBuffer;
129
- blasAtlas: BLASAtlas;
130
- instanceAABBs: GPUBuffer;
131
- instanceInverses: GPUBuffer;
132
- entityCountBuffer: GPUBuffer;
133
- instanceCount: GPUBuffer;
134
- tlas: TLASBuffers;
116
+ postProcess: PostProcessUniforms;
135
117
  }
136
118
 
137
119
  export const Render = resource<Render>("render");
138
120
 
139
- function getRenderState(state: State): RenderState | undefined {
140
- return Render.from(state) as RenderState | undefined;
141
- }
142
-
143
121
  const RenderSystem: System = {
144
122
  group: "draw",
145
123
  first: true,
146
124
 
147
125
  update(state: State) {
148
- const render = getRenderState(state);
126
+ const render = Render.from(state);
149
127
  const compute = Compute.from(state);
150
128
  const canvas = Canvas.from(state);
151
129
  if (!render || !compute || !canvas) return;
@@ -212,54 +190,54 @@ const RenderSystem: System = {
212
190
  const hasHaze = state.hasComponent(eid, Haze);
213
191
  const hazeParams = hasHaze
214
192
  ? {
215
- density: Haze.density[eid],
216
- color: Haze.color[eid],
217
- }
193
+ density: Haze.density[eid],
194
+ color: Haze.color[eid],
195
+ }
218
196
  : undefined;
219
197
 
220
198
  const hasSky = state.hasComponent(eid, Sky);
221
199
  const skyParams = hasSky
222
200
  ? {
223
- zenith: Sky.zenith[eid],
224
- horizon: Sky.horizon[eid],
225
- }
201
+ zenith: Sky.zenith[eid],
202
+ horizon: Sky.horizon[eid],
203
+ }
226
204
  : undefined;
227
205
 
228
206
  const hasMoon = state.hasComponent(eid, Moon);
229
207
  const moonParams = hasMoon
230
208
  ? {
231
- phase: Moon.phase[eid],
232
- glow: Moon.glow[eid],
233
- azimuth: Moon.azimuth[eid],
234
- elevation: Moon.elevation[eid],
235
- }
209
+ phase: Moon.phase[eid],
210
+ glow: Moon.glow[eid],
211
+ azimuth: Moon.azimuth[eid],
212
+ elevation: Moon.elevation[eid],
213
+ }
236
214
  : undefined;
237
215
 
238
216
  const hasStars = state.hasComponent(eid, Stars);
239
217
  const starsParams = hasStars
240
218
  ? {
241
- intensity: Stars.intensity[eid],
242
- amount: Stars.amount[eid],
243
- }
219
+ intensity: Stars.intensity[eid],
220
+ amount: Stars.amount[eid],
221
+ }
244
222
  : undefined;
245
223
 
246
224
  const hasClouds = state.hasComponent(eid, Clouds);
247
225
  const cloudsParams = hasClouds
248
226
  ? {
249
- coverage: Clouds.coverage[eid],
250
- density: Clouds.density[eid],
251
- height: Clouds.height[eid],
252
- color: Clouds.color[eid],
253
- }
227
+ coverage: Clouds.coverage[eid],
228
+ density: Clouds.density[eid],
229
+ height: Clouds.height[eid],
230
+ color: Clouds.color[eid],
231
+ }
254
232
  : undefined;
255
233
 
256
234
  const hasSun = state.hasComponent(eid, Sun);
257
235
  const sunParams = hasSun
258
236
  ? {
259
- size: Sun.size[eid],
260
- glow: Sun.glow[eid],
261
- color: Sun.color[eid],
262
- }
237
+ size: Sun.size[eid],
238
+ glow: Sun.glow[eid],
239
+ color: Sun.color[eid],
240
+ }
263
241
  : undefined;
264
242
 
265
243
  uploadCamera(
@@ -272,7 +250,15 @@ const RenderSystem: System = {
272
250
  shadowSamples,
273
251
  reflectionDepth,
274
252
  refractionDepth,
275
- uploadCount,
253
+ uploadCount
254
+ );
255
+
256
+ time[0] = state.time.elapsed;
257
+ device.queue.writeBuffer(render.scene, 240, time);
258
+
259
+ uploadSky(
260
+ device,
261
+ render.sky,
276
262
  hazeParams,
277
263
  skyParams,
278
264
  moonParams,
@@ -311,31 +297,26 @@ const RenderSystem: System = {
311
297
  }
312
298
  }
313
299
 
314
- let ambientData = { color: 0x888888, intensity: 1.0 };
315
- let directionalData = {
316
- color: 0xffffff,
317
- intensity: 1.0,
318
- directionX: -0.5,
319
- directionY: -1.0,
320
- directionZ: -0.5,
321
- };
300
+ ambientData.color = 0x888888;
301
+ ambientData.intensity = 1.0;
302
+ directionalData.color = 0xffffff;
303
+ directionalData.intensity = 1.0;
304
+ directionalData.directionX = -0.5;
305
+ directionalData.directionY = -1.0;
306
+ directionalData.directionZ = -0.5;
322
307
 
323
308
  for (const eid of state.query([AmbientLight])) {
324
- ambientData = {
325
- color: AmbientLight.color[eid],
326
- intensity: AmbientLight.intensity[eid],
327
- };
309
+ ambientData.color = AmbientLight.color[eid];
310
+ ambientData.intensity = AmbientLight.intensity[eid];
328
311
  break;
329
312
  }
330
313
 
331
314
  for (const eid of state.query([DirectionalLight])) {
332
- directionalData = {
333
- color: DirectionalLight.color[eid],
334
- intensity: DirectionalLight.intensity[eid],
335
- directionX: DirectionalLight.directionX[eid],
336
- directionY: DirectionalLight.directionY[eid],
337
- directionZ: DirectionalLight.directionZ[eid],
338
- };
315
+ directionalData.color = DirectionalLight.color[eid];
316
+ directionalData.intensity = DirectionalLight.intensity[eid];
317
+ directionalData.directionX = DirectionalLight.directionX[eid];
318
+ directionalData.directionY = DirectionalLight.directionY[eid];
319
+ directionalData.directionZ = DirectionalLight.directionZ[eid];
339
320
  break;
340
321
  }
341
322
 
@@ -350,7 +331,6 @@ const RenderSystem: System = {
350
331
  uploadCount * 16
351
332
  );
352
333
 
353
- const meshEntities = state.query([Mesh, WorldTransform]);
354
334
  device.queue.writeBuffer(render.colors, 0, MeshColors.data, 0, uploadCount * 4);
355
335
  device.queue.writeBuffer(render.sizes, 0, MeshSizes.data, 0, uploadCount * 4);
356
336
  device.queue.writeBuffer(render.pbr, 0, MeshPBR.data, 0, uploadCount * 4);
@@ -359,21 +339,6 @@ const RenderSystem: System = {
359
339
  countBuffer[0] = uploadCount;
360
340
  device.queue.writeBuffer(render.entityCountBuffer, 0, countBuffer);
361
341
 
362
- let meshCount = 0;
363
- for (const eid of meshEntities) {
364
- EntityIds.data[meshCount] = eid;
365
- meshCount++;
366
- }
367
- device.queue.writeBuffer(
368
- render.tlas.entityIds,
369
- 0,
370
- EntityIds.data,
371
- 0,
372
- Math.max(meshCount, 1)
373
- );
374
- countBuffer[0] = meshCount;
375
- device.queue.writeBuffer(render.instanceCount, 0, countBuffer);
376
-
377
342
  for (const eid of state.query([Surface])) {
378
343
  const surfaceType = Surface.type[eid] & 0xff;
379
344
  const volume = (MeshVolumes.data[eid] ?? 0) & 0xf;
@@ -381,13 +346,6 @@ const RenderSystem: System = {
381
346
  SurfaceIds.data[eid] = surfaceType | (volume << 8) | (shapeId << 16);
382
347
  }
383
348
  device.queue.writeBuffer(render.surfaces, 0, SurfaceIds.data, 0, uploadCount);
384
-
385
- collectBatches(
386
- meshEntities,
387
- (eid) => Surface.type[eid] ?? SurfaceType.Default,
388
- render.batchEntities
389
- );
390
- updateBatches(device, render.batchEntities, render, render.indirect);
391
349
  },
392
350
  };
393
351
 
@@ -441,10 +399,10 @@ export const RenderPlugin: Plugin = {
441
399
  });
442
400
 
443
401
  const shapeAtlas = createShapeAtlas(device);
444
- const blasAtlas = createBLASAtlas(device, getMesh);
445
402
 
446
- const renderState: RenderState = {
403
+ const renderState: Render = {
447
404
  scene: createSceneBuffer(device),
405
+ sky: createSkyBuffer(device),
448
406
  matrices: createPropertyBuffer(MAX_ENTITIES * 64, "matrices"),
449
407
  colors: createPropertyBuffer(MAX_ENTITIES * 16, "colors"),
450
408
  sizes: createPropertyBuffer(MAX_ENTITIES * 16, "sizes"),
@@ -453,10 +411,6 @@ export const RenderPlugin: Plugin = {
453
411
  shapes: createPropertyBuffer(MAX_ENTITIES * 4, "shapes"),
454
412
  surfaces: createPropertyBuffer(MAX_ENTITIES * 4, "surfaces"),
455
413
  data: createPropertyBuffer(MAX_ENTITIES * 64, "data"),
456
- indirect: createIndirectBuffer(device, MAX_BATCH_SLOTS),
457
- batches: Array(MAX_BATCH_SLOTS).fill(null),
458
- batchEntities: Array(MAX_BATCH_SLOTS).fill(null),
459
- buffers: new Map(),
460
414
  entityCount: 1,
461
415
  postProcess: {
462
416
  tonemap: false,
@@ -473,20 +427,11 @@ export const RenderPlugin: Plugin = {
473
427
  meshVertices: shapeAtlas.vertices,
474
428
  meshIndices: shapeAtlas.indices,
475
429
  meshMeta: shapeAtlas.meta,
476
- blasAtlas,
477
- instanceAABBs: createPropertyBuffer(MAX_ENTITIES * 32, "instanceAABBs"),
478
- instanceInverses: createPropertyBuffer(MAX_ENTITIES * 64, "instanceInverses"),
479
430
  entityCountBuffer: device.createBuffer({
480
431
  label: "entityCount",
481
432
  size: 4,
482
433
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
483
434
  }),
484
- instanceCount: device.createBuffer({
485
- label: "instanceCount",
486
- size: 4,
487
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
488
- }),
489
- tlas: createTLASBuffers(device),
490
435
  width: 0,
491
436
  height: 0,
492
437
  };
@@ -498,18 +443,6 @@ export const RenderPlugin: Plugin = {
498
443
  };
499
444
  state.setResource(Draws, drawState);
500
445
 
501
- const instanceNode = createInstanceNode({
502
- matrices: renderState.matrices,
503
- sizes: renderState.sizes,
504
- shapes: renderState.shapes,
505
- shapeAABBs: renderState.blasAtlas.shapeAABBs,
506
- entityCount: renderState.entityCountBuffer,
507
- instanceAABBs: renderState.instanceAABBs,
508
- instanceInverses: renderState.instanceInverses,
509
- getEntityCount: () => renderState.entityCount,
510
- });
511
- compute.graph.add(instanceNode);
512
-
513
446
  const dataNode = createDataNode({
514
447
  colors: renderState.colors,
515
448
  pbr: renderState.pbr,
@@ -521,79 +454,6 @@ export const RenderPlugin: Plugin = {
521
454
  });
522
455
  compute.graph.add(dataNode);
523
456
 
524
- const tlasNode = createTLASNode({
525
- instanceAABBs: renderState.instanceAABBs,
526
- instanceCount: renderState.instanceCount,
527
- tlas: renderState.tlas,
528
- getEntityCount: () => renderState.entityCount,
529
- });
530
- compute.graph.add(tlasNode);
531
-
532
- const getRaytracing = () => {
533
- for (const eid of state.query([Camera])) {
534
- if (Camera.active[eid]) {
535
- return state.hasComponent(eid, Raytracing);
536
- }
537
- }
538
- return false;
539
- };
540
-
541
- const getClearColor = () => {
542
- for (const eid of state.query([Camera])) {
543
- if (Camera.active[eid]) {
544
- const packed = Camera.clearColor[eid];
545
- return {
546
- r: ((packed >> 16) & 0xff) / 255,
547
- g: ((packed >> 8) & 0xff) / 255,
548
- b: (packed & 0xff) / 255,
549
- };
550
- }
551
- }
552
- return { r: 0, g: 0, b: 0 };
553
- };
554
-
555
- const getSky = () => {
556
- for (const eid of state.query([Camera])) {
557
- if (Camera.active[eid]) {
558
- return state.hasComponent(eid, Sky);
559
- }
560
- }
561
- return false;
562
- };
563
-
564
- const forwardNode = createForwardNode({
565
- scene: renderState.scene,
566
- matrices: renderState.matrices,
567
- colors: renderState.colors,
568
- sizes: renderState.sizes,
569
- pbr: renderState.pbr,
570
- emission: renderState.emission,
571
- shapes: renderState.shapes,
572
- surfaces: renderState.surfaces,
573
- data: renderState.data,
574
- getSurfaces: getDefaultAllSurfaces,
575
- getRaytracing,
576
- getClearColor,
577
- getSky,
578
- acquire: (message) => Activity.from(state)?.acquire(message),
579
- batches: () => renderState.batches,
580
- tlasNodes: renderState.tlas.bvhNodes,
581
- tlasInstanceIds: renderState.tlas.instanceIds,
582
- blasNodes: renderState.blasAtlas.nodesBuffer,
583
- blasTriIds: renderState.blasAtlas.triIdsBuffer,
584
- blasTriangles: renderState.blasAtlas.trianglesBuffer,
585
- blasMeta: renderState.blasAtlas.metaBuffer,
586
- instanceInverses: renderState.instanceInverses,
587
- });
588
- compute.graph.add(forwardNode);
589
-
590
- compute.graph.add(
591
- createDepthConvertNode({
592
- scene: renderState.scene,
593
- getRaytracing,
594
- })
595
- );
596
-
597
457
  compute.graph.add(createOverlayNode({ state }));
598
458
 
599
459
  compute.graph.add(
@@ -20,21 +20,20 @@ export function createIndirectBuffer(device: GPUDevice, slotCount: number): GPUB
20
20
  });
21
21
  }
22
22
 
23
+ const indirectData = new ArrayBuffer(INDIRECT_SIZE);
24
+ const indirectView = new DataView(indirectData);
25
+
23
26
  export function writeIndirect(
24
27
  device: GPUDevice,
25
28
  buffer: GPUBuffer,
26
29
  slot: number,
27
30
  args: IndirectArgs
28
31
  ): void {
29
- const offset = slot * INDIRECT_SIZE;
30
- const data = new ArrayBuffer(INDIRECT_SIZE);
31
- const view = new DataView(data);
32
-
33
- view.setUint32(0, args.indexCount, true);
34
- view.setUint32(4, args.instanceCount, true);
35
- view.setUint32(8, args.firstIndex, true);
36
- view.setInt32(12, args.baseVertex, true);
37
- view.setUint32(16, args.firstInstance, true);
32
+ indirectView.setUint32(0, args.indexCount, true);
33
+ indirectView.setUint32(4, args.instanceCount, true);
34
+ indirectView.setUint32(8, args.firstIndex, true);
35
+ indirectView.setInt32(12, args.baseVertex, true);
36
+ indirectView.setUint32(16, args.firstInstance, true);
38
37
 
39
- device.queue.writeBuffer(buffer, offset, data);
38
+ device.queue.writeBuffer(buffer, slot * INDIRECT_SIZE, indirectData);
40
39
  }