simulationjsv2 0.10.5 → 0.11.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 +4 -0
- package/TODO.md +4 -20
- package/dist/backend.d.ts +38 -0
- package/dist/backend.js +127 -0
- package/dist/backends/backend.d.ts +22 -0
- package/dist/backends/backend.js +21 -0
- package/dist/backends/webgl.d.ts +19 -0
- package/dist/backends/webgl.js +112 -0
- package/dist/backends/webgpu.d.ts +25 -0
- package/dist/backends/webgpu.js +134 -0
- package/dist/buffers/buffer.d.ts +15 -0
- package/dist/buffers/buffer.js +42 -0
- package/dist/buffers/webgl.d.ts +13 -0
- package/dist/buffers/webgl.js +46 -0
- package/dist/buffers/webgpu.d.ts +12 -0
- package/dist/buffers/webgpu.js +40 -0
- package/dist/buffers.d.ts +20 -7
- package/dist/buffers.js +54 -20
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/geometry.d.ts +3 -2
- package/dist/geometry.js +8 -4
- package/dist/globals.d.ts +6 -7
- package/dist/globals.js +7 -12
- package/dist/graphics.d.ts +20 -21
- package/dist/graphics.js +57 -59
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/internalUtils.d.ts +3 -4
- package/dist/internalUtils.js +3 -1
- package/dist/shaders/shader.d.ts +18 -0
- package/dist/shaders/shader.js +63 -0
- package/dist/shaders/utils.d.ts +33 -0
- package/dist/shaders/utils.js +25 -0
- package/dist/shaders/webgl.d.ts +74 -0
- package/dist/shaders/webgl.js +242 -0
- package/dist/shaders/webgpu.d.ts +40 -0
- package/dist/{shaders.js → shaders/webgpu.js} +73 -114
- package/dist/simulation.d.ts +11 -5
- package/dist/simulation.js +49 -86
- package/dist/types.d.ts +54 -36
- package/dist/utils.d.ts +3 -4
- package/dist/utils.js +6 -9
- package/package.json +26 -26
- package/pnpm-workspace.yaml +2 -0
- package/dist/pipelineUtil.d.ts +0 -5
- package/dist/pipelineUtil.js +0 -22
- package/dist/shaders.d.ts +0 -37
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { WebGLMemoBuffer } from '../buffers/webgl.js';
|
|
2
|
+
import { FLOAT_SIZE, mat4ByteLength } from '../constants.js';
|
|
3
|
+
import { globalInfo, logger } from '../globals.js';
|
|
4
|
+
import { orthogonalMatrix, worldProjectionMatrix } from '../simulation.js';
|
|
5
|
+
import { defaultVertexBufferWriter, defaultVertexColorBufferWriter, SimJSShader } from './shader.js';
|
|
6
|
+
export class SimJSWebGLShader extends SimJSShader {
|
|
7
|
+
buffers;
|
|
8
|
+
shaderProgram = null;
|
|
9
|
+
shaderProgramInfoLayout = null;
|
|
10
|
+
shaderProgramInfo = null;
|
|
11
|
+
gl = null;
|
|
12
|
+
uniformBufferWriter;
|
|
13
|
+
getShaderProgramInfoFn;
|
|
14
|
+
vertexSource;
|
|
15
|
+
fragmentSource;
|
|
16
|
+
bufferDeclerations;
|
|
17
|
+
constructor(vertexSource, fragmentSource, bufferDeclerations, uniformBufferWriter, vertexBufferWriter, getShaderProgramInfoFn) {
|
|
18
|
+
super('webgl', vertexBufferWriter);
|
|
19
|
+
this.buffers = [];
|
|
20
|
+
this.vertexSource = vertexSource;
|
|
21
|
+
this.fragmentSource = fragmentSource;
|
|
22
|
+
this.uniformBufferWriter = uniformBufferWriter;
|
|
23
|
+
this.getShaderProgramInfoFn = getShaderProgramInfoFn;
|
|
24
|
+
this.bufferDeclerations = bufferDeclerations;
|
|
25
|
+
const canvas = globalInfo.getCanvas();
|
|
26
|
+
if (!canvas) {
|
|
27
|
+
globalInfo.addToInitShader(this);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const backend = canvas.getBackend().as('webgl');
|
|
31
|
+
this.init(backend.getContextOrError());
|
|
32
|
+
}
|
|
33
|
+
init(gl) {
|
|
34
|
+
this.gl = gl;
|
|
35
|
+
this.shaderProgram = this.initShaderProgram(gl, this.vertexSource, this.fragmentSource);
|
|
36
|
+
this.shaderProgramInfoLayout = this.getShaderProgramInfoFn();
|
|
37
|
+
this.shaderProgramInfo = this.programInfoLayoutToProgramInfo(this.shaderProgram, gl, this.shaderProgramInfoLayout);
|
|
38
|
+
for (const dec of this.bufferDeclerations) {
|
|
39
|
+
const buf = new WebGLMemoBuffer(this.gl, dec.target, dec.usage, dec.defaultCapacity ?? 0);
|
|
40
|
+
this.buffers.push(buf);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
programInfoLayoutToProgramInfo(program, gl, layout) {
|
|
44
|
+
const res = {
|
|
45
|
+
program: program,
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
attributeLocations: [],
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
uniformLocations: []
|
|
50
|
+
};
|
|
51
|
+
let bufferLength = 0;
|
|
52
|
+
for (const obj of layout.attributeLocations) {
|
|
53
|
+
const key = Object.keys(obj)[0];
|
|
54
|
+
const size = obj[key];
|
|
55
|
+
const loc = gl.getAttribLocation(program, key);
|
|
56
|
+
const tuple = [key, loc];
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
res.attributeLocations.push(tuple);
|
|
59
|
+
bufferLength += size;
|
|
60
|
+
}
|
|
61
|
+
this.bufferLength = bufferLength;
|
|
62
|
+
for (const obj of layout.uniformLocations) {
|
|
63
|
+
const key = Object.keys(obj)[0];
|
|
64
|
+
const loc = gl.getUniformLocation(program, key);
|
|
65
|
+
const tuple = [key, loc];
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
res.uniformLocations.push(tuple);
|
|
68
|
+
}
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
71
|
+
initShaderProgram(gl, vertexShaderSource, fragmentShaderSource) {
|
|
72
|
+
const vertexShader = this.loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
73
|
+
const fragmentShader = this.loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
74
|
+
const shaderProgram = gl.createProgram();
|
|
75
|
+
if (!shaderProgram)
|
|
76
|
+
throw logger.error('Shader program init error');
|
|
77
|
+
gl.attachShader(shaderProgram, vertexShader);
|
|
78
|
+
gl.attachShader(shaderProgram, fragmentShader);
|
|
79
|
+
gl.linkProgram(shaderProgram);
|
|
80
|
+
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
|
|
81
|
+
throw logger.error('Error initializing shader program');
|
|
82
|
+
}
|
|
83
|
+
return shaderProgram;
|
|
84
|
+
}
|
|
85
|
+
loadShader(ctx, shaderType, code) {
|
|
86
|
+
const shader = ctx.createShader(shaderType);
|
|
87
|
+
if (!shader)
|
|
88
|
+
throw logger.error('Error creating shader');
|
|
89
|
+
ctx.shaderSource(shader, code);
|
|
90
|
+
ctx.compileShader(shader);
|
|
91
|
+
if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) {
|
|
92
|
+
const err = logger.error(`Error compiling shaders: ${ctx.getShaderInfoLog(shader)}`);
|
|
93
|
+
ctx.deleteShader(shader);
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
return shader;
|
|
97
|
+
}
|
|
98
|
+
getShaderProgram() {
|
|
99
|
+
if (!this.shaderProgram)
|
|
100
|
+
throw logger.error('Shader program not initialized');
|
|
101
|
+
return this.shaderProgram;
|
|
102
|
+
}
|
|
103
|
+
getShaderProgramInfo() {
|
|
104
|
+
if (!this.shaderProgramInfo)
|
|
105
|
+
throw logger.error('Shader program not initialized');
|
|
106
|
+
return this.shaderProgramInfo;
|
|
107
|
+
}
|
|
108
|
+
writeUniformBuffers(obj) {
|
|
109
|
+
if (!this.gl || !this.shaderProgramInfo)
|
|
110
|
+
throw logger.error('Shader not initialized');
|
|
111
|
+
this.uniformBufferWriter(this.shaderProgramInfo, this.gl, obj, this.buffers);
|
|
112
|
+
}
|
|
113
|
+
writeShaderProgramAttributes(buffer, vertexCallOffset, vertexCallBuffer) {
|
|
114
|
+
if (!this.gl || !this.shaderProgramInfoLayout || !this.shaderProgramInfo) {
|
|
115
|
+
throw logger.error('Shader not initialized');
|
|
116
|
+
}
|
|
117
|
+
const gl = this.gl;
|
|
118
|
+
buffer.write(vertexCallBuffer, vertexCallOffset);
|
|
119
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer.getBuffer());
|
|
120
|
+
const STRIDE = this.bufferLength * FLOAT_SIZE;
|
|
121
|
+
let localOffset = 0;
|
|
122
|
+
for (let i = 0; i < this.shaderProgramInfo.attributeLocations.length; i++) {
|
|
123
|
+
const [key, loc] = this.shaderProgramInfo.attributeLocations[i];
|
|
124
|
+
const size = this.shaderProgramInfoLayout.attributeLocations[i][key];
|
|
125
|
+
gl.enableVertexAttribArray(loc);
|
|
126
|
+
gl.vertexAttribPointer(loc, size, gl.FLOAT, false, STRIDE, vertexCallOffset + localOffset);
|
|
127
|
+
localOffset += size * FLOAT_SIZE;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function defaultWebGLUniformBufferWriter(programInfo, gl, obj, _buffers) {
|
|
132
|
+
const projBuf = obj.is3d ? worldProjectionMatrix : orthogonalMatrix;
|
|
133
|
+
let buffer = obj.getUniformBuffer();
|
|
134
|
+
if (!buffer) {
|
|
135
|
+
buffer = new WebGLMemoBuffer(gl, gl.ARRAY_BUFFER, gl.DYNAMIC_DRAW, WEBGL_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE);
|
|
136
|
+
obj.setUniformBuffer(buffer);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
buffer.as('webgl');
|
|
140
|
+
}
|
|
141
|
+
gl.uniformMatrix4fv(programInfo.uniformLocations[0][1], false, projBuf);
|
|
142
|
+
const modelMatrix = obj.getModelMatrix();
|
|
143
|
+
gl.uniformMatrix4fv(programInfo.uniformLocations[1][1], false, modelMatrix);
|
|
144
|
+
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
145
|
+
// if (obj.isInstance) {
|
|
146
|
+
// buffers[0].write((obj as Instance<SimulationElement3d>).getInstanceBuffer());
|
|
147
|
+
// }
|
|
148
|
+
// gl.bindBuffer(gl.ARRAY_BUFFER, buffers[0].getBuffer());
|
|
149
|
+
// const mat4BaseLoc = programInfo.attributeLocations.instanceMatrix;
|
|
150
|
+
// const mat4Stride = 64;
|
|
151
|
+
// for (let i = 0; i < 4; i++) {
|
|
152
|
+
// const loc = mat4BaseLoc + i;
|
|
153
|
+
// const offset = i * 4 * FLOAT_SIZE;
|
|
154
|
+
// gl.enableVertexAttribArray(loc);
|
|
155
|
+
// gl.vertexAttribPointer(loc, 4, gl.FLOAT, false, mat4Stride, offset);
|
|
156
|
+
// gl.vertexAttribDivisor(loc, 1);
|
|
157
|
+
// }
|
|
158
|
+
// gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
159
|
+
}
|
|
160
|
+
const defaultWebGLVertexShader = `#version 300 es
|
|
161
|
+
|
|
162
|
+
// uniforms
|
|
163
|
+
uniform mat4 worldProjectionMatrix;
|
|
164
|
+
uniform mat4 modelProjectionMatrix;
|
|
165
|
+
|
|
166
|
+
// attributes
|
|
167
|
+
layout(location = 0) in vec3 position;
|
|
168
|
+
layout(location = 1) in vec4 color;
|
|
169
|
+
layout(location = 2) in vec2 uv;
|
|
170
|
+
layout(location = 3) in float drawingInstance;
|
|
171
|
+
|
|
172
|
+
// consumes locations 4, 5, 6, 7
|
|
173
|
+
//layout(location = 4) in mat4 instanceMatrix;
|
|
174
|
+
|
|
175
|
+
out vec2 vFragUV;
|
|
176
|
+
out vec4 vFragColor;
|
|
177
|
+
out vec4 vFragPosition;
|
|
178
|
+
|
|
179
|
+
void main() {
|
|
180
|
+
vec4 finalPosition;
|
|
181
|
+
vec4 posInput = vec4(position, 1.0);
|
|
182
|
+
|
|
183
|
+
if (drawingInstance == 1.0) {
|
|
184
|
+
//finalPosition = worldProjectionMatrix * modelProjectionMatrix * instanceMatrix * posInput;
|
|
185
|
+
finalPosition = worldProjectionMatrix * modelProjectionMatrix * posInput;
|
|
186
|
+
} else {
|
|
187
|
+
finalPosition = worldProjectionMatrix * modelProjectionMatrix * posInput;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
gl_Position = finalPosition;
|
|
191
|
+
|
|
192
|
+
vFragUV = uv;
|
|
193
|
+
vFragColor = color;
|
|
194
|
+
vFragPosition = finalPosition;
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
197
|
+
const defaultWebGLFragmentShader = `#version 300 es
|
|
198
|
+
precision mediump float;
|
|
199
|
+
|
|
200
|
+
in vec2 vFragUV;
|
|
201
|
+
in vec4 vFragColor;
|
|
202
|
+
in vec4 vFragPosition;
|
|
203
|
+
|
|
204
|
+
layout(location = 0) out vec4 outColor;
|
|
205
|
+
|
|
206
|
+
void main() {
|
|
207
|
+
outColor = vFragColor;
|
|
208
|
+
}
|
|
209
|
+
`;
|
|
210
|
+
const WEBGL_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE = mat4ByteLength * 2;
|
|
211
|
+
export const defaultWebGLShader = new SimJSWebGLShader(defaultWebGLVertexShader, defaultWebGLFragmentShader, [
|
|
212
|
+
// {
|
|
213
|
+
// target: WebGL2RenderingContext.ARRAY_BUFFER,
|
|
214
|
+
// usage: WebGL2RenderingContext.DYNAMIC_DRAW,
|
|
215
|
+
// defaultCapacity: 64
|
|
216
|
+
// }
|
|
217
|
+
], defaultWebGLUniformBufferWriter, defaultVertexBufferWriter, () => ({
|
|
218
|
+
attributeLocations: [
|
|
219
|
+
{ position: 3 },
|
|
220
|
+
{ color: 4 },
|
|
221
|
+
{ uv: 2 },
|
|
222
|
+
{ drawingInstance: 1 }
|
|
223
|
+
// instanceMatrix: 16
|
|
224
|
+
],
|
|
225
|
+
uniformLocations: [{ worldProjectionMatrix: 64 }, { modelProjectionMatrix: 64 }]
|
|
226
|
+
}));
|
|
227
|
+
export const defaultWebGLVertexColorShader = new SimJSWebGLShader(defaultWebGLVertexShader, defaultWebGLFragmentShader, [
|
|
228
|
+
// {
|
|
229
|
+
// target: WebGL2RenderingContext.ARRAY_BUFFER,
|
|
230
|
+
// usage: WebGL2RenderingContext.DYNAMIC_DRAW,
|
|
231
|
+
// defaultCapacity: 64
|
|
232
|
+
// }
|
|
233
|
+
], defaultWebGLUniformBufferWriter, defaultVertexColorBufferWriter, () => ({
|
|
234
|
+
attributeLocations: [
|
|
235
|
+
{ position: 3 },
|
|
236
|
+
{ color: 4 },
|
|
237
|
+
{ uv: 2 },
|
|
238
|
+
{ drawingInstance: 1 }
|
|
239
|
+
// instanceMatrix: 16
|
|
240
|
+
],
|
|
241
|
+
uniformLocations: [{ worldProjectionMatrix: 64 }, { modelProjectionMatrix: 64 }]
|
|
242
|
+
}));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
|
|
2
|
+
import { SimulationElement3d } from '../graphics.js';
|
|
3
|
+
import { WebGPUBufferDecleration, Vector3, VertexBufferWriter, VertexParamInfo } from '../types.js';
|
|
4
|
+
import { SimJSShader } from './shader.js';
|
|
5
|
+
export declare const WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE: number;
|
|
6
|
+
type WebGPUUniformBufferWriter = (device: GPUDevice, element: SimulationElement3d, buffers: WebGPUMemoBuffer[]) => void;
|
|
7
|
+
type WebGPUBindGroupGenerator = (device: GPUDevice, element: SimulationElement3d, buffers: WebGPUMemoBuffer[]) => GPUBindGroup[];
|
|
8
|
+
export declare class SimJSWebGPUShader extends SimJSShader {
|
|
9
|
+
protected buffers: WebGPUMemoBuffer[];
|
|
10
|
+
private bindGroupLayoutDescriptors;
|
|
11
|
+
private bindGroupLayouts;
|
|
12
|
+
private module;
|
|
13
|
+
private code;
|
|
14
|
+
private fragmentMain;
|
|
15
|
+
private vertexMain;
|
|
16
|
+
private vertexBuffers;
|
|
17
|
+
private uniformBufferWriter;
|
|
18
|
+
private bindGroupGenerator;
|
|
19
|
+
private bufferDeclerations;
|
|
20
|
+
private device;
|
|
21
|
+
constructor(code: string, descriptors: GPUBindGroupLayoutDescriptor[], vertexParams: VertexParamInfo[], bufferDeclerations: WebGPUBufferDecleration[], uniformBufferWriter: WebGPUUniformBufferWriter, bindGroupGenerator: WebGPUBindGroupGenerator, vertexBufferWriter: VertexBufferWriter, vertexMain?: string, fragmentMain?: string);
|
|
22
|
+
init(device: GPUDevice): void;
|
|
23
|
+
getCode(): string;
|
|
24
|
+
getVertexBuffers(): GPUVertexBufferLayout;
|
|
25
|
+
getBindGroupLayouts(): GPUBindGroupLayout[];
|
|
26
|
+
getBindGroupLayoutDescriptors(): GPUBindGroupLayoutDescriptor[];
|
|
27
|
+
getBufferInfo(): WebGPUBufferDecleration[];
|
|
28
|
+
getUniformBufferWriter(): WebGPUUniformBufferWriter;
|
|
29
|
+
getVertexBufferWriter(): VertexBufferWriter;
|
|
30
|
+
getBindGroupGenerator(): WebGPUBindGroupGenerator;
|
|
31
|
+
getModule(): GPUShaderModule;
|
|
32
|
+
getVertexMain(): string;
|
|
33
|
+
getFragmentMain(): string;
|
|
34
|
+
setVertexInfo(element: SimulationElement3d, buffer: Float32Array, vertex: Vector3, vertexIndex: number, offset: number): void;
|
|
35
|
+
writeUniformBuffers(el: SimulationElement3d): void;
|
|
36
|
+
getBindGroups(device: GPUDevice, el: SimulationElement3d): GPUBindGroup[];
|
|
37
|
+
}
|
|
38
|
+
export declare const defaultWebGPUShader: SimJSWebGPUShader;
|
|
39
|
+
export declare const defaultWebGPUVertexColorShader: SimJSWebGPUShader;
|
|
40
|
+
export {};
|
|
@@ -1,32 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mat4ByteLength } from '
|
|
3
|
-
import { globalInfo } from '
|
|
4
|
-
import { createBindGroup
|
|
5
|
-
|
|
1
|
+
import { WebGPUMemoBuffer } from '../buffers/webgpu.js';
|
|
2
|
+
import { mat4ByteLength, modelProjMatOffset } from '../constants.js';
|
|
3
|
+
import { globalInfo, logger } from '../globals.js';
|
|
4
|
+
import { createBindGroup } from '../utils.js';
|
|
5
|
+
import { orthogonalMatrix, worldProjectionMatrix } from '../simulation.js';
|
|
6
|
+
import { worldProjMatOffset } from '../constants.js';
|
|
7
|
+
import { defaultVertexColorBufferWriter, SimJSShader } from './shader.js';
|
|
8
|
+
export const WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE = mat4ByteLength * 2 + 4 * 2 + 8; // 4x4 matrix * 2 + vec2<f32> + 8 bc 144 is cool
|
|
6
9
|
const defaultInfos = [
|
|
7
10
|
{
|
|
8
|
-
usage: GPUBufferUsage.
|
|
9
|
-
owned: false
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
usage: GPUBufferUsage.STORAGE,
|
|
11
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
13
12
|
defaultSize: 10 * 4 * 16 // not sure where this came from, made it up a while ago
|
|
14
13
|
}
|
|
15
14
|
];
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const defaultWebGPUUniformBufferWriter = (device, el, buffers) => {
|
|
16
|
+
const projBuf = el.is3d ? worldProjectionMatrix : orthogonalMatrix;
|
|
17
|
+
let buffer = el.getUniformBuffer();
|
|
18
|
+
if (!buffer) {
|
|
19
|
+
buffer = new WebGPUMemoBuffer(device, GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, WEBGPU_DEFAULT_SHADER_UNIFORM_BUFFER_SIZE);
|
|
20
|
+
el.setUniformBuffer(buffer);
|
|
21
|
+
}
|
|
22
|
+
device.queue.writeBuffer(buffer.getBuffer(), worldProjMatOffset, projBuf.buffer, projBuf.byteOffset, projBuf.byteLength);
|
|
23
|
+
const modelMatrix = el.getModelMatrix();
|
|
24
|
+
device.queue.writeBuffer(buffer.getBuffer(), modelProjMatOffset, modelMatrix.buffer, modelMatrix.byteOffset, modelMatrix.byteLength);
|
|
25
|
+
if (el.isInstance) {
|
|
26
|
+
buffers[0].write(el.getInstanceBuffer());
|
|
27
|
+
}
|
|
20
28
|
};
|
|
21
|
-
const defaultBindGroupGenerator = (el, buffers) => {
|
|
29
|
+
const defaultBindGroupGenerator = (_device, el, buffers) => {
|
|
30
|
+
// TODO - why is this here?
|
|
22
31
|
const shader = el.getShader();
|
|
32
|
+
if (!shader.compatableWith('webgpu'))
|
|
33
|
+
throw logger.error('Wrong shader type for backend or something idk');
|
|
23
34
|
const gpuBuffers = [
|
|
24
|
-
el.getUniformBuffer(),
|
|
25
|
-
|
|
35
|
+
el.getUniformBuffer().getBuffer(),
|
|
36
|
+
buffers[0].getBuffer()
|
|
26
37
|
];
|
|
27
38
|
return [createBindGroup(shader, 0, gpuBuffers)];
|
|
28
39
|
};
|
|
29
|
-
export class
|
|
40
|
+
export class SimJSWebGPUShader extends SimJSShader {
|
|
41
|
+
buffers;
|
|
30
42
|
bindGroupLayoutDescriptors;
|
|
31
43
|
bindGroupLayouts;
|
|
32
44
|
module;
|
|
@@ -34,29 +46,23 @@ export class Shader {
|
|
|
34
46
|
fragmentMain;
|
|
35
47
|
vertexMain;
|
|
36
48
|
vertexBuffers;
|
|
37
|
-
|
|
38
|
-
bufferWriter;
|
|
39
|
-
vertexBufferWriter;
|
|
49
|
+
uniformBufferWriter;
|
|
40
50
|
bindGroupGenerator;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
constructor(code, descriptors, vertexParams,
|
|
51
|
+
bufferDeclerations;
|
|
52
|
+
device;
|
|
53
|
+
constructor(code, descriptors, vertexParams, bufferDeclerations, uniformBufferWriter, bindGroupGenerator, vertexBufferWriter, vertexMain = 'vertex_main', fragmentMain = 'fragment_main') {
|
|
54
|
+
super('webgpu', vertexBufferWriter);
|
|
55
|
+
this.buffers = [];
|
|
56
|
+
this.device = null;
|
|
44
57
|
this.code = code;
|
|
45
58
|
this.bindGroupLayoutDescriptors = descriptors;
|
|
46
59
|
this.bindGroupLayouts = null;
|
|
47
60
|
this.module = null;
|
|
48
|
-
this.
|
|
49
|
-
this.vertexBufferWriter = vertexBufferWriter;
|
|
61
|
+
this.uniformBufferWriter = uniformBufferWriter;
|
|
50
62
|
this.bindGroupGenerator = bindGroupGenerator;
|
|
51
63
|
this.vertexMain = vertexMain;
|
|
52
64
|
this.fragmentMain = fragmentMain;
|
|
53
|
-
this.
|
|
54
|
-
this.buffers = [];
|
|
55
|
-
for (let i = 0; i < bufferInfos.length; i++) {
|
|
56
|
-
if (bufferInfos[i].owned === false)
|
|
57
|
-
continue;
|
|
58
|
-
this.buffers.push(new MemoBuffer(bufferInfos[i].usage, bufferInfos[i].defaultSize ?? 0));
|
|
59
|
-
}
|
|
65
|
+
this.bufferDeclerations = bufferDeclerations;
|
|
60
66
|
let stride = 0;
|
|
61
67
|
const attributes = [];
|
|
62
68
|
for (let i = 0; i < vertexParams.length; i++) {
|
|
@@ -72,18 +78,30 @@ export class Shader {
|
|
|
72
78
|
arrayStride: stride,
|
|
73
79
|
attributes
|
|
74
80
|
};
|
|
81
|
+
const canvas = globalInfo.getCanvas();
|
|
82
|
+
if (!canvas) {
|
|
83
|
+
globalInfo.addToInitShader(this);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const backend = canvas.getBackend().as('webgpu');
|
|
87
|
+
this.init(backend.getDeviceOrError());
|
|
88
|
+
}
|
|
89
|
+
init(device) {
|
|
90
|
+
this.device = device;
|
|
91
|
+
for (let i = 0; i < this.bufferDeclerations.length; i++) {
|
|
92
|
+
this.buffers.push(new WebGPUMemoBuffer(device, this.bufferDeclerations[i].usage, this.bufferDeclerations[i].defaultSize ?? 0));
|
|
93
|
+
}
|
|
75
94
|
}
|
|
76
95
|
getCode() {
|
|
77
96
|
return this.code;
|
|
78
97
|
}
|
|
79
|
-
getBufferLength() {
|
|
80
|
-
return this.bufferLength;
|
|
81
|
-
}
|
|
82
98
|
getVertexBuffers() {
|
|
83
99
|
return this.vertexBuffers;
|
|
84
100
|
}
|
|
85
101
|
getBindGroupLayouts() {
|
|
86
|
-
|
|
102
|
+
// TODO - probably change
|
|
103
|
+
const backend = globalInfo.errorGetCanvas().getBackend();
|
|
104
|
+
const device = backend.getDeviceOrError();
|
|
87
105
|
if (!this.bindGroupLayouts) {
|
|
88
106
|
this.bindGroupLayouts = this.bindGroupLayoutDescriptors.map((descriptor) => device.createBindGroupLayout(descriptor));
|
|
89
107
|
}
|
|
@@ -93,10 +111,10 @@ export class Shader {
|
|
|
93
111
|
return this.bindGroupLayoutDescriptors;
|
|
94
112
|
}
|
|
95
113
|
getBufferInfo() {
|
|
96
|
-
return this.
|
|
114
|
+
return this.bufferDeclerations;
|
|
97
115
|
}
|
|
98
|
-
|
|
99
|
-
return this.
|
|
116
|
+
getUniformBufferWriter() {
|
|
117
|
+
return this.uniformBufferWriter;
|
|
100
118
|
}
|
|
101
119
|
getVertexBufferWriter() {
|
|
102
120
|
return this.vertexBufferWriter;
|
|
@@ -105,7 +123,9 @@ export class Shader {
|
|
|
105
123
|
return this.bindGroupGenerator;
|
|
106
124
|
}
|
|
107
125
|
getModule() {
|
|
108
|
-
|
|
126
|
+
// TODO - probably change
|
|
127
|
+
const backend = globalInfo.errorGetCanvas().getBackend();
|
|
128
|
+
const device = backend.getDeviceOrError();
|
|
109
129
|
if (!this.module) {
|
|
110
130
|
this.module = device.createShaderModule({ code: this.code });
|
|
111
131
|
}
|
|
@@ -120,19 +140,20 @@ export class Shader {
|
|
|
120
140
|
setVertexInfo(element, buffer, vertex, vertexIndex, offset) {
|
|
121
141
|
this.vertexBufferWriter(element, buffer, vertex, vertexIndex, offset);
|
|
122
142
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
writeUniformBuffers(el) {
|
|
144
|
+
if (!this.device)
|
|
145
|
+
throw logger.error('Shader not initialized');
|
|
146
|
+
this.uniformBufferWriter(this.device, el, this.buffers);
|
|
126
147
|
}
|
|
127
|
-
getBindGroups(el) {
|
|
128
|
-
return this.bindGroupGenerator(el, this.buffers);
|
|
148
|
+
getBindGroups(device, el) {
|
|
149
|
+
return this.bindGroupGenerator(device, el, this.buffers);
|
|
129
150
|
}
|
|
130
151
|
}
|
|
131
152
|
const positionSize = 4 * 3;
|
|
132
153
|
const colorSize = 4 * 4;
|
|
133
154
|
const uvSize = 4 * 2;
|
|
134
155
|
const drawingInstancesSize = 4;
|
|
135
|
-
|
|
156
|
+
const defaultWebGPUShaderSource = `struct Uniforms {
|
|
136
157
|
worldProjectionMatrix: mat4x4<f32>,
|
|
137
158
|
modelProjectionMatrix: mat4x4<f32>,
|
|
138
159
|
}
|
|
@@ -178,7 +199,8 @@ fn fragment_main(
|
|
|
178
199
|
) -> @location(0) vec4<f32> {
|
|
179
200
|
return fragColor;
|
|
180
201
|
}
|
|
181
|
-
|
|
202
|
+
`;
|
|
203
|
+
export const defaultWebGPUShader = new SimJSWebGPUShader(defaultWebGPUShaderSource, [
|
|
182
204
|
{
|
|
183
205
|
entries: [
|
|
184
206
|
{
|
|
@@ -214,7 +236,7 @@ fn fragment_main(
|
|
|
214
236
|
size: drawingInstancesSize,
|
|
215
237
|
format: 'float32'
|
|
216
238
|
}
|
|
217
|
-
], defaultInfos,
|
|
239
|
+
], defaultInfos, defaultWebGPUUniformBufferWriter, defaultBindGroupGenerator, (el, buffer, vertex, _, offset) => {
|
|
218
240
|
const material = el.getMaterial();
|
|
219
241
|
const vertexColor = material.getColor();
|
|
220
242
|
buffer[offset] = vertex[0];
|
|
@@ -229,54 +251,7 @@ fn fragment_main(
|
|
|
229
251
|
buffer[offset + 8] = 0;
|
|
230
252
|
buffer[offset + 9] = el.isInstanced ? 1 : 0;
|
|
231
253
|
});
|
|
232
|
-
export const
|
|
233
|
-
struct Uniforms {
|
|
234
|
-
worldProjectionMatrix: mat4x4<f32>,
|
|
235
|
-
modelProjectionMatrix: mat4x4<f32>,
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
239
|
-
|
|
240
|
-
@group(0) @binding(1) var<storage> instanceMatrices: array<mat4x4f>;
|
|
241
|
-
|
|
242
|
-
struct VertexOutput {
|
|
243
|
-
@builtin(position) Position: vec4<f32>,
|
|
244
|
-
@location(0) fragUV: vec2<f32>,
|
|
245
|
-
@location(1) fragColor: vec4<f32>,
|
|
246
|
-
@location(2) fragPosition: vec4<f32>,
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
@vertex
|
|
250
|
-
fn vertex_main(
|
|
251
|
-
@builtin(instance_index) instanceIdx: u32,
|
|
252
|
-
@location(0) position: vec3<f32>,
|
|
253
|
-
@location(1) color: vec4<f32>,
|
|
254
|
-
@location(2) uv: vec2<f32>,
|
|
255
|
-
@location(3) drawingInstance: f32
|
|
256
|
-
) -> VertexOutput {
|
|
257
|
-
var output: VertexOutput;
|
|
258
|
-
|
|
259
|
-
if (drawingInstance == 1) {
|
|
260
|
-
output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * instanceMatrices[instanceIdx] * vec4(position, 1.0);
|
|
261
|
-
} else {
|
|
262
|
-
output.Position = uniforms.worldProjectionMatrix * uniforms.modelProjectionMatrix * vec4(position, 1.0);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
output.fragUV = uv;
|
|
266
|
-
output.fragPosition = output.Position;
|
|
267
|
-
output.fragColor = color;
|
|
268
|
-
return output;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
@fragment
|
|
272
|
-
fn fragment_main(
|
|
273
|
-
@location(0) fragUV: vec2<f32>,
|
|
274
|
-
@location(1) fragColor: vec4<f32>,
|
|
275
|
-
@location(2) fragPosition: vec4<f32>
|
|
276
|
-
) -> @location(0) vec4<f32> {
|
|
277
|
-
return fragColor;
|
|
278
|
-
}
|
|
279
|
-
`, [
|
|
254
|
+
export const defaultWebGPUVertexColorShader = new SimJSWebGPUShader(defaultWebGPUShaderSource, [
|
|
280
255
|
{
|
|
281
256
|
entries: [
|
|
282
257
|
{
|
|
@@ -312,20 +287,4 @@ fn fragment_main(
|
|
|
312
287
|
size: drawingInstancesSize,
|
|
313
288
|
format: 'float32'
|
|
314
289
|
}
|
|
315
|
-
], defaultInfos,
|
|
316
|
-
const material = el.getMaterial();
|
|
317
|
-
const colors = material.getVertexColors();
|
|
318
|
-
const vertexColor = colors[vertexIndex] ?? el.getColor();
|
|
319
|
-
// const vertexColor = color(0, 255, 255);
|
|
320
|
-
buffer[offset] = vertex[0];
|
|
321
|
-
buffer[offset + 1] = vertex[1];
|
|
322
|
-
buffer[offset + 2] = vertex[2];
|
|
323
|
-
buffer[offset + 3] = vertexColor.r / 255;
|
|
324
|
-
buffer[offset + 4] = vertexColor.g / 255;
|
|
325
|
-
buffer[offset + 5] = vertexColor.b / 255;
|
|
326
|
-
buffer[offset + 6] = vertexColor.a;
|
|
327
|
-
// TODO possibly change uv for textures
|
|
328
|
-
buffer[offset + 7] = 0;
|
|
329
|
-
buffer[offset + 8] = 0;
|
|
330
|
-
buffer[offset + 9] = el.isInstanced ? 1 : 0;
|
|
331
|
-
});
|
|
290
|
+
], defaultInfos, defaultWebGPUUniformBufferWriter, defaultBindGroupGenerator, defaultVertexColorBufferWriter);
|
package/dist/simulation.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SimulationElement3d } from './graphics.js';
|
|
2
|
-
import type { Vector2, Vector3, LerpFunc } from './types.js';
|
|
2
|
+
import type { Vector2, Vector3, LerpFunc, BackendType } from './types.js';
|
|
3
3
|
import { Color } from './utils.js';
|
|
4
4
|
import { Settings } from './settings.js';
|
|
5
|
+
import { SimJsBackend } from './backends/backend.js';
|
|
5
6
|
export declare const worldProjectionMatrix: import("./types.js").Mat4;
|
|
6
7
|
export declare const orthogonalMatrix: import("./types.js").Mat4;
|
|
7
8
|
export declare class Camera {
|
|
@@ -24,9 +25,13 @@ export declare class Camera {
|
|
|
24
25
|
getAspectRatio(): number;
|
|
25
26
|
}
|
|
26
27
|
export declare let camera: Camera;
|
|
28
|
+
type SimulationOptions = {
|
|
29
|
+
sceneCamera?: Camera | null;
|
|
30
|
+
showFrameRate?: boolean;
|
|
31
|
+
backendMode?: BackendType;
|
|
32
|
+
};
|
|
27
33
|
export declare class Simulation extends Settings {
|
|
28
34
|
canvasRef: HTMLCanvasElement | null;
|
|
29
|
-
private bgColor;
|
|
30
35
|
private scene;
|
|
31
36
|
private fittingElement;
|
|
32
37
|
private running;
|
|
@@ -34,12 +39,12 @@ export declare class Simulation extends Settings {
|
|
|
34
39
|
private resizeEvents;
|
|
35
40
|
private frameRateView;
|
|
36
41
|
private transparentElements;
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
constructor(idOrCanvasRef: string | HTMLCanvasElement, sceneCamera?: Camera | null, showFrameRate?: boolean);
|
|
42
|
+
private backend;
|
|
43
|
+
constructor(idOrCanvasRef: string | HTMLCanvasElement, options?: SimulationOptions);
|
|
40
44
|
private handleCanvasResize;
|
|
41
45
|
on<K extends keyof HTMLElementEventMap>(event: K, cb: (this: HTMLCanvasElement, ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
|
|
42
46
|
onResize(cb: (width: number, height: number) => void): void;
|
|
47
|
+
getBackend(): SimJsBackend;
|
|
43
48
|
getWidth(): number;
|
|
44
49
|
getHeight(): number;
|
|
45
50
|
add(el: SimulationElement3d, id?: string): void;
|
|
@@ -58,3 +63,4 @@ export declare class Simulation extends Settings {
|
|
|
58
63
|
private renderScene;
|
|
59
64
|
fitElement(): void;
|
|
60
65
|
}
|
|
66
|
+
export {};
|