simulationjsv2 0.3.3 → 0.4.1
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/README.md +3 -3
- package/dist/graphics.d.ts +1 -1
- package/dist/internalUtils.d.ts +24 -3
- package/dist/internalUtils.js +62 -4
- package/dist/simulation.d.ts +18 -4
- package/dist/simulation.js +72 -19
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SimulationJS v2
|
|
2
2
|
|
|
3
|
-
SimulationJS is a graphics library with simple easy to use APIs. Version 2 hopes to boost performance by using webgpu under the hood.
|
|
3
|
+
SimulationJS is a graphics library with simple easy to use APIs. Version 2 hopes to improve 3d graphics and boost performance by using webgpu under the hood.
|
|
4
4
|
|
|
5
|
-
The APIs for v2 will
|
|
5
|
+
The APIs for v2 will differ however semantically, using them should be nearly identical.
|
|
6
6
|
|
|
7
|
-
**Documentation
|
|
7
|
+
**Documentation eventually**
|
|
8
8
|
|
|
9
9
|
By _Jackson Otto_
|
package/dist/graphics.d.ts
CHANGED
package/dist/internalUtils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference types="
|
|
1
|
+
/// <reference types="@webgpu/types" />
|
|
2
2
|
import { Mat4, Vector2, Vector3 } from './types.js';
|
|
3
3
|
import { Color } from './utils.js';
|
|
4
4
|
import { SimulationElement } from './graphics.js';
|
|
@@ -17,7 +17,28 @@ export declare const getTransformationMatrix: (pos: Vector3, rotation: Vector3,
|
|
|
17
17
|
export declare const getOrthoMatrix: (screenSize: [number, number]) => Float32Array;
|
|
18
18
|
export declare const buildDepthTexture: (device: GPUDevice, width: number, height: number) => GPUTexture;
|
|
19
19
|
export declare const buildMultisampleTexture: (device: GPUDevice, ctx: GPUCanvasContext, width: number, height: number) => GPUTexture;
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const addObject: (scene: SimSceneObjInfo[], el: SimulationElement<any>, id?: string) => void;
|
|
21
|
+
export declare const removeObject: (scene: SimSceneObjInfo[], el: SimulationElement<any>) => void;
|
|
22
|
+
export declare const removeObjectId: (scene: SimSceneObjInfo[], id: string) => void;
|
|
23
|
+
export declare class SimSceneObjInfo {
|
|
24
|
+
private obj;
|
|
25
|
+
private id;
|
|
26
|
+
private lifetime;
|
|
27
|
+
private currentLife;
|
|
28
|
+
constructor(obj: SimulationElement<any>, id?: string);
|
|
29
|
+
/**
|
|
30
|
+
* @param lifetime - ms
|
|
31
|
+
*/
|
|
32
|
+
setLifetime(lifetime: number): void;
|
|
33
|
+
getLifetime(): number | null;
|
|
34
|
+
lifetimeComplete(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* @param amount - ms
|
|
37
|
+
*/
|
|
38
|
+
traverseLife(amount: number): void;
|
|
39
|
+
getObj(): SimulationElement<Vector3 | Vector2>;
|
|
40
|
+
getId(): string | null;
|
|
41
|
+
}
|
|
21
42
|
declare class Logger {
|
|
22
43
|
constructor();
|
|
23
44
|
private fmt;
|
|
@@ -42,5 +63,5 @@ export declare function matrixFromRotation(rotation: Vector3): Mat4;
|
|
|
42
63
|
export declare function rotateMat4(mat: Mat4, rotation: Vector3): void;
|
|
43
64
|
export declare function createPipeline(device: GPUDevice, module: GPUShaderModule, bindGroupLayout: GPUBindGroupLayout, presentationFormat: GPUTextureFormat, entryPoint: string, topology: GPUPrimitiveTopology): GPURenderPipeline;
|
|
44
65
|
export declare function triangulateWireFrameOrder(len: number): number[];
|
|
45
|
-
export declare function getTotalVertices(scene:
|
|
66
|
+
export declare function getTotalVertices(scene: SimSceneObjInfo[]): number;
|
|
46
67
|
export {};
|
package/dist/internalUtils.js
CHANGED
|
@@ -59,14 +59,71 @@ export const buildMultisampleTexture = (device, ctx, width, height) => {
|
|
|
59
59
|
sampleCount: 4
|
|
60
60
|
});
|
|
61
61
|
};
|
|
62
|
-
export const
|
|
62
|
+
export const addObject = (scene, el, id) => {
|
|
63
63
|
if (el instanceof SimulationElement) {
|
|
64
|
-
|
|
64
|
+
const obj = new SimSceneObjInfo(el, id);
|
|
65
|
+
scene.unshift(obj);
|
|
65
66
|
}
|
|
66
67
|
else {
|
|
67
68
|
throw logger.error('Cannot add invalid SimulationElement');
|
|
68
69
|
}
|
|
69
70
|
};
|
|
71
|
+
export const removeObject = (scene, el) => {
|
|
72
|
+
if (!(el instanceof SimulationElement))
|
|
73
|
+
return;
|
|
74
|
+
for (let i = 0; i < scene.length; i++) {
|
|
75
|
+
if (scene[i].getObj() === el) {
|
|
76
|
+
scene.splice(i, 1);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export const removeObjectId = (scene, id) => {
|
|
82
|
+
for (let i = 0; i < scene.length; i++) {
|
|
83
|
+
if (scene[i].getId() === id) {
|
|
84
|
+
scene.splice(i, 1);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export class SimSceneObjInfo {
|
|
90
|
+
obj;
|
|
91
|
+
id;
|
|
92
|
+
lifetime; // ms
|
|
93
|
+
currentLife;
|
|
94
|
+
constructor(obj, id) {
|
|
95
|
+
this.obj = obj;
|
|
96
|
+
this.id = id || null;
|
|
97
|
+
this.lifetime = null;
|
|
98
|
+
this.currentLife = 0;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @param lifetime - ms
|
|
102
|
+
*/
|
|
103
|
+
setLifetime(lifetime) {
|
|
104
|
+
this.lifetime = lifetime;
|
|
105
|
+
}
|
|
106
|
+
getLifetime() {
|
|
107
|
+
return this.lifetime;
|
|
108
|
+
}
|
|
109
|
+
lifetimeComplete() {
|
|
110
|
+
if (this.lifetime === null)
|
|
111
|
+
return false;
|
|
112
|
+
return this.currentLife >= this.lifetime;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @param amount - ms
|
|
116
|
+
*/
|
|
117
|
+
traverseLife(amount) {
|
|
118
|
+
this.currentLife += amount;
|
|
119
|
+
}
|
|
120
|
+
getObj() {
|
|
121
|
+
return this.obj;
|
|
122
|
+
}
|
|
123
|
+
getId() {
|
|
124
|
+
return this.id;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
70
127
|
class Logger {
|
|
71
128
|
constructor() { }
|
|
72
129
|
fmt(msg) {
|
|
@@ -250,9 +307,10 @@ export function triangulateWireFrameOrder(len) {
|
|
|
250
307
|
export function getTotalVertices(scene) {
|
|
251
308
|
let total = 0;
|
|
252
309
|
for (let i = 0; i < scene.length; i++) {
|
|
253
|
-
|
|
310
|
+
const obj = scene[i].getObj();
|
|
311
|
+
if (obj.isCollection)
|
|
254
312
|
continue;
|
|
255
|
-
total +=
|
|
313
|
+
total += obj.getVertexCount();
|
|
256
314
|
}
|
|
257
315
|
return total;
|
|
258
316
|
}
|
package/dist/simulation.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
/// <reference types="
|
|
1
|
+
/// <reference types="@webgpu/types" />
|
|
2
2
|
import { SimulationElement, SimulationElement3d } from './graphics.js';
|
|
3
3
|
import type { Vector2, Vector3, LerpFunc } from './types.js';
|
|
4
4
|
import { Color } from './utils.js';
|
|
5
5
|
import { BlankGeometry } from './geometry.js';
|
|
6
|
+
import { SimSceneObjInfo } from './internalUtils.js';
|
|
6
7
|
export declare class Simulation {
|
|
7
8
|
canvasRef: HTMLCanvasElement | null;
|
|
8
9
|
private bgColor;
|
|
9
10
|
private scene;
|
|
10
11
|
private fittingElement;
|
|
11
12
|
private running;
|
|
13
|
+
private initialized;
|
|
12
14
|
private frameRateView;
|
|
13
15
|
private camera;
|
|
14
16
|
private pipelines;
|
|
15
17
|
private renderInfo;
|
|
16
18
|
constructor(idOrCanvasRef: string | HTMLCanvasElement, camera?: Camera | null, showFrameRate?: boolean);
|
|
17
|
-
add(el: SimulationElement<any
|
|
19
|
+
add(el: SimulationElement<any>, id?: string): void;
|
|
20
|
+
remove(el: SimulationElement<any>): void;
|
|
21
|
+
removeId(id: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* @param lifetime - ms
|
|
24
|
+
*/
|
|
25
|
+
setLifetime(el: SimulationElement<any>, lifetime: number): void;
|
|
18
26
|
setCanvasSize(width: number, height: number): void;
|
|
19
27
|
start(): void;
|
|
20
28
|
stop(): void;
|
|
@@ -33,9 +41,15 @@ export declare class SceneCollection extends SimulationElement3d {
|
|
|
33
41
|
constructor(name: string);
|
|
34
42
|
setWireframe(_: boolean): void;
|
|
35
43
|
getName(): string;
|
|
36
|
-
getScene():
|
|
37
|
-
|
|
44
|
+
getScene(): SimSceneObjInfo[];
|
|
45
|
+
setSceneObjects(newScene: SimulationElement<any>[]): void;
|
|
46
|
+
setScene(newScene: SimSceneObjInfo[]): void;
|
|
38
47
|
add(el: SimulationElement<any>): void;
|
|
48
|
+
remove(el: SimulationElement<any>): void;
|
|
49
|
+
/**
|
|
50
|
+
* @param lifetime - ms
|
|
51
|
+
*/
|
|
52
|
+
setLifetime(el: SimulationElement<any>, lifetime: number): void;
|
|
39
53
|
empty(): void;
|
|
40
54
|
getSceneBuffer(camera: Camera): number[];
|
|
41
55
|
getWireframe(camera: Camera): number[];
|
package/dist/simulation.js
CHANGED
|
@@ -3,7 +3,7 @@ import { SimulationElement3d } from './graphics.js';
|
|
|
3
3
|
import { BUF_LEN } from './constants.js';
|
|
4
4
|
import { Color, transitionValues, vector2, vector3 } from './utils.js';
|
|
5
5
|
import { BlankGeometry } from './geometry.js';
|
|
6
|
-
import {
|
|
6
|
+
import { SimSceneObjInfo, addObject, buildDepthTexture, buildMultisampleTexture, buildProjectionMatrix, createPipeline, getOrthoMatrix, getTotalVertices, getTransformationMatrix, logger, removeObject, removeObjectId } from './internalUtils.js';
|
|
7
7
|
const shader = `
|
|
8
8
|
struct Uniforms {
|
|
9
9
|
modelViewProjectionMatrix : mat4x4<f32>,
|
|
@@ -115,6 +115,7 @@ export class Simulation {
|
|
|
115
115
|
scene = [];
|
|
116
116
|
fittingElement = false;
|
|
117
117
|
running = true;
|
|
118
|
+
initialized = false;
|
|
118
119
|
frameRateView;
|
|
119
120
|
camera;
|
|
120
121
|
pipelines;
|
|
@@ -152,8 +153,23 @@ export class Simulation {
|
|
|
152
153
|
this.frameRateView = new FrameRateView(showFrameRate);
|
|
153
154
|
this.frameRateView.updateFrameRate(1);
|
|
154
155
|
}
|
|
155
|
-
add(el) {
|
|
156
|
-
|
|
156
|
+
add(el, id) {
|
|
157
|
+
addObject(this.scene, el, id);
|
|
158
|
+
}
|
|
159
|
+
remove(el) {
|
|
160
|
+
removeObject(this.scene, el);
|
|
161
|
+
}
|
|
162
|
+
removeId(id) {
|
|
163
|
+
removeObjectId(this.scene, id);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* @param lifetime - ms
|
|
167
|
+
*/
|
|
168
|
+
setLifetime(el, lifetime) {
|
|
169
|
+
for (let i = 0; i < this.scene.length; i++) {
|
|
170
|
+
if (this.scene[i].getObj() === el)
|
|
171
|
+
this.scene[i].setLifetime(lifetime);
|
|
172
|
+
}
|
|
157
173
|
}
|
|
158
174
|
setCanvasSize(width, height) {
|
|
159
175
|
this.assertHasCanvas();
|
|
@@ -163,8 +179,13 @@ export class Simulation {
|
|
|
163
179
|
this.canvasRef.style.height = height + 'px';
|
|
164
180
|
}
|
|
165
181
|
start() {
|
|
182
|
+
if (this.initialized) {
|
|
183
|
+
this.running = true;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
166
186
|
(async () => {
|
|
167
187
|
this.assertHasCanvas();
|
|
188
|
+
this.initialized = true;
|
|
168
189
|
this.running = true;
|
|
169
190
|
const adapter = await navigator.gpu.requestAdapter();
|
|
170
191
|
if (!adapter)
|
|
@@ -191,8 +212,9 @@ export class Simulation {
|
|
|
191
212
|
}
|
|
192
213
|
propagateDevice(device) {
|
|
193
214
|
for (let i = 0; i < this.scene.length; i++) {
|
|
194
|
-
|
|
195
|
-
|
|
215
|
+
const obj = this.scene[i].getObj();
|
|
216
|
+
if (obj.isInstance) {
|
|
217
|
+
obj.setDevice(device);
|
|
196
218
|
}
|
|
197
219
|
}
|
|
198
220
|
}
|
|
@@ -299,9 +321,11 @@ export class Simulation {
|
|
|
299
321
|
let prev = Date.now() - 10;
|
|
300
322
|
let prevFps = 0;
|
|
301
323
|
const frame = async () => {
|
|
302
|
-
if (!
|
|
324
|
+
if (!canvas)
|
|
303
325
|
return;
|
|
304
326
|
requestAnimationFrame(frame);
|
|
327
|
+
if (!this.running)
|
|
328
|
+
return;
|
|
305
329
|
const now = Date.now();
|
|
306
330
|
const diff = Math.max(now - prev, 1);
|
|
307
331
|
prev = now;
|
|
@@ -339,14 +363,14 @@ export class Simulation {
|
|
|
339
363
|
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
340
364
|
passEncoder.setPipeline(this.pipelines.triangleList3d);
|
|
341
365
|
passEncoder.setBindGroup(0, uniformBindGroup);
|
|
342
|
-
this.renderScene(device, passEncoder, this.scene);
|
|
366
|
+
this.renderScene(device, passEncoder, this.scene, diff);
|
|
343
367
|
this.camera.updateConsumed();
|
|
344
368
|
passEncoder.end();
|
|
345
369
|
device.queue.submit([commandEncoder.finish()]);
|
|
346
370
|
};
|
|
347
371
|
requestAnimationFrame(frame);
|
|
348
372
|
}
|
|
349
|
-
async renderScene(device, passEncoder, scene) {
|
|
373
|
+
async renderScene(device, passEncoder, scene, diff) {
|
|
350
374
|
if (this.pipelines === null)
|
|
351
375
|
return;
|
|
352
376
|
let totalVertices = getTotalVertices(scene);
|
|
@@ -355,17 +379,28 @@ export class Simulation {
|
|
|
355
379
|
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
356
380
|
});
|
|
357
381
|
let currentOffset = 0;
|
|
382
|
+
let toRemove = [];
|
|
358
383
|
for (let i = 0; i < scene.length; i++) {
|
|
359
|
-
|
|
360
|
-
|
|
384
|
+
const lifetime = scene[i].getLifetime();
|
|
385
|
+
if (lifetime !== null) {
|
|
386
|
+
const complete = scene[i].lifetimeComplete();
|
|
387
|
+
if (complete) {
|
|
388
|
+
toRemove.push(i);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
scene[i].traverseLife(diff);
|
|
392
|
+
}
|
|
393
|
+
const obj = scene[i].getObj();
|
|
394
|
+
if (obj.isCollection) {
|
|
395
|
+
this.renderScene(device, passEncoder, obj.getScene(), diff);
|
|
361
396
|
continue;
|
|
362
397
|
}
|
|
363
|
-
const buffer = new Float32Array(
|
|
398
|
+
const buffer = new Float32Array(obj.getBuffer(this.camera));
|
|
364
399
|
const vertexCount = buffer.length / BUF_LEN;
|
|
365
400
|
device.queue.writeBuffer(vertexBuffer, currentOffset, buffer);
|
|
366
401
|
vertexBuffer.unmap();
|
|
367
|
-
const is3d = Boolean(
|
|
368
|
-
if (
|
|
402
|
+
const is3d = Boolean(obj.is3d);
|
|
403
|
+
if (obj.isWireframe()) {
|
|
369
404
|
if (is3d) {
|
|
370
405
|
passEncoder.setPipeline(this.pipelines.lineStrip3d);
|
|
371
406
|
}
|
|
@@ -374,7 +409,7 @@ export class Simulation {
|
|
|
374
409
|
}
|
|
375
410
|
}
|
|
376
411
|
else {
|
|
377
|
-
const type =
|
|
412
|
+
const type = obj.getGeometryType();
|
|
378
413
|
if (type === 'strip') {
|
|
379
414
|
if (is3d) {
|
|
380
415
|
passEncoder.setPipeline(this.pipelines.triangleStrip3d);
|
|
@@ -393,9 +428,9 @@ export class Simulation {
|
|
|
393
428
|
}
|
|
394
429
|
}
|
|
395
430
|
let instances = 1;
|
|
396
|
-
if (
|
|
397
|
-
instances =
|
|
398
|
-
const buf =
|
|
431
|
+
if (obj.isInstance) {
|
|
432
|
+
instances = obj.getNumInstances();
|
|
433
|
+
const buf = obj.getMatrixBuffer();
|
|
399
434
|
if (buf && this.renderInfo) {
|
|
400
435
|
const uniformBindGroup = device.createBindGroup({
|
|
401
436
|
layout: this.renderInfo.bindGroupLayout,
|
|
@@ -421,6 +456,9 @@ export class Simulation {
|
|
|
421
456
|
passEncoder.draw(vertexCount, instances, 0, 0);
|
|
422
457
|
currentOffset += buffer.byteLength;
|
|
423
458
|
}
|
|
459
|
+
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
460
|
+
removeObject(scene, scene[i].getObj());
|
|
461
|
+
}
|
|
424
462
|
}
|
|
425
463
|
fitElement() {
|
|
426
464
|
this.assertHasCanvas();
|
|
@@ -457,17 +495,32 @@ export class SceneCollection extends SimulationElement3d {
|
|
|
457
495
|
getScene() {
|
|
458
496
|
return this.scene;
|
|
459
497
|
}
|
|
498
|
+
setSceneObjects(newScene) {
|
|
499
|
+
this.scene = newScene.map((item) => new SimSceneObjInfo(item));
|
|
500
|
+
}
|
|
460
501
|
setScene(newScene) {
|
|
461
502
|
this.scene = newScene;
|
|
462
503
|
}
|
|
463
504
|
add(el) {
|
|
464
|
-
|
|
505
|
+
addObject(this.scene, el);
|
|
506
|
+
}
|
|
507
|
+
remove(el) {
|
|
508
|
+
removeObject(this.scene, el);
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* @param lifetime - ms
|
|
512
|
+
*/
|
|
513
|
+
setLifetime(el, lifetime) {
|
|
514
|
+
for (let i = 0; i < this.scene.length; i++) {
|
|
515
|
+
if (this.scene[i].getObj() === el)
|
|
516
|
+
this.scene[i].setLifetime(lifetime);
|
|
517
|
+
}
|
|
465
518
|
}
|
|
466
519
|
empty() {
|
|
467
520
|
this.scene = [];
|
|
468
521
|
}
|
|
469
522
|
getSceneBuffer(camera) {
|
|
470
|
-
return this.scene.map((item) => item.getBuffer(camera)).flat();
|
|
523
|
+
return this.scene.map((item) => item.getObj().getBuffer(camera)).flat();
|
|
471
524
|
}
|
|
472
525
|
getWireframe(camera) {
|
|
473
526
|
return this.getSceneBuffer(camera);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference types="
|
|
1
|
+
/// <reference types="@webgpu/types" />
|
|
2
2
|
import { CubicBezierCurve2d, SplinePoint2d } from './graphics.js';
|
|
3
3
|
import { Color, Vertex } from './utils.js';
|
|
4
4
|
export type Shift<T extends any[]> = ((...args: T) => any) extends (arg1: any, ...rest: infer R) => any ? R : never;
|