simulationjsv2 0.7.3 → 0.8.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/README.md +1 -3
- package/TODO.md +6 -5
- package/dist/buffers.d.ts +13 -0
- package/dist/buffers.js +44 -0
- package/dist/constants.d.ts +0 -6
- package/dist/constants.js +1 -6
- package/dist/geometry.d.ts +23 -41
- package/dist/geometry.js +85 -204
- package/dist/globals.d.ts +26 -0
- package/dist/globals.js +51 -0
- package/dist/graphics.d.ts +44 -29
- package/dist/graphics.js +252 -229
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/internalUtils.d.ts +14 -31
- package/dist/internalUtils.js +83 -153
- package/dist/materials.d.ts +20 -0
- package/dist/materials.js +51 -0
- package/dist/shaders.d.ts +37 -0
- package/dist/shaders.js +330 -0
- package/dist/simulation.d.ts +7 -24
- package/dist/simulation.js +72 -338
- package/dist/types.d.ts +51 -45
- package/dist/utils.d.ts +8 -3
- package/dist/utils.js +36 -8
- package/package.json +1 -1
package/dist/simulation.js
CHANGED
|
@@ -1,58 +1,10 @@
|
|
|
1
1
|
import { vec3 } from 'wgpu-matrix';
|
|
2
|
-
import {
|
|
3
|
-
import { BUF_LEN, worldProjMatOffset } from './constants.js';
|
|
2
|
+
import { SimulationElement3d } from './graphics.js';
|
|
4
3
|
import { Color, matrix4, transitionValues, vector2, vector3 } from './utils.js';
|
|
5
|
-
import {
|
|
6
|
-
import { SimSceneObjInfo, buildDepthTexture, buildMultisampleTexture, updateProjectionMatrix, createPipeline, getTotalVertices, logger, removeObjectId, updateOrthoProjectionMatrix, updateWorldProjectionMatrix, globalInfo } from './internalUtils.js';
|
|
4
|
+
import { SimSceneObjInfo, buildDepthTexture, buildMultisampleTexture, updateProjectionMatrix, getVertexAndIndexSize, removeObjectId, updateOrthoProjectionMatrix, updateWorldProjectionMatrix, CachedArray } from './internalUtils.js';
|
|
7
5
|
import { Settings } from './settings.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
worldProjectionMatrix: mat4x4<f32>,
|
|
11
|
-
modelProjectionMatrix: mat4x4<f32>,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
15
|
-
|
|
16
|
-
@group(0) @binding(1) var<storage> instanceMatrices: array<mat4x4f>;
|
|
17
|
-
|
|
18
|
-
struct VertexOutput {
|
|
19
|
-
@builtin(position) Position: vec4<f32>,
|
|
20
|
-
@location(0) fragUV: vec2<f32>,
|
|
21
|
-
@location(1) fragColor: vec4<f32>,
|
|
22
|
-
@location(2) fragPosition: vec4<f32>,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@vertex
|
|
26
|
-
fn vertex_main(
|
|
27
|
-
@builtin(instance_index) instanceIdx: u32,
|
|
28
|
-
@location(0) position: vec3<f32>,
|
|
29
|
-
@location(1) color: vec4<f32>,
|
|
30
|
-
@location(2) uv: vec2<f32>,
|
|
31
|
-
@location(3) drawingInstance: f32
|
|
32
|
-
) -> VertexOutput {
|
|
33
|
-
var output: VertexOutput;
|
|
34
|
-
|
|
35
|
-
if (drawingInstance == 1) {
|
|
36
|
-
output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * instanceMatrices[instanceIdx] * vec4(position, 1.0);
|
|
37
|
-
} else {
|
|
38
|
-
output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * vec4(position, 1.0);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
output.fragUV = uv;
|
|
42
|
-
output.fragPosition = output.Position;
|
|
43
|
-
output.fragColor = color;
|
|
44
|
-
return output;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@fragment
|
|
48
|
-
fn fragment_main(
|
|
49
|
-
@location(0) fragUV: vec2<f32>,
|
|
50
|
-
@location(1) fragColor: vec4<f32>,
|
|
51
|
-
@location(2) fragPosition: vec4<f32>
|
|
52
|
-
) -> @location(0) vec4<f32> {
|
|
53
|
-
return fragColor;
|
|
54
|
-
}
|
|
55
|
-
`;
|
|
6
|
+
import { MemoBuffer } from './buffers.js';
|
|
7
|
+
import { globalInfo, logger } from './globals.js';
|
|
56
8
|
const simjsFrameRateCss = `.simjs-frame-rate {
|
|
57
9
|
position: absolute;
|
|
58
10
|
top: 0;
|
|
@@ -99,28 +51,10 @@ class FrameRateView {
|
|
|
99
51
|
}
|
|
100
52
|
}
|
|
101
53
|
}
|
|
102
|
-
const baseBindGroupLayout = {
|
|
103
|
-
entries: [
|
|
104
|
-
{
|
|
105
|
-
binding: 0,
|
|
106
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
107
|
-
buffer: {
|
|
108
|
-
type: 'uniform'
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
binding: 1,
|
|
113
|
-
visibility: GPUShaderStage.VERTEX,
|
|
114
|
-
buffer: {
|
|
115
|
-
type: 'read-only-storage'
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
]
|
|
119
|
-
};
|
|
120
54
|
let aspectRatio = 0;
|
|
121
55
|
const projMat = matrix4();
|
|
122
|
-
const
|
|
123
|
-
const
|
|
56
|
+
export const worldProjectionMatrix = matrix4();
|
|
57
|
+
export const orthogonalMatrix = matrix4();
|
|
124
58
|
export class Camera {
|
|
125
59
|
pos;
|
|
126
60
|
rotation;
|
|
@@ -216,25 +150,24 @@ export class Simulation extends Settings {
|
|
|
216
150
|
fittingElement = false;
|
|
217
151
|
running = true;
|
|
218
152
|
initialized = false;
|
|
219
|
-
pipelines = null;
|
|
220
|
-
renderInfo = null;
|
|
221
153
|
resizeEvents;
|
|
222
154
|
frameRateView;
|
|
155
|
+
transparentElements;
|
|
156
|
+
vertexBuffer;
|
|
157
|
+
indexBuffer;
|
|
223
158
|
constructor(idOrCanvasRef, sceneCamera = null, showFrameRate = false) {
|
|
224
159
|
super();
|
|
225
160
|
if (typeof idOrCanvasRef === 'string') {
|
|
226
161
|
const ref = document.getElementById(idOrCanvasRef);
|
|
227
|
-
if (ref
|
|
228
|
-
this.canvasRef = ref;
|
|
229
|
-
else
|
|
162
|
+
if (!ref)
|
|
230
163
|
throw logger.error(`Cannot find canvas with id ${idOrCanvasRef}`);
|
|
164
|
+
this.canvasRef = ref;
|
|
231
165
|
}
|
|
232
166
|
else if (idOrCanvasRef instanceof HTMLCanvasElement) {
|
|
233
167
|
this.canvasRef = idOrCanvasRef;
|
|
234
168
|
}
|
|
235
|
-
else
|
|
169
|
+
else
|
|
236
170
|
throw logger.error(`Canvas ref/id provided is invalid`);
|
|
237
|
-
}
|
|
238
171
|
const parent = this.canvasRef.parentElement;
|
|
239
172
|
if (sceneCamera) {
|
|
240
173
|
camera = sceneCamera;
|
|
@@ -247,6 +180,9 @@ export class Simulation extends Settings {
|
|
|
247
180
|
});
|
|
248
181
|
this.frameRateView = new FrameRateView(showFrameRate);
|
|
249
182
|
this.frameRateView.updateFrameRate(1);
|
|
183
|
+
this.transparentElements = new CachedArray();
|
|
184
|
+
this.vertexBuffer = new MemoBuffer(GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, 0);
|
|
185
|
+
this.indexBuffer = new MemoBuffer(GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, 0);
|
|
250
186
|
}
|
|
251
187
|
handleCanvasResize(parent) {
|
|
252
188
|
if (this.fittingElement) {
|
|
@@ -325,13 +261,18 @@ export class Simulation extends Settings {
|
|
|
325
261
|
throw logger.error('Context is null');
|
|
326
262
|
const device = await adapter.requestDevice();
|
|
327
263
|
globalInfo.setDevice(device);
|
|
264
|
+
const screenSize = vector2(this.canvasRef.width, this.canvasRef.height);
|
|
265
|
+
camera.setScreenSize(screenSize);
|
|
266
|
+
const canvas = this.canvasRef;
|
|
267
|
+
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
268
|
+
canvas.height = canvas.clientHeight * devicePixelRatio;
|
|
269
|
+
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
328
270
|
ctx.configure({
|
|
329
271
|
device,
|
|
330
|
-
format:
|
|
272
|
+
format: presentationFormat,
|
|
273
|
+
alphaMode: 'opaque'
|
|
331
274
|
});
|
|
332
|
-
|
|
333
|
-
camera.setScreenSize(screenSize);
|
|
334
|
-
this.render(ctx);
|
|
275
|
+
this.render(device, ctx, canvas);
|
|
335
276
|
})();
|
|
336
277
|
}
|
|
337
278
|
stop() {
|
|
@@ -346,35 +287,7 @@ export class Simulation extends Settings {
|
|
|
346
287
|
getSceneObjects() {
|
|
347
288
|
return this.scene.map((item) => item.getObj());
|
|
348
289
|
}
|
|
349
|
-
render(ctx) {
|
|
350
|
-
const device = globalInfo.getDevice();
|
|
351
|
-
if (this.canvasRef === null || device === null)
|
|
352
|
-
return;
|
|
353
|
-
const canvas = this.canvasRef;
|
|
354
|
-
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
355
|
-
canvas.height = canvas.clientHeight * devicePixelRatio;
|
|
356
|
-
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
357
|
-
const shaderModule = device.createShaderModule({ code: shader });
|
|
358
|
-
ctx.configure({
|
|
359
|
-
device,
|
|
360
|
-
format: presentationFormat,
|
|
361
|
-
alphaMode: 'premultiplied'
|
|
362
|
-
});
|
|
363
|
-
const instanceBuffer = device.createBuffer({
|
|
364
|
-
size: 10 * 4 * 16,
|
|
365
|
-
usage: GPUBufferUsage.STORAGE
|
|
366
|
-
});
|
|
367
|
-
const bindGroupLayout = device.createBindGroupLayout(baseBindGroupLayout);
|
|
368
|
-
this.renderInfo = {
|
|
369
|
-
bindGroupLayout,
|
|
370
|
-
instanceBuffer,
|
|
371
|
-
vertexBuffer: null
|
|
372
|
-
};
|
|
373
|
-
this.pipelines = {
|
|
374
|
-
triangleList: createPipeline(device, shaderModule, [bindGroupLayout], presentationFormat, 'triangle-list'),
|
|
375
|
-
triangleStrip: createPipeline(device, shaderModule, [bindGroupLayout], presentationFormat, 'triangle-strip'),
|
|
376
|
-
lineStrip: createPipeline(device, shaderModule, [bindGroupLayout], presentationFormat, 'line-strip')
|
|
377
|
-
};
|
|
290
|
+
render(device, ctx, canvas) {
|
|
378
291
|
const colorAttachment = {
|
|
379
292
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
380
293
|
// @ts-ignore
|
|
@@ -388,8 +301,8 @@ export class Simulation extends Settings {
|
|
|
388
301
|
updateProjectionMatrix(projMat, newAspectRatio);
|
|
389
302
|
aspectRatio = newAspectRatio;
|
|
390
303
|
}
|
|
391
|
-
updateWorldProjectionMatrix(
|
|
392
|
-
updateOrthoProjectionMatrix(
|
|
304
|
+
updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
|
|
305
|
+
updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
|
|
393
306
|
let multisampleTexture = buildMultisampleTexture(device, ctx, canvas.width, canvas.height);
|
|
394
307
|
let depthTexture = buildDepthTexture(device, canvas.width, canvas.height);
|
|
395
308
|
const renderPassDescriptor = {
|
|
@@ -405,7 +318,7 @@ export class Simulation extends Settings {
|
|
|
405
318
|
let prev = Date.now() - 10;
|
|
406
319
|
let prevFps = 0;
|
|
407
320
|
const frame = async () => {
|
|
408
|
-
if (!canvas
|
|
321
|
+
if (!canvas)
|
|
409
322
|
return;
|
|
410
323
|
requestAnimationFrame(frame);
|
|
411
324
|
if (!this.running)
|
|
@@ -414,12 +327,10 @@ export class Simulation extends Settings {
|
|
|
414
327
|
const diff = Math.max(now - prev, 1);
|
|
415
328
|
prev = now;
|
|
416
329
|
const fps = 1000 / diff;
|
|
417
|
-
if (
|
|
330
|
+
if (this.frameRateView.isActive() && fps === prevFps) {
|
|
418
331
|
this.frameRateView.updateFrameRate(fps);
|
|
419
332
|
}
|
|
420
333
|
prevFps = fps;
|
|
421
|
-
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
422
|
-
canvas.height = canvas.clientHeight * devicePixelRatio;
|
|
423
334
|
const screenSize = camera.getScreenSize();
|
|
424
335
|
if (screenSize[0] !== canvas.width || screenSize[1] !== canvas.height) {
|
|
425
336
|
camera.setScreenSize(vector2(canvas.width, canvas.height));
|
|
@@ -427,7 +338,7 @@ export class Simulation extends Settings {
|
|
|
427
338
|
screenSize[1] = canvas.height;
|
|
428
339
|
aspectRatio = camera.getAspectRatio();
|
|
429
340
|
updateProjectionMatrix(projMat, aspectRatio);
|
|
430
|
-
updateWorldProjectionMatrix(
|
|
341
|
+
updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
|
|
431
342
|
multisampleTexture = buildMultisampleTexture(device, ctx, screenSize[0], screenSize[1]);
|
|
432
343
|
depthTexture = buildDepthTexture(device, screenSize[0], screenSize[1]);
|
|
433
344
|
renderPassDescriptor.depthStencilAttachment.view = depthTexture.createView();
|
|
@@ -439,140 +350,72 @@ export class Simulation extends Settings {
|
|
|
439
350
|
// @ts-ignore
|
|
440
351
|
renderPassDescriptor.colorAttachments[0].resolveTarget = ctx.getCurrentTexture().createView();
|
|
441
352
|
if (camera.hasUpdated()) {
|
|
442
|
-
updateOrthoProjectionMatrix(
|
|
443
|
-
updateWorldProjectionMatrix(
|
|
353
|
+
updateOrthoProjectionMatrix(orthogonalMatrix, camera.getScreenSize());
|
|
354
|
+
updateWorldProjectionMatrix(worldProjectionMatrix, projMat);
|
|
444
355
|
}
|
|
445
356
|
const commandEncoder = device.createCommandEncoder();
|
|
446
357
|
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
this.renderScene(device, passEncoder, this.renderInfo.vertexBuffer, this.scene, 0, diff);
|
|
358
|
+
const [totalVerticesSize, totalIndexSize] = getVertexAndIndexSize(this.scene);
|
|
359
|
+
this.vertexBuffer.setSize(totalVerticesSize * 4);
|
|
360
|
+
this.indexBuffer.setSize(totalIndexSize * 4);
|
|
361
|
+
this.transparentElements.reset();
|
|
362
|
+
const [opaqueVertexOffset, opaqueIndexOffset] = this.renderScene(device, passEncoder, this.vertexBuffer.getBuffer(), this.indexBuffer.getBuffer(), 0, 0, this.scene, this.scene.length, diff, false);
|
|
363
|
+
this.renderScene(device, passEncoder, this.vertexBuffer.getBuffer(), this.indexBuffer.getBuffer(), opaqueVertexOffset, opaqueIndexOffset, this.transparentElements.getArray(), this.transparentElements.length, diff, true);
|
|
457
364
|
camera.updateConsumed();
|
|
458
365
|
passEncoder.end();
|
|
459
366
|
device.queue.submit([commandEncoder.finish()]);
|
|
460
367
|
};
|
|
461
368
|
requestAnimationFrame(frame);
|
|
462
369
|
}
|
|
463
|
-
renderScene(device, passEncoder, vertexBuffer, scene,
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
let currentOffset = startOffset;
|
|
370
|
+
renderScene(device, passEncoder, vertexBuffer, indexBuffer, startVertexOffset, startIndexOffset, scene, numElements, diff, transparent) {
|
|
371
|
+
let vertexOffset = startVertexOffset;
|
|
372
|
+
let indexOffset = startIndexOffset;
|
|
467
373
|
const toRemove = [];
|
|
468
|
-
for (let i = 0; i <
|
|
469
|
-
const
|
|
374
|
+
for (let i = 0; i < numElements; i++) {
|
|
375
|
+
const sceneObj = scene[i];
|
|
376
|
+
const lifetime = sceneObj.getLifetime();
|
|
470
377
|
if (lifetime !== null) {
|
|
471
|
-
const complete =
|
|
378
|
+
const complete = sceneObj.lifetimeComplete();
|
|
472
379
|
if (complete) {
|
|
473
380
|
toRemove.push(i);
|
|
474
381
|
continue;
|
|
475
382
|
}
|
|
476
|
-
|
|
383
|
+
sceneObj.traverseLife(diff);
|
|
384
|
+
}
|
|
385
|
+
const obj = sceneObj.getObj();
|
|
386
|
+
if (!transparent && obj.isTransparent()) {
|
|
387
|
+
this.transparentElements.add(sceneObj);
|
|
388
|
+
continue;
|
|
477
389
|
}
|
|
478
|
-
const obj = scene[i].getObj();
|
|
479
390
|
if (obj.hasChildren()) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
shaderInfo = {
|
|
485
|
-
pipeline,
|
|
486
|
-
paramGenerator: obj.getVertexParamGenerator(),
|
|
487
|
-
bufferInfo: obj.hasBindGroup()
|
|
488
|
-
? {
|
|
489
|
-
buffers: obj.getBindGroupBuffers(device),
|
|
490
|
-
layout: obj.getBindGroupLayout()
|
|
491
|
-
}
|
|
492
|
-
: null
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
currentOffset += this.renderScene(device, passEncoder, vertexBuffer, obj.getChildrenInfos(), currentOffset, diff, shaderInfo);
|
|
391
|
+
const childObjects = obj.getChildrenInfos();
|
|
392
|
+
const [vertexDiff, indexDiff] = this.renderScene(device, passEncoder, vertexBuffer, indexBuffer, vertexOffset, indexOffset, childObjects, childObjects.length, diff, transparent);
|
|
393
|
+
vertexOffset += vertexDiff;
|
|
394
|
+
indexOffset += indexDiff;
|
|
497
395
|
}
|
|
498
396
|
if (obj.isEmpty)
|
|
499
397
|
continue;
|
|
500
|
-
const
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
device.queue.writeBuffer(
|
|
504
|
-
vertexBuffer.
|
|
505
|
-
passEncoder.
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
passEncoder.
|
|
512
|
-
}
|
|
513
|
-
else if (obj.isWireframe()) {
|
|
514
|
-
passEncoder.setPipeline(this.pipelines.lineStrip);
|
|
398
|
+
const vertices = obj.getVertexBuffer();
|
|
399
|
+
const indices = obj.getIndexBuffer();
|
|
400
|
+
device.queue.writeBuffer(vertexBuffer, vertexOffset, vertices.buffer, vertices.byteOffset, vertices.byteLength);
|
|
401
|
+
device.queue.writeBuffer(indexBuffer, indexOffset, indices.buffer, indices.byteOffset, indices.byteLength);
|
|
402
|
+
passEncoder.setVertexBuffer(0, vertexBuffer, vertexOffset, vertices.byteLength);
|
|
403
|
+
passEncoder.setIndexBuffer(indexBuffer, 'uint32', indexOffset, indices.byteLength);
|
|
404
|
+
passEncoder.setPipeline(obj.getPipeline());
|
|
405
|
+
obj.writeBuffers();
|
|
406
|
+
const instances = obj.isInstance ? obj.getNumInstances() : 1;
|
|
407
|
+
const bindGroups = obj.getShader().getBindGroups(obj);
|
|
408
|
+
for (let i = 0; i < bindGroups.length; i++) {
|
|
409
|
+
passEncoder.setBindGroup(i, bindGroups[i]);
|
|
515
410
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
passEncoder.setPipeline(this.pipelines.triangleStrip);
|
|
520
|
-
}
|
|
521
|
-
else if (type === 'list') {
|
|
522
|
-
passEncoder.setPipeline(this.pipelines.triangleList);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
let instances = 1;
|
|
526
|
-
if (this.renderInfo) {
|
|
527
|
-
let instanceBuffer;
|
|
528
|
-
if (obj.isInstance) {
|
|
529
|
-
instances = obj.getNumInstances();
|
|
530
|
-
instanceBuffer =
|
|
531
|
-
obj.getMatrixBuffer() ?? this.renderInfo.instanceBuffer;
|
|
532
|
-
}
|
|
533
|
-
else {
|
|
534
|
-
instanceBuffer = this.renderInfo.instanceBuffer;
|
|
535
|
-
}
|
|
536
|
-
const uniformBindGroup = device.createBindGroup({
|
|
537
|
-
layout: this.renderInfo.bindGroupLayout,
|
|
538
|
-
entries: [
|
|
539
|
-
{
|
|
540
|
-
binding: 0,
|
|
541
|
-
resource: {
|
|
542
|
-
buffer: uniformBuffer
|
|
543
|
-
}
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
binding: 1,
|
|
547
|
-
resource: {
|
|
548
|
-
buffer: instanceBuffer
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
]
|
|
552
|
-
});
|
|
553
|
-
passEncoder.setBindGroup(0, uniformBindGroup);
|
|
554
|
-
}
|
|
555
|
-
if (shaderInfo && shaderInfo.bufferInfo) {
|
|
556
|
-
const bindGroupEntries = shaderInfo.bufferInfo.buffers.map((buffer, index) => ({
|
|
557
|
-
binding: index,
|
|
558
|
-
resource: {
|
|
559
|
-
buffer
|
|
560
|
-
}
|
|
561
|
-
}));
|
|
562
|
-
const bindGroup = device.createBindGroup({
|
|
563
|
-
layout: shaderInfo.bufferInfo.layout,
|
|
564
|
-
entries: bindGroupEntries
|
|
565
|
-
});
|
|
566
|
-
passEncoder.setBindGroup(1, bindGroup);
|
|
567
|
-
}
|
|
568
|
-
// TODO maybe switch to drawIndexed
|
|
569
|
-
passEncoder.draw(vertexCount, instances, 0, 0);
|
|
570
|
-
currentOffset += buffer.byteLength;
|
|
411
|
+
passEncoder.drawIndexed(indices.length, instances);
|
|
412
|
+
vertexOffset += vertices.byteLength;
|
|
413
|
+
indexOffset += indices.byteLength;
|
|
571
414
|
}
|
|
572
415
|
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
573
|
-
this.remove(scene
|
|
416
|
+
this.remove(scene.at(i).getObj());
|
|
574
417
|
}
|
|
575
|
-
return
|
|
418
|
+
return [vertexOffset - startVertexOffset, indexOffset - startIndexOffset];
|
|
576
419
|
}
|
|
577
420
|
fitElement() {
|
|
578
421
|
if (this.canvasRef === null)
|
|
@@ -586,112 +429,3 @@ export class Simulation extends Settings {
|
|
|
586
429
|
}
|
|
587
430
|
}
|
|
588
431
|
}
|
|
589
|
-
const defaultShaderCode = `
|
|
590
|
-
struct Uniforms {
|
|
591
|
-
worldProjectionMatrix: mat4x4<f32>,
|
|
592
|
-
modelProjectionMatrix: mat4x4<f32>,
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
596
|
-
|
|
597
|
-
@group(0) @binding(1) var<storage> instanceMatrices: array<mat4x4f>;
|
|
598
|
-
`;
|
|
599
|
-
export class ShaderGroup extends EmptyElement {
|
|
600
|
-
code;
|
|
601
|
-
module;
|
|
602
|
-
pipeline;
|
|
603
|
-
bindGroupLayout;
|
|
604
|
-
topology;
|
|
605
|
-
paramGenerator;
|
|
606
|
-
vertexParams;
|
|
607
|
-
bindGroup;
|
|
608
|
-
valueBuffers;
|
|
609
|
-
constructor(shaderCode, topology = 'triangle-list', vertexParams, paramGenerator, bindGroup) {
|
|
610
|
-
super();
|
|
611
|
-
this.geometry = new BlankGeometry();
|
|
612
|
-
this.code = defaultShaderCode + shaderCode;
|
|
613
|
-
this.module = null;
|
|
614
|
-
this.pipeline = null;
|
|
615
|
-
this.bindGroupLayout = null;
|
|
616
|
-
this.bindGroup = bindGroup || null;
|
|
617
|
-
this.topology = topology;
|
|
618
|
-
this.paramGenerator = paramGenerator;
|
|
619
|
-
this.vertexParams = vertexParams;
|
|
620
|
-
this.valueBuffers = null;
|
|
621
|
-
}
|
|
622
|
-
initPipeline() {
|
|
623
|
-
const device = globalInfo.errorGetDevice();
|
|
624
|
-
this.module = device.createShaderModule({ code: this.code });
|
|
625
|
-
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
626
|
-
const bindGroupLayout = device.createBindGroupLayout(baseBindGroupLayout);
|
|
627
|
-
const bindGroups = [bindGroupLayout];
|
|
628
|
-
if (this.bindGroup !== null) {
|
|
629
|
-
const entryValues = this.bindGroup.bindings.map((binding, index) => ({
|
|
630
|
-
binding: index,
|
|
631
|
-
visibility: binding.visibility,
|
|
632
|
-
buffer: binding.buffer
|
|
633
|
-
}));
|
|
634
|
-
this.bindGroupLayout = device.createBindGroupLayout({
|
|
635
|
-
entries: entryValues
|
|
636
|
-
});
|
|
637
|
-
bindGroups.push(this.bindGroupLayout);
|
|
638
|
-
}
|
|
639
|
-
this.pipeline = createPipeline(device, this.module, bindGroups, presentationFormat, this.topology, this.vertexParams);
|
|
640
|
-
}
|
|
641
|
-
getBindGroupLayout() {
|
|
642
|
-
return this.bindGroupLayout;
|
|
643
|
-
}
|
|
644
|
-
getPipeline() {
|
|
645
|
-
if (!this.pipeline)
|
|
646
|
-
this.initPipeline();
|
|
647
|
-
return this.pipeline;
|
|
648
|
-
}
|
|
649
|
-
getBindGroupBuffers(device) {
|
|
650
|
-
if (this.bindGroup === null)
|
|
651
|
-
return null;
|
|
652
|
-
if (device === null)
|
|
653
|
-
return null;
|
|
654
|
-
const values = this.bindGroup.values();
|
|
655
|
-
if (this.valueBuffers === null) {
|
|
656
|
-
this.valueBuffers = [];
|
|
657
|
-
for (let i = 0; i < values.length; i++) {
|
|
658
|
-
const buffer = this.createBuffer(device, values[i]);
|
|
659
|
-
this.valueBuffers.push(buffer);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
else {
|
|
663
|
-
for (let i = 0; i < values.length; i++) {
|
|
664
|
-
const arrayConstructor = values[i].array;
|
|
665
|
-
const array = new arrayConstructor(values[i].value);
|
|
666
|
-
if (array.byteLength > this.valueBuffers[i].size) {
|
|
667
|
-
const newBuffer = this.createBuffer(device, values[i]);
|
|
668
|
-
this.valueBuffers[i].destroy();
|
|
669
|
-
this.valueBuffers[i] = newBuffer;
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
device.queue.writeBuffer(this.valueBuffers[i], 0, array.buffer, array.byteOffset, array.byteLength);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
return this.valueBuffers;
|
|
677
|
-
}
|
|
678
|
-
createBuffer(device, value) {
|
|
679
|
-
const arrayConstructor = value.array;
|
|
680
|
-
const array = new arrayConstructor(value.value);
|
|
681
|
-
const buffer = device.createBuffer({
|
|
682
|
-
mappedAtCreation: true,
|
|
683
|
-
size: array.byteLength,
|
|
684
|
-
usage: value.usage
|
|
685
|
-
});
|
|
686
|
-
const bufferArr = new arrayConstructor(buffer.getMappedRange());
|
|
687
|
-
bufferArr.set(array);
|
|
688
|
-
buffer.unmap();
|
|
689
|
-
return buffer;
|
|
690
|
-
}
|
|
691
|
-
getVertexParamGenerator() {
|
|
692
|
-
return this.paramGenerator;
|
|
693
|
-
}
|
|
694
|
-
hasBindGroup() {
|
|
695
|
-
return !!this.bindGroup;
|
|
696
|
-
}
|
|
697
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/// <reference types="@webgpu/types" />
|
|
2
|
+
import { MemoBuffer } from './buffers.js';
|
|
2
3
|
import { CubicBezierCurve2d, SimulationElement2d, SimulationElement3d, SplinePoint2d } from './graphics.js';
|
|
3
|
-
import { Color
|
|
4
|
+
import { Color } from './utils.js';
|
|
4
5
|
export type FloatArray = Float32Array | Float64Array;
|
|
6
|
+
export type UintArray = Uint8Array | Uint16Array | Uint32Array;
|
|
7
|
+
export type IntArray = Int8Array | Int16Array | Int32Array;
|
|
8
|
+
export type ArrayTypes = FloatArray | UintArray | IntArray;
|
|
5
9
|
export type Vector4 = FloatArray & [number, number, number, number];
|
|
6
10
|
export type Vector3 = FloatArray & [number, number, number];
|
|
7
11
|
export type Vector2 = FloatArray & [number, number];
|
|
@@ -29,84 +33,86 @@ export type VertexColorMap = Record<number, Color>;
|
|
|
29
33
|
export type ElementRotation<T extends Vector2 | Vector3> = T extends Vector2 ? number : T;
|
|
30
34
|
export type AnySimulationElement = SimulationElement2d | SimulationElement3d;
|
|
31
35
|
export type EmptyParams = object;
|
|
32
|
-
export
|
|
36
|
+
export interface CubeGeometryParams {
|
|
33
37
|
width: number;
|
|
34
38
|
height: number;
|
|
35
39
|
depth: number;
|
|
36
|
-
}
|
|
37
|
-
export
|
|
40
|
+
}
|
|
41
|
+
export interface SquareGeometryParams {
|
|
38
42
|
width: number;
|
|
39
43
|
height: number;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
export type CircleGeometryParams = {
|
|
44
|
+
}
|
|
45
|
+
export interface CircleGeometryParams {
|
|
44
46
|
radius: number;
|
|
45
47
|
detail: number;
|
|
46
|
-
}
|
|
47
|
-
export
|
|
48
|
+
}
|
|
49
|
+
export interface Spline2dGeometryParams {
|
|
48
50
|
points: SplinePoint2d[];
|
|
49
|
-
curves: CubicBezierCurve2d[];
|
|
50
|
-
distance: number;
|
|
51
51
|
detail: number;
|
|
52
52
|
interpolateStart: number;
|
|
53
53
|
interpolateLimit: number;
|
|
54
54
|
thickness: number;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
curves: CubicBezierCurve2d[];
|
|
56
|
+
distance: number;
|
|
57
|
+
vertexInterpolations: number[];
|
|
58
|
+
curveVertexIndices: number[];
|
|
59
|
+
}
|
|
60
|
+
export interface LineGeometryParams {
|
|
59
61
|
pos: Vector3;
|
|
60
62
|
to: Vector3;
|
|
61
|
-
fromColor: Color | null;
|
|
62
|
-
toColor: Color | null;
|
|
63
63
|
thickness: number;
|
|
64
|
-
}
|
|
65
|
-
export
|
|
66
|
-
points: Vertex[];
|
|
67
|
-
};
|
|
68
|
-
export type TraceLinesParams = {
|
|
69
|
-
vertices: Vertex[];
|
|
64
|
+
}
|
|
65
|
+
export interface TraceLinesParams {
|
|
70
66
|
maxLength: number | null;
|
|
71
|
-
}
|
|
72
|
-
export
|
|
67
|
+
}
|
|
68
|
+
export interface PipelineGroup {
|
|
73
69
|
triangleList: GPURenderPipeline;
|
|
74
70
|
triangleStrip: GPURenderPipeline;
|
|
75
71
|
lineStrip: GPURenderPipeline;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
};
|
|
82
|
-
export type VertexParamGeneratorInfo = {
|
|
72
|
+
triangleListTransparent: GPURenderPipeline;
|
|
73
|
+
triangleStripTransparent: GPURenderPipeline;
|
|
74
|
+
lineStripTransparent: GPURenderPipeline;
|
|
75
|
+
}
|
|
76
|
+
export interface VertexParamGeneratorInfo {
|
|
83
77
|
bufferSize: number;
|
|
84
78
|
createBuffer: (x: number, y: number, z: number, color: Color) => number[];
|
|
85
|
-
}
|
|
86
|
-
export
|
|
79
|
+
}
|
|
80
|
+
export interface ShaderInfo {
|
|
87
81
|
pipeline: GPURenderPipeline;
|
|
88
82
|
paramGenerator: VertexParamGeneratorInfo;
|
|
89
83
|
bufferInfo: {
|
|
90
84
|
buffers: GPUBuffer[];
|
|
91
85
|
layout: GPUBindGroupLayout;
|
|
92
86
|
} | null;
|
|
93
|
-
}
|
|
94
|
-
export
|
|
87
|
+
}
|
|
88
|
+
export interface VertexParamInfo {
|
|
95
89
|
format: GPUVertexFormat;
|
|
96
90
|
size: number;
|
|
97
|
-
}
|
|
98
|
-
export
|
|
91
|
+
}
|
|
92
|
+
export interface BindGroupEntry {
|
|
99
93
|
visibility: GPUBindGroupLayoutEntry['visibility'];
|
|
100
94
|
buffer: GPUBindGroupLayoutEntry['buffer'];
|
|
101
|
-
}
|
|
95
|
+
}
|
|
102
96
|
export type ArrayConstructors = Float32ArrayConstructor | Float64ArrayConstructor | Int8ArrayConstructor | Int16ArrayConstructor | Int32ArrayConstructor;
|
|
103
|
-
export
|
|
104
|
-
export type BindGroupValue = {
|
|
97
|
+
export interface BindGroupValue {
|
|
105
98
|
value: number[];
|
|
106
99
|
usage: GPUBufferDescriptor['usage'];
|
|
107
100
|
array: ArrayConstructors;
|
|
108
|
-
}
|
|
109
|
-
export
|
|
101
|
+
}
|
|
102
|
+
export interface BindGroupInfo {
|
|
110
103
|
bindings: BindGroupEntry[];
|
|
111
104
|
values: () => BindGroupValue[];
|
|
112
|
-
}
|
|
105
|
+
}
|
|
106
|
+
export interface SimulationElementInfo {
|
|
107
|
+
topology: GPUPrimitiveTopology;
|
|
108
|
+
transparent: boolean;
|
|
109
|
+
cullMode: GPUCullMode;
|
|
110
|
+
}
|
|
111
|
+
export interface BufferInfo {
|
|
112
|
+
usage: GPUBufferDescriptor['usage'];
|
|
113
|
+
defaultSize?: number;
|
|
114
|
+
owned?: boolean;
|
|
115
|
+
}
|
|
116
|
+
export type VertexBufferWriter = (element: SimulationElement3d, buffer: Float32Array, vertex: Vector3, vertexIndex: number, offset: number) => void;
|
|
117
|
+
export type BufferWriter = (element: SimulationElement3d, buffers: MemoBuffer[], device: GPUDevice) => void;
|
|
118
|
+
export type BindGroupGenerator = (element: SimulationElement3d, buffers: MemoBuffer[]) => GPUBindGroup[];
|