matrix-engine-wgpu 1.3.18 → 1.4.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/examples/load-obj-file.js +4 -8
- package/package.json +1 -1
- package/public/examples.js +140 -205
- package/readme.md +1 -1
- package/src/engine/lights.js +23 -36
- package/src/engine/materials.js +5 -6
- package/src/engine/mesh-obj.js +6 -26
- package/src/physics/matrix-ammo.js +0 -42
- package/src/shaders/fragment.wgsl.js +77 -45
- package/src/world.js +42 -72
package/src/world.js
CHANGED
|
@@ -5,13 +5,22 @@ import {ArcballCamera, WASDCamera} from "./engine/engine.js";
|
|
|
5
5
|
import {createInputHandler} from "./engine/engine.js";
|
|
6
6
|
import MEMeshObj from "./engine/mesh-obj.js";
|
|
7
7
|
import MatrixAmmo from "./physics/matrix-ammo.js";
|
|
8
|
-
import {LOG_WARN, genName, mb, scriptManager, urlQuery} from "./engine/utils.js";
|
|
8
|
+
import {LOG_FUNNY_SMALL, LOG_WARN, genName, mb, scriptManager, urlQuery} from "./engine/utils.js";
|
|
9
9
|
import {MultiLang} from "./multilang/lang.js";
|
|
10
10
|
import {MatrixSounds} from "./sounds/sounds.js";
|
|
11
11
|
import {play} from "./engine/loader-obj.js";
|
|
12
12
|
import {SpotLight} from "./engine/lights.js";
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @description
|
|
16
|
+
* Main engine root class.
|
|
17
|
+
* @author Nikola Lukic 2025
|
|
18
|
+
* @email zlatnaspirala@gmail.com
|
|
19
|
+
* @web https://maximumroulette.com
|
|
20
|
+
* @github zlatnaspirala
|
|
21
|
+
*/
|
|
14
22
|
export default class MatrixEngineWGPU {
|
|
23
|
+
lightContainer
|
|
15
24
|
|
|
16
25
|
mainRenderBundle = [];
|
|
17
26
|
lightContainer = [];
|
|
@@ -29,9 +38,7 @@ export default class MatrixEngineWGPU {
|
|
|
29
38
|
matrixAmmo = new MatrixAmmo();
|
|
30
39
|
matrixSounds = new MatrixSounds();
|
|
31
40
|
|
|
32
|
-
// The input handler
|
|
33
41
|
constructor(options, callback) {
|
|
34
|
-
// console.log('typeof options ', typeof options )
|
|
35
42
|
if(typeof options == 'undefined' || typeof options == "function") {
|
|
36
43
|
this.options = {
|
|
37
44
|
useSingleRenderPass: true,
|
|
@@ -95,7 +102,6 @@ export default class MatrixEngineWGPU {
|
|
|
95
102
|
this.label.get = r;
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
|
-
|
|
99
105
|
this.init({canvas, callback})
|
|
100
106
|
}
|
|
101
107
|
|
|
@@ -106,15 +112,7 @@ export default class MatrixEngineWGPU {
|
|
|
106
112
|
extensions: ["ray_tracing"]
|
|
107
113
|
});
|
|
108
114
|
|
|
109
|
-
// Maybe works in ssl with webworkers...
|
|
110
|
-
// const adapterInfo = await this.adapter.requestAdapterInfo();
|
|
111
|
-
// var test = this.adapter.features()
|
|
112
|
-
// console.log(adapterInfo.vendor);
|
|
113
|
-
// console.log('test' + test);
|
|
114
|
-
// console.log("FEATURES : " + this.adapter.features)
|
|
115
|
-
|
|
116
115
|
this.context = canvas.getContext('webgpu');
|
|
117
|
-
|
|
118
116
|
const devicePixelRatio = window.devicePixelRatio;
|
|
119
117
|
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
120
118
|
canvas.height = canvas.clientHeight * devicePixelRatio;
|
|
@@ -132,21 +130,20 @@ export default class MatrixEngineWGPU {
|
|
|
132
130
|
this.frame = this.framePassPerObject;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
|
|
136
|
-
// this.sceneUniformBuffer = this.device.createBuffer({
|
|
137
|
-
// // Two 4x4 viewProj matrices,
|
|
138
|
-
// // one for the camera and one for the light.
|
|
139
|
-
// // Then a vec3 for the light position.
|
|
140
|
-
// // Rounded to the nearest multiple of 16.
|
|
141
|
-
// size: 2 * 4 * 16 + 4 * 4,
|
|
142
|
-
// usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
143
|
-
// });
|
|
144
|
-
|
|
133
|
+
this.MAX_SPOTLIGHTS = 20;
|
|
145
134
|
this.inputHandler = createInputHandler(window, canvas);
|
|
146
|
-
|
|
135
|
+
this.createGlobalStuff();
|
|
147
136
|
this.run(callback)
|
|
148
137
|
};
|
|
149
138
|
|
|
139
|
+
createGlobalStuff() {
|
|
140
|
+
this.spotlightUniformBuffer = this.device.createBuffer({
|
|
141
|
+
label: 'spotlightUniformBufferGLOBAL',
|
|
142
|
+
size: this.MAX_SPOTLIGHTS * 80,
|
|
143
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
150
147
|
getSceneObjectByName(name) {
|
|
151
148
|
return this.mainRenderBundle.find((sceneObject) => sceneObject.name === name)
|
|
152
149
|
}
|
|
@@ -252,12 +249,11 @@ export default class MatrixEngineWGPU {
|
|
|
252
249
|
}
|
|
253
250
|
|
|
254
251
|
addLight(o) {
|
|
255
|
-
// test light global; entity
|
|
256
252
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
257
253
|
let newLight = new SpotLight(camera, this.inputHandler);
|
|
258
254
|
newLight.prepareBuffer(this.device);
|
|
259
255
|
this.lightContainer.push(newLight);
|
|
260
|
-
console.log(
|
|
256
|
+
console.log(`%cAdd light: ${newLight}`, LOG_FUNNY_SMALL);
|
|
261
257
|
}
|
|
262
258
|
|
|
263
259
|
addMeshObj = (o, clearColor = this.options.clearColor) => {
|
|
@@ -289,18 +285,14 @@ export default class MatrixEngineWGPU {
|
|
|
289
285
|
if(typeof o.physics.scale === 'undefined') {o.physics.scale = o.scale;}
|
|
290
286
|
if(typeof o.physics.rotation === 'undefined') {o.physics.rotation = o.rotation;}
|
|
291
287
|
o.physics.position = o.position;
|
|
292
|
-
// console.log('Mesh procedure', o)
|
|
293
|
-
// TEST OBJS SEQ ANIMS
|
|
294
288
|
if(typeof o.objAnim == 'undefined' || typeof o.objAnim == null) {
|
|
295
289
|
o.objAnim = null;
|
|
296
290
|
} else {
|
|
297
|
-
// console.log('o.anim', o.objAnim)
|
|
298
291
|
if(typeof o.objAnim.animations !== 'undefined') {
|
|
299
292
|
o.objAnim.play = play;
|
|
300
293
|
}
|
|
301
294
|
// no need for single test it in future
|
|
302
295
|
o.objAnim.meshList = o.objAnim.meshList;
|
|
303
|
-
|
|
304
296
|
if(typeof o.mesh === 'undefined') {
|
|
305
297
|
o.mesh = o.objAnim.meshList[0];
|
|
306
298
|
console.info('objSeq animation is active.');
|
|
@@ -314,7 +306,7 @@ export default class MatrixEngineWGPU {
|
|
|
314
306
|
}
|
|
315
307
|
}
|
|
316
308
|
let myMesh1 = new MEMeshObj(this.canvas, this.device, this.context, o);
|
|
317
|
-
myMesh1.
|
|
309
|
+
myMesh1.spotlightUniformBuffer = this.spotlightUniformBuffer;
|
|
318
310
|
myMesh1.inputHandler = this.inputHandler;
|
|
319
311
|
myMesh1.clearColor = clearColor;
|
|
320
312
|
if(o.physics.enabled == true) {
|
|
@@ -340,9 +332,6 @@ export default class MatrixEngineWGPU {
|
|
|
340
332
|
if(!this.lastFrameMS) {dt = 16;}
|
|
341
333
|
this.lastFrameMS = now;
|
|
342
334
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
343
|
-
|
|
344
|
-
// engine, once per frame
|
|
345
|
-
// const camera = this.cameras[this.mainCameraParams.type];
|
|
346
335
|
camera.update(dt, this.inputHandler());
|
|
347
336
|
const camVP = mat4.multiply(camera.projectionMatrix, camera.view); // P * V
|
|
348
337
|
|
|
@@ -356,27 +345,19 @@ export default class MatrixEngineWGPU {
|
|
|
356
345
|
camVP.byteLength
|
|
357
346
|
);
|
|
358
347
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// this.device.queue.writeBuffer(
|
|
373
|
-
// mesh.sceneUniformBuffer, // or a shared one if/when you centralize it
|
|
374
|
-
// 0,
|
|
375
|
-
// sceneData.buffer,
|
|
376
|
-
// sceneData.byteOffset,
|
|
377
|
-
// sceneData.byteLength
|
|
378
|
-
// );
|
|
379
|
-
// }
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
updateLights() {
|
|
351
|
+
// Update buffer every frame
|
|
352
|
+
const data = new Float32Array(this.MAX_SPOTLIGHTS * 20);
|
|
353
|
+
for(let i = 0;i < this.MAX_SPOTLIGHTS;i++) {
|
|
354
|
+
if(i < this.lightContainer.length) {
|
|
355
|
+
data.set(this.lightContainer[i].getLightDataBuffer(), i * 20);
|
|
356
|
+
} else {
|
|
357
|
+
data.set(new Float32Array(20), i * 20);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, data.buffer);
|
|
380
361
|
}
|
|
381
362
|
|
|
382
363
|
frameSinglePass = () => {
|
|
@@ -389,35 +370,24 @@ export default class MatrixEngineWGPU {
|
|
|
389
370
|
let renderPass;
|
|
390
371
|
let commandEncoder = this.device.createCommandEncoder();
|
|
391
372
|
|
|
373
|
+
this.updateLights()
|
|
392
374
|
this.test()
|
|
375
|
+
|
|
393
376
|
// 1️⃣ Update light data (position, direction, uniforms)
|
|
394
377
|
for(const light of this.lightContainer) {
|
|
395
|
-
light.updateLightBuffer();
|
|
396
378
|
this.mainRenderBundle.forEach((meItem, index) => {
|
|
379
|
+
|
|
397
380
|
light.updateSceneUniforms(this.mainRenderBundle, this.cameras.WASD);
|
|
398
381
|
})
|
|
399
382
|
}
|
|
400
383
|
|
|
401
384
|
this.mainRenderBundle.forEach((meItem, index) => {meItem.position.update()})
|
|
402
385
|
if(this.matrixAmmo) this.matrixAmmo.updatePhysics();
|
|
403
|
-
|
|
404
|
-
// no cast WORKING
|
|
405
|
-
// this.mainRenderBundle.forEach((meItem, index) => {
|
|
406
|
-
// meItem.draw(commandEncoder);
|
|
407
|
-
|
|
408
|
-
// shadowPass = commandEncoder.beginRenderPass(meItem.shadowPassDescriptor);
|
|
409
|
-
// shadowPass.setPipeline(meItem.shadowPipeline);
|
|
410
|
-
// meItem.drawShadows(shadowPass);
|
|
411
|
-
// shadowPass.end();
|
|
412
|
-
// })
|
|
413
|
-
|
|
414
|
-
// cast!
|
|
415
386
|
const firstItem = this.mainRenderBundle[0];
|
|
416
387
|
shadowPass = commandEncoder.beginRenderPass(firstItem.shadowPassDescriptor);
|
|
417
388
|
shadowPass.setPipeline(firstItem.shadowPipeline);
|
|
418
389
|
for(const meItem of this.mainRenderBundle) {
|
|
419
|
-
|
|
420
|
-
meItem.drawShadows(shadowPass); // Draw ALL objects
|
|
390
|
+
meItem.drawShadows(shadowPass);
|
|
421
391
|
}
|
|
422
392
|
shadowPass.end();
|
|
423
393
|
|
|
@@ -441,7 +411,7 @@ export default class MatrixEngineWGPU {
|
|
|
441
411
|
this.device.queue.submit([commandEncoder.finish()]);
|
|
442
412
|
requestAnimationFrame(this.frame);
|
|
443
413
|
} catch(err) {
|
|
444
|
-
console.log('%
|
|
414
|
+
console.log('%cLoop (err):' + err, LOG_WARN)
|
|
445
415
|
requestAnimationFrame(this.frame);
|
|
446
416
|
}
|
|
447
417
|
}
|
|
@@ -456,7 +426,7 @@ export default class MatrixEngineWGPU {
|
|
|
456
426
|
if(meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'load';
|
|
457
427
|
}
|
|
458
428
|
// Update transforms, physics, etc. (optional)
|
|
459
|
-
meItem.draw(commandEncoder);
|
|
429
|
+
meItem.draw(commandEncoder);
|
|
460
430
|
if(meItem.renderBundle) {
|
|
461
431
|
// Set up view per object
|
|
462
432
|
meItem.renderPassDescriptor.colorAttachments[0].view =
|
|
@@ -465,7 +435,7 @@ export default class MatrixEngineWGPU {
|
|
|
465
435
|
passEncoder.executeBundles([meItem.renderBundle]); // ✅ Use only this bundle
|
|
466
436
|
passEncoder.end();
|
|
467
437
|
} else {
|
|
468
|
-
meItem.draw(commandEncoder);
|
|
438
|
+
meItem.draw(commandEncoder);
|
|
469
439
|
}
|
|
470
440
|
});
|
|
471
441
|
this.device.queue.submit([commandEncoder.finish()]);
|