matrix-engine-wgpu 1.2.14 → 1.3.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "matrix-engine-wgpu",
3
- "version": "1.2.14",
4
- "description": "+HOTFIX raycast, webGPU powered pwa application. Crazy fast rendering with AmmoJS physics support. Simple raycaster hit object added.",
3
+ "version": "1.3.0",
4
+ "description": "obj sequence anim +HOTFIX raycast, webGPU powered pwa application. Crazy fast rendering with AmmoJS physics support. Simple raycaster hit object added.",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "./src"
@@ -18,6 +18,8 @@
18
18
  "keywords": [
19
19
  "3dScene",
20
20
  "webGPU",
21
+ "webgpu-obj-sequence",
22
+ "obj-sequence-animation",
21
23
  "webGPU-hit-detect",
22
24
  "webGPU-raycaster",
23
25
  "webGPU-click-on-object",
package/readme.md CHANGED
@@ -234,6 +234,77 @@ window.app = application;
234
234
  ```
235
235
 
236
236
 
237
+ ## 🔁 Load OBJ Sequence Animation
238
+
239
+ This example shows how to load and animate a sequence of .obj files to simulate mesh-based animation (e.g. walking character).
240
+
241
+ js
242
+ Copy
243
+ Edit
244
+ import MatrixEngineWGPU from "../src/world.js";
245
+ import { downloadMeshes, makeObjSeqArg } from "../src/engine/loader-obj.js";
246
+ import { LOG_MATRIX } from "../src/engine/utils.js";
247
+
248
+ export var loadObjsSequence = function () {
249
+ let loadObjFile = new MatrixEngineWGPU({
250
+ useSingleRenderPass: true,
251
+ canvasSize: "fullscreen",
252
+ mainCameraParams: {
253
+ type: "WASD",
254
+ responseCoef: 1000,
255
+ },
256
+ }, () => {
257
+
258
+ addEventListener("AmmoReady", () => {
259
+ downloadMeshes(
260
+ makeObjSeqArg({
261
+ id: "swat-walk-pistol",
262
+ path: "res/meshes/objs-sequence/swat-walk-pistol",
263
+ from: 1,
264
+ to: 20,
265
+ }),
266
+ onLoadObj,
267
+ { scale: [10, 10, 10] }
268
+ );
269
+ });
270
+
271
+ function onLoadObj(m) {
272
+ console.log(`%c Loaded objs: ${m} `, LOG_MATRIX);
273
+ var objAnim = {
274
+ id: "swat-walk-pistol",
275
+ meshList: m,
276
+ currentAni: 1,
277
+ animations: {
278
+ active: "walk",
279
+ walk: { from: 1, to: 20, speed: 3 },
280
+ walkPistol: { from: 36, to: 60, speed: 3 },
281
+ },
282
+ };
283
+
284
+ loadObjFile.addMeshObj({
285
+ position: { x: 0, y: 2, z: -10 },
286
+ rotation: { x: 0, y: 0, z: 0 },
287
+ rotationSpeed: { x: 0, y: 0, z: 0 },
288
+ scale: [100, 100, 100],
289
+ texturesPaths: ["./res/meshes/blender/cube.png"],
290
+ name: "swat",
291
+ mesh: m["swat-walk-pistol"],
292
+ physics: {
293
+ enabled: false,
294
+ geometry: "Cube",
295
+ },
296
+ objAnim: objAnim,
297
+ });
298
+
299
+ app.mainRenderBundle[0].objAnim.play("walk");
300
+ }
301
+ });
302
+
303
+ window.app = loadObjFile;
304
+ };
305
+
306
+ ### 📽️ Preview
307
+
237
308
  ## @Note
238
309
  If this happen less then 15 times (Loading procces) then it is ok probably...
239
310
  ```warn
@@ -278,6 +349,7 @@ Uses `watchify` to bundle JavaScript.
278
349
  ## Resources
279
350
 
280
351
  All resources and output go into the `./public` folder — everything you need in one place.
352
+ This is static file storage.
281
353
 
282
354
  ---
283
355
 
@@ -464,7 +464,7 @@ export default class MEBall {
464
464
 
465
465
  draw = () => {
466
466
  if(this.moonTexture == null) {
467
- console.log('not ready')
467
+ // console.log('not ready')
468
468
  return;
469
469
  }
470
470
  const transformationMatrix = this.getTransformationMatrix(this.position);
@@ -478,7 +478,7 @@ export default class MECube {
478
478
 
479
479
  draw = () => {
480
480
  if(this.moonTexture == null) {
481
- console.log('not ready')
481
+ // console.log('not ready')
482
482
  return;
483
483
  }
484
484
  const transformationMatrix = this.getTransformationMatrix(this.position);
@@ -467,6 +467,7 @@ export const makeObjSeqArg = (arg) => {
467
467
  * Switching obj seq animations frames range.
468
468
  */
469
469
  export function play (nameAni) {
470
- this.animation.anims.active = nameAni;
471
- this.animation.currentAni = this.animation.anims[this.animation.anims.active].from;
470
+ this.animations.active = nameAni;
471
+ this.currentAni = this.animations[this.animations.active].from;
472
+ this.playing = true;
472
473
  }
@@ -30,6 +30,14 @@ export default class MEMeshObj {
30
30
  this.mesh.uvs = this.mesh.textures;
31
31
  console.log(`%c Mesh loaded: ${o.name}`, LOG_FUNNY_SMALL);
32
32
 
33
+ // TEST OBJ SEQ ANIM
34
+ //
35
+ if(typeof o.objAnim !== 'undefined' && o.objAnim != null) {
36
+ this.objAnim = o.objAnim;
37
+ console.log(`%c Mesh objAnim exist: ${o.objAnim}`, LOG_FUNNY_SMALL);
38
+ this.drawElements = this.drawElementsAnim;
39
+ }
40
+
33
41
  this.inputHandler = createInputHandler(window, canvas);
34
42
  this.cameras = o.cameras;
35
43
 
@@ -61,7 +69,7 @@ export default class MEMeshObj {
61
69
  this.modelViewProjectionMatrix = mat4.create();
62
70
  // console.log('cube added texturesPaths: ', this.texturesPaths)
63
71
  this.loadTex0(this.texturesPaths, device).then(() => {
64
- // console.log('loaded tex buffer for mesh:', this.texture0)
72
+ console.log('loaded tex buffer for mesh:', this.texture0)
65
73
  resolve()
66
74
  })
67
75
  })
@@ -117,19 +125,18 @@ export default class MEMeshObj {
117
125
 
118
126
  // Create the model index buffer.
119
127
  this.indexCount = this.mesh.indices.length;
128
+ const indexCount = this.mesh.indices.length;
129
+ const size = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
130
+
120
131
  this.indexBuffer = this.device.createBuffer({
121
- size: this.indexCount * Uint16Array.BYTES_PER_ELEMENT,
122
- usage: GPUBufferUsage.INDEX,
123
- mappedAtCreation: true,
132
+ size,
133
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
134
+ mappedAtCreation: true
124
135
  });
125
- {
126
- // const mapping = new Uint16Array(this.indexBuffer.getMappedRange());
127
- // for(let i = 0;i < this.mesh.indices.length;++i) {
128
- // mapping.set(this.mesh.indices[i], i);
129
- // }
130
- new Uint16Array(this.indexBuffer.getMappedRange()).set(this.mesh.indices);
131
- this.indexBuffer.unmap();
132
- }
136
+
137
+ new Uint16Array(this.indexBuffer.getMappedRange()).set(this.mesh.indices);
138
+ this.indexBuffer.unmap();
139
+ this.indexCount = indexCount;
133
140
 
134
141
  // Create the depth texture for rendering/sampling the shadow map.
135
142
  this.shadowDepthTexture = this.device.createTexture({
@@ -179,7 +186,8 @@ export default class MEMeshObj {
179
186
 
180
187
  const primitive = {
181
188
  topology: 'triangle-list',
182
- cullMode: 'back',
189
+ // cullMode: 'back', // ORI
190
+ cullMode: 'none', // ORI
183
191
  };
184
192
 
185
193
  this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
@@ -290,7 +298,7 @@ export default class MEMeshObj {
290
298
  });
291
299
 
292
300
  const depthTexture = this.device.createTexture({
293
- size: [canvas.width, canvas.height, 1],
301
+ size: [canvas.width, canvas.height],
294
302
  format: 'depth24plus-stencil8',
295
303
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
296
304
  });
@@ -301,7 +309,7 @@ export default class MEMeshObj {
301
309
  // view is acquired and set in render loop.
302
310
  view: undefined,
303
311
  clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
304
- loadOp: 'clear',
312
+ loadOp: 'clear', // load old fix for FF
305
313
  storeOp: 'store',
306
314
  },
307
315
  ],
@@ -326,8 +334,7 @@ export default class MEMeshObj {
326
334
  // one for the camera and one for the light.
327
335
  // Then a vec3 for the light position.
328
336
  // Rounded to the nearest multiple of 16.
329
- // size: 2 * 4 * 16 + 4 * 4,
330
- size: 160,
337
+ size: 2 * 4 * 16 + 4 * 4,
331
338
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
332
339
  });
333
340
 
@@ -393,16 +400,25 @@ export default class MEMeshObj {
393
400
  // const this.viewMatrix = mat4.identity()
394
401
  const camera = this.cameras[this.mainCameraParams.type];
395
402
  this.viewMatrix = camera.update(deltaTime, this.inputHandler());
403
+ const scaleVec = [1, 1, 1]; // your desired scale OPTION 1
404
+ const scaleMatrix = mat4.scaling(scaleVec);
405
+ // Apply scaling
406
+ mat4.multiply(scaleMatrix, this.viewMatrix, this.viewMatrix);
407
+
396
408
  mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
397
- mat4.rotate(
398
- this.viewMatrix,
399
- vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
400
- degToRad(this.rotation.angle), this.viewMatrix)
401
- // console.info('this: ', this)
402
- mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
403
- mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
404
- mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
405
- // console.info('angle: ', this.rotation.angle, ' axis ' , this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
409
+
410
+ if(this.itIsPhysicsBody == true) {
411
+ mat4.rotate(
412
+ this.viewMatrix,
413
+ vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
414
+ degToRad(this.rotation.angle), this.viewMatrix)
415
+ // console.info('angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
416
+ } else {
417
+ mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
418
+ mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
419
+ mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
420
+ // console.info('NOT PHYSICS angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
421
+ }
406
422
  mat4.multiply(this.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
407
423
  return this.modelViewProjectionMatrix;
408
424
  }
@@ -475,6 +491,11 @@ export default class MEMeshObj {
475
491
  };
476
492
 
477
493
  this.done = true;
494
+ }).then(() => {
495
+ if(typeof this.objAnim !== 'undefined' && this.objAnim !== null) {
496
+ console.log('after all load configutr mesh list buffers')
497
+ this.updateMeshListBuffers()
498
+ }
478
499
  })
479
500
  }
480
501
 
@@ -553,9 +574,17 @@ export default class MEMeshObj {
553
574
 
554
575
  return new Promise(async (resolve) => {
555
576
  const response = await fetch(texturesPaths[0]);
577
+
578
+ // const blob = await response.blob();
579
+ // if(!blob.type.startsWith('image/')) {
580
+ // console.error("Unexpected texture response type:", blob.type);
581
+ // return;
582
+ // }
583
+
584
+ // const imageBitmap = await createImageBitmap(blob);
556
585
  const imageBitmap = await createImageBitmap(await response.blob());
557
586
  this.texture0 = device.createTexture({
558
- size: [imageBitmap.width, imageBitmap.height, 1],
587
+ size: [imageBitmap.width, imageBitmap.height, 1], // REMOVED 1
559
588
  format: 'rgba8unorm',
560
589
  usage:
561
590
  GPUTextureUsage.TEXTURE_BINDING |
@@ -574,7 +603,6 @@ export default class MEMeshObj {
574
603
 
575
604
  draw = (commandEncoder) => {
576
605
  if(this.done == false) return;
577
- // console.log('test draw for meshObj !')
578
606
  const transformationMatrix = this.getTransformationMatrix(this.position);
579
607
  this.device.queue.writeBuffer(
580
608
  this.sceneUniformBuffer,
@@ -598,6 +626,97 @@ export default class MEMeshObj {
598
626
  renderPass.drawIndexed(this.indexCount);
599
627
  }
600
628
 
629
+ // test
630
+ createGPUBuffer(dataArray, usage) {
631
+ if(!dataArray || typeof dataArray.length !== 'number') {
632
+ throw new Error('Invalid data array passed to createGPUBuffer');
633
+ }
634
+
635
+ const size = dataArray.length * dataArray.BYTES_PER_ELEMENT;
636
+ if(!Number.isFinite(size) || size <= 0) {
637
+ throw new Error(`Invalid buffer size: ${size}`);
638
+ }
639
+
640
+ const buffer = this.device.createBuffer({
641
+ size,
642
+ usage,
643
+ mappedAtCreation: true,
644
+ });
645
+
646
+ const writeArray = dataArray.constructor === Float32Array
647
+ ? new Float32Array(buffer.getMappedRange())
648
+ : new Uint16Array(buffer.getMappedRange());
649
+
650
+ writeArray.set(dataArray);
651
+ buffer.unmap();
652
+
653
+ return buffer;
654
+ }
655
+
656
+
657
+ updateMeshListBuffers() {
658
+ for(const key in this.objAnim.meshList) {
659
+ const mesh = this.objAnim.meshList[key];
660
+
661
+ mesh.vertexBuffer = this.device.createBuffer({
662
+ size: mesh.vertices.length * Float32Array.BYTES_PER_ELEMENT,
663
+ usage: GPUBufferUsage.VERTEX,
664
+ mappedAtCreation: true,
665
+ });
666
+ new Float32Array(mesh.vertexBuffer.getMappedRange()).set(mesh.vertices);
667
+ mesh.vertexBuffer.unmap();
668
+
669
+ // Normals
670
+ mesh.vertexNormalsBuffer = this.device.createBuffer({
671
+ size: mesh.vertexNormals.length * Float32Array.BYTES_PER_ELEMENT,
672
+ usage: GPUBufferUsage.VERTEX,
673
+ mappedAtCreation: true,
674
+ });
675
+ new Float32Array(mesh.vertexNormalsBuffer.getMappedRange()).set(mesh.vertexNormals);
676
+ mesh.vertexNormalsBuffer.unmap();
677
+
678
+ // UVs
679
+ mesh.vertexTexCoordsBuffer = this.device.createBuffer({
680
+ size: mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
681
+ usage: GPUBufferUsage.VERTEX,
682
+ mappedAtCreation: true,
683
+ });
684
+ new Float32Array(mesh.vertexTexCoordsBuffer.getMappedRange()).set(mesh.textures);
685
+ mesh.vertexTexCoordsBuffer.unmap();
686
+
687
+ // Indices
688
+ const indexCount = mesh.indices.length;
689
+ const indexSize = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
690
+ mesh.indexBuffer = this.device.createBuffer({
691
+ size: indexSize,
692
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
693
+ mappedAtCreation: true,
694
+ });
695
+ new Uint16Array(mesh.indexBuffer.getMappedRange()).set(mesh.indices);
696
+ mesh.indexBuffer.unmap();
697
+ mesh.indexCount = indexCount;
698
+ }
699
+ }
700
+
701
+ drawElementsAnim = (renderPass) => {
702
+ console.log('render is for anim')
703
+ renderPass.setBindGroup(0, this.sceneBindGroupForRender);
704
+ renderPass.setBindGroup(1, this.modelBindGroup);
705
+ const mesh = this.objAnim.meshList[this.objAnim.id + this.objAnim.currentAni];
706
+
707
+ renderPass.setVertexBuffer(0, mesh.vertexBuffer);
708
+ renderPass.setVertexBuffer(1, mesh.vertexNormalsBuffer);
709
+ renderPass.setVertexBuffer(2, mesh.vertexTexCoordsBuffer);
710
+ renderPass.setIndexBuffer(mesh.indexBuffer, 'uint16');
711
+ renderPass.drawIndexed(mesh.indexCount);
712
+ if(this.objAnim.playing == true) {
713
+ this.objAnim.currentAni++;
714
+ if(this.objAnim.currentAni >= this.objAnim.animations[this.objAnim.animations.active].to) {
715
+ this.objAnim.currentAni = this.objAnim.animations[this.objAnim.animations.active].from;
716
+ }
717
+ }
718
+ }
719
+
601
720
  drawShadows = (shadowPass) => {
602
721
  shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
603
722
  shadowPass.setBindGroup(1, this.modelBindGroup);
@@ -241,7 +241,6 @@ export default class MEMesh {
241
241
  {
242
242
  // view is acquired and set in render loop.
243
243
  view: undefined,
244
-
245
244
  clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
246
245
  loadOp: 'load',
247
246
  storeOp: 'store',
@@ -11,91 +11,82 @@
11
11
  * app is global - will be fixed in future
12
12
  */
13
13
  import {mat4, vec3, vec4} from "wgpu-matrix";
14
-
15
14
  let rayHitEvent;
16
15
 
17
16
  export let touchCoordinate = {
18
- enabled: false,
19
- x: 0,
20
- y: 0,
21
- stopOnFirstDetectedHit: false
17
+ enabled: false,
18
+ x: 0,
19
+ y: 0,
20
+ stopOnFirstDetectedHit: false
22
21
  };
23
22
 
24
23
  function multiplyMatrixVector(matrix, vector) {
25
- return vec4.transformMat4(vector, matrix);
24
+ return vec4.transformMat4(vector, matrix);
26
25
  }
27
26
 
28
27
  export function getRayFromMouse(event, canvas, camera) {
29
- const rect = canvas.getBoundingClientRect();
30
- let x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
31
- let y = ((event.clientY - rect.top) / rect.height) * 2 - 1;
32
- // simple invert
33
- x = -x;
34
- y = -y;
35
- const fov = Math.PI / 4;
36
- const aspect = canvas.width / canvas.height;
37
- const near = 0.1;
38
- const far = 1000;
39
- camera.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 1000.0);
40
- const invProjection = mat4.inverse(camera.projectionMatrix);
41
-
42
- // const correctedView = mat4.clone(camera.view_);
43
- // correctedView[2] *= -1;
44
- // correctedView[6] *= -1;
45
- // correctedView[10] *= -1;
46
- // const invView = mat4.inverse(correctedView);
47
-
48
- const invView = mat4.inverse(camera.view);
49
-
50
- const ndc = [x, y, 1, 1];
51
- let worldPos = multiplyMatrixVector(invProjection, ndc);
52
- worldPos = multiplyMatrixVector(invView, worldPos);
53
- let world;
54
- if (worldPos[3] !== 0) {
55
- world = [
56
- worldPos[0] / worldPos[3],
57
- worldPos[2] / worldPos[3],
58
- worldPos[1] / worldPos[3]
59
- ];
60
- } else {
61
- console.log("[raycaster]special case 0.")
62
- world = [
63
- worldPos[0],
64
- worldPos[1],
65
- worldPos[2]
66
- ];
67
- }
68
- const rayOrigin = [camera.position[0], camera.position[1], camera.position[2]];
69
- const rayDirection = vec3.normalize(vec3.subtract(world, rayOrigin));
70
-
71
- rayDirection[2] = -rayDirection[2];
72
-
73
- return {rayOrigin, rayDirection};
28
+ const rect = canvas.getBoundingClientRect();
29
+ let x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
30
+ let y = ((event.clientY - rect.top) / rect.height) * 2 - 1;
31
+ // simple invert
32
+ x = -x;
33
+ y = -y;
34
+ const fov = Math.PI / 4;
35
+ const aspect = canvas.width / canvas.height;
36
+ const near = 0.1;
37
+ const far = 1000;
38
+ camera.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 1000.0);
39
+ const invProjection = mat4.inverse(camera.projectionMatrix);
40
+ const invView = mat4.inverse(camera.view);
41
+ const ndc = [x, y, 1, 1];
42
+ let worldPos = multiplyMatrixVector(invProjection, ndc);
43
+ worldPos = multiplyMatrixVector(invView, worldPos);
44
+ let world;
45
+ if(worldPos[3] !== 0) {
46
+ world = [
47
+ worldPos[0] / worldPos[3],
48
+ worldPos[2] / worldPos[3],
49
+ worldPos[1] / worldPos[3]
50
+ ];
51
+ } else {
52
+ console.log("[raycaster]special case 0.");
53
+ world = [
54
+ worldPos[0],
55
+ worldPos[1],
56
+ worldPos[2]
57
+ ];
58
+ }
59
+ const rayOrigin = [camera.position[0], camera.position[1], camera.position[2]];
60
+ const rayDirection = vec3.normalize(vec3.subtract(world, rayOrigin));
61
+ rayDirection[2] = -rayDirection[2];
62
+ return {rayOrigin, rayDirection};
74
63
  }
75
64
 
76
65
  export function rayIntersectsSphere(rayOrigin, rayDirection, sphereCenter, sphereRadius) {
77
- const pos = [sphereCenter.x, sphereCenter.y, sphereCenter.z];
78
- const oc = vec3.subtract(rayOrigin, pos);
79
- const a = vec3.dot(rayDirection, rayDirection);
80
- const b = 2.0 * vec3.dot(oc, rayDirection);
81
- const c = vec3.dot(oc, oc) - sphereRadius * sphereRadius;
82
- const discriminant = b * b - 4 * a * c;
83
- return discriminant > 0;
66
+ const pos = [sphereCenter.x, sphereCenter.y, sphereCenter.z];
67
+ const oc = vec3.subtract(rayOrigin, pos);
68
+ const a = vec3.dot(rayDirection, rayDirection);
69
+ const b = 2.0 * vec3.dot(oc, rayDirection);
70
+ const c = vec3.dot(oc, oc) - sphereRadius * sphereRadius;
71
+ const discriminant = b * b - 4 * a * c;
72
+ return discriminant > 0;
84
73
  }
85
74
 
86
- export function addRaycastListener () {
87
- window.addEventListener('click', (event) => {
88
- let canvas = document.getElementsByTagName('canvas')[0];
89
- let camera = app.cameras.WASD;
90
- const { rayOrigin, rayDirection } = getRayFromMouse(event, canvas, camera);
91
- for (const object of app.mainRenderBundle) {
92
- if (rayIntersectsSphere(rayOrigin, rayDirection, object.position, object.raycast.radius)) {
93
- // console.log('Object clicked:', object.name);
94
- // Just like in matrix-engine webGL version "ray.hit.event"
95
- dispatchEvent(new CustomEvent('ray.hit.event', {detail: {
96
- hitObject: object
97
- }}))
98
- }
99
- }
100
- });
75
+ export function addRaycastListener() {
76
+ let canvasDom = document.getElementById("canvas1");
77
+ canvasDom.addEventListener('click', (event) => {
78
+ let camera = app.cameras.WASD;
79
+ const {rayOrigin, rayDirection} = getRayFromMouse(event, canvasDom, camera);
80
+ for(const object of app.mainRenderBundle) {
81
+ if(rayIntersectsSphere(rayOrigin, rayDirection, object.position, object.raycast.radius)) {
82
+ console.log('Object clicked:', object.name);
83
+ // Just like in matrix-engine webGL version "ray.hit.event"
84
+ dispatchEvent(new CustomEvent('ray.hit.event', {
85
+ detail: {
86
+ hitObject: object
87
+ }
88
+ }))
89
+ }
90
+ }
91
+ });
101
92
  }
@@ -708,12 +708,14 @@ export let mb = {
708
708
  mb.c++;
709
709
  },
710
710
  error: function(content) {
711
+ if (mb.root()== null) return;
711
712
  mb.root().classList.remove("success")
712
713
  mb.root().classList.add("error")
713
714
  mb.root().classList.add("fadeInDown");
714
715
  mb.show(content, 'err');
715
716
  },
716
717
  success: function(content) {
718
+ if (mb.root()== null) return;
717
719
  mb.root().classList.remove("error")
718
720
  mb.root().classList.add("success")
719
721
  mb.root().classList.add("fadeInDown");
@@ -1,4 +1,3 @@
1
- // import {vec3} from "wgpu-matrix";
2
1
  import {LOG_FUNNY, degToRad, quaternion_rotation_matrix, radToDeg, scriptManager} from "../engine/utils";
3
2
 
4
3
  export default class MatrixAmmo {
@@ -17,7 +16,6 @@ export default class MatrixAmmo {
17
16
  }
18
17
 
19
18
  init = () => {
20
- // console.log('pre ammo')
21
19
  Ammo().then(Ammo => {
22
20
  // Physics variables
23
21
  this.dynamicsWorld = null;
@@ -58,8 +56,6 @@ export default class MatrixAmmo {
58
56
  body.name = 'ground';
59
57
  this.ground = body;
60
58
  this.dynamicsWorld.addRigidBody(body);
61
- // this.rigidBodies.push(body);
62
- // add collide event
63
59
  this.detectCollision()
64
60
  }
65
61
 
@@ -79,15 +75,12 @@ export default class MatrixAmmo {
79
75
  var mass = 1;
80
76
  var localInertia = new Ammo.btVector3(0, 0, 0);
81
77
  colShape.calculateLocalInertia(mass, localInertia);
82
-
83
78
  startTransform.setOrigin(new Ammo.btVector3(pOptions.position.x, pOptions.position.y, pOptions.position.z));
84
79
 
85
80
  var myMotionState = new Ammo.btDefaultMotionState(startTransform),
86
81
  rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia),
87
82
  body = new Ammo.btRigidBody(rbInfo);
88
83
 
89
- console.log("TEST ADDING PHYSICS ");
90
-
91
84
  body.MEObject = MEObject;
92
85
  this.dynamicsWorld.addRigidBody(body);
93
86
  this.rigidBodies.push(body);
@@ -95,7 +88,6 @@ export default class MatrixAmmo {
95
88
  }
96
89
 
97
90
  addPhysicsBox(MEObject, pOptions) {
98
-
99
91
  const FLAGS = {
100
92
  TEST_NIDZA: 3,
101
93
  CF_KINEMATIC_OBJECT: 2
@@ -110,7 +102,6 @@ export default class MatrixAmmo {
110
102
  var localInertia = new Ammo.btVector3(0, 0, 0);
111
103
  colShape.calculateLocalInertia(mass, localInertia);
112
104
  startTransform.setOrigin(new Ammo.btVector3(pOptions.position.x, pOptions.position.y, pOptions.position.z));
113
- //rotation
114
105
  // console.log('startTransform.setRotation', startTransform.setRotation)
115
106
  var t = startTransform.getRotation()
116
107
  t.setX(degToRad(pOptions.rotation.x))
@@ -118,8 +109,6 @@ export default class MatrixAmmo {
118
109
  t.setZ(degToRad(pOptions.rotation.z))
119
110
  startTransform.setRotation(t)
120
111
 
121
- // startTransform.setRotation(pOptions.rotation.x, pOptions.rotation.y, pOptions.rotation.z);
122
-
123
112
  var myMotionState = new Ammo.btDefaultMotionState(startTransform),
124
113
  rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia),
125
114
  body = new Ammo.btRigidBody(rbInfo);
@@ -135,8 +124,8 @@ export default class MatrixAmmo {
135
124
  } else {
136
125
  body.setActivationState(4)
137
126
  }
138
- // console.log('what is name.', pOptions.name)
139
127
  body.name = pOptions.name;
128
+ MEObject.itIsPhysicsBody = true;
140
129
  body.MEObject = MEObject;
141
130
  this.dynamicsWorld.addRigidBody(body);
142
131
  this.rigidBodies.push(body);
@@ -168,7 +157,6 @@ export default class MatrixAmmo {
168
157
  let ms = physicsBody.getMotionState();
169
158
  if(ms) {
170
159
  var tmpTrans = new Ammo.btTransform();
171
- // quat.setValue(quat.x(), quat.y(), quat.z(), quat.w());
172
160
  tmpTrans.setIdentity();
173
161
  tmpTrans.setOrigin(pos);
174
162
  tmpTrans.setRotation(localRot);
@@ -222,7 +210,6 @@ export default class MatrixAmmo {
222
210
  detectCollision() {
223
211
  // console.log('override this')
224
212
  return;
225
-
226
213
  this.lastRoll = '';
227
214
  this.presentScore = '';
228
215
 
@@ -3,8 +3,7 @@ export let fragmentWGSL = `override shadowDepthTextureSize: f32 = 1024.0;
3
3
  struct Scene {
4
4
  lightViewProjMatrix : mat4x4f,
5
5
  cameraViewProjMatrix : mat4x4f,
6
- lightPos : vec4f,
7
- // padding: f32, // 👈 fix alignment
6
+ lightPos : vec3f,
8
7
  }
9
8
 
10
9
  @group(0) @binding(0) var<uniform> scene : Scene;
@@ -40,7 +39,7 @@ fn main(input : FragmentInput) -> @location(0) vec4f {
40
39
  }
41
40
  }
42
41
  visibility /= 9.0;
43
- let lambertFactor = max(dot(normalize(scene.lightPos.xyz - input.fragPos), normalize(input.fragNorm)), 0.0);
42
+ let lambertFactor = max(dot(normalize(scene.lightPos - input.fragPos), normalize(input.fragNorm)), 0.0);
44
43
  let lightingFactor = min(ambientFactor + visibility * lambertFactor, 1.0);
45
44
  let textureColor = textureSample(meshTexture, meshSampler, input.uv);
46
45
 
@@ -1,8 +1,7 @@
1
1
  export let vertexWGSL = `struct Scene {
2
2
  lightViewProjMatrix: mat4x4f,
3
3
  cameraViewProjMatrix: mat4x4f,
4
- lightPos: vec4f,
5
- // padding: f32, // 👈 fix alignment
4
+ lightPos: vec3f,
6
5
  }
7
6
 
8
7
  struct Model {
@@ -1,8 +1,7 @@
1
1
  export let vertexShadowWGSL = `struct Scene {
2
2
  lightViewProjMatrix: mat4x4f,
3
3
  cameraViewProjMatrix: mat4x4f,
4
- lightPos: vec4f,
5
- // padding: f32, // 👈 fix alignment
4
+ lightPos: vec3f,
6
5
  }
7
6
 
8
7
  struct Model {
package/src/world.js CHANGED
@@ -8,6 +8,7 @@ import MatrixAmmo from "./physics/matrix-ammo.js";
8
8
  import {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
+ import {play} from "./engine/loader-obj.js";
11
12
 
12
13
  export default class MatrixEngineWGPU {
13
14
 
@@ -34,6 +35,7 @@ export default class MatrixEngineWGPU {
34
35
  this.options = {
35
36
  useSingleRenderPass: true,
36
37
  canvasSize: 'fullscreen',
38
+ canvasId: 'canvas1',
37
39
  mainCameraParams: {
38
40
  type: 'WASD',
39
41
  responseCoef: 2000
@@ -41,6 +43,9 @@ export default class MatrixEngineWGPU {
41
43
  }
42
44
  callback = options;
43
45
  }
46
+ if(typeof options.canvasId === 'undefined') {
47
+ options.canvasId = 'canvas1';
48
+ }
44
49
  if(typeof options.mainCameraParams === 'undefined') {
45
50
  options.mainCameraParams = {
46
51
  type: 'WASD',
@@ -48,12 +53,11 @@ export default class MatrixEngineWGPU {
48
53
  }
49
54
  }
50
55
  this.options = options;
51
-
52
56
  this.mainCameraParams = options.mainCameraParams;
53
57
 
54
58
  const target = this.options.appendTo || document.body;
55
-
56
59
  var canvas = document.createElement('canvas')
60
+ canvas.id = this.options.canvasId;
57
61
  if(this.options.canvasSize == 'fullscreen') {
58
62
  canvas.width = window.innerWidth;
59
63
  canvas.height = window.innerHeight;
@@ -255,28 +259,21 @@ export default class MatrixEngineWGPU {
255
259
  if(typeof o.texturesPaths === 'undefined') {o.texturesPaths = ['./res/textures/default.png']}
256
260
  if(typeof o.mainCameraParams === 'undefined') {o.mainCameraParams = this.mainCameraParams}
257
261
  if(typeof o.scale === 'undefined') {o.scale = [1, 1, 1];}
258
- if(typeof o.raycast === 'undefined') {o.raycast = {enabled: false}}
259
-
262
+ if(typeof o.raycast === 'undefined') {o.raycast = {enabled: false, radius: 2}}
260
263
  o.entityArgPass = this.entityArgPass;
261
264
  o.cameras = this.cameras;
262
- // if(typeof o.name === 'undefined') {o.name = 'random' + Math.random();}
263
- if(typeof o.mesh === 'undefined') {
264
- mb.error('arg mesh is empty for ', o.name);
265
- throw console.error('arg mesh is empty...');
266
- return;
267
- }
268
265
  if(typeof o.physics === 'undefined') {
269
266
  o.physics = {
270
267
  scale: [1, 1, 1],
271
268
  enabled: true,
272
- geometry: "Sphere",
273
- radius: o.scale,
269
+ geometry: "Sphere",// must be fixed<<
270
+ radius: (typeof o.scale == Number ? o.scale : o.scale[0]),
274
271
  name: o.name,
275
272
  rotation: o.rotation
276
273
  }
277
274
  }
278
275
  if(typeof o.physics.enabled === 'undefined') {o.physics.enabled = true}
279
- if(typeof o.physics.geometry === 'undefined') {o.physics.geometry = "Sphere"}
276
+ if(typeof o.physics.geometry === 'undefined') {o.physics.geometry = "Cube"}
280
277
  if(typeof o.physics.radius === 'undefined') {o.physics.radius = o.scale}
281
278
  if(typeof o.physics.mass === 'undefined') {o.physics.mass = 1;}
282
279
  if(typeof o.physics.name === 'undefined') {o.physics.name = o.name;}
@@ -284,6 +281,39 @@ export default class MatrixEngineWGPU {
284
281
  if(typeof o.physics.rotation === 'undefined') {o.physics.rotation = o.rotation;}
285
282
  o.physics.position = o.position;
286
283
  // console.log('Mesh procedure', o)
284
+ // TEST OBJS SEQ ANIMS
285
+ if(typeof o.objAnim == 'undefined' || typeof o.objAnim == null) {
286
+ o.objAnim = null;
287
+ } else {
288
+ console.log('o.anim', o.objAnim)
289
+ // o.objAnim = {
290
+ // id: o.objAnim.id,
291
+ // sumOfAniFrames: o.objAnim.sumOfAniFrames,
292
+ // currentAni: o.objAnim.currentAni,
293
+ // speed: o.objAnim.speed,
294
+ // currentDraws: 0
295
+ // };
296
+
297
+ if(typeof o.objAnim.animations !== 'undefined') {
298
+ // o.objAnim.animation.anims = o.objAnim.animations;
299
+ console.log('o.o.objAnim.animations ', o.objAnim.animations )
300
+ o.objAnim.play = play;
301
+ }
302
+ // no need for single test it in future
303
+ o.objAnim.meshList = o.objAnim.meshList;
304
+
305
+ if(typeof o.mesh === 'undefined') {
306
+ o.mesh = o.objAnim.meshList[0];
307
+ console.info('objSeq animation is active.');
308
+ }
309
+ // scale for all second option!
310
+ o.objAnim.scaleAll = function(s) {
311
+ for(var k in this.meshList) {
312
+ console.log('SCALE');
313
+ this.meshList[k].setScale(s);
314
+ }
315
+ }
316
+ }
287
317
  let myMesh1 = new MEMeshObj(this.canvas, this.device, this.context, o)
288
318
  if(o.physics.enabled == true) {
289
319
  this.matrixAmmo.addPhysics(myMesh1, o.physics)
@@ -345,9 +375,7 @@ export default class MatrixEngineWGPU {
345
375
 
346
376
  framePassPerObject = () => {
347
377
  let commandEncoder = this.device.createCommandEncoder();
348
-
349
378
  this.matrixAmmo.updatePhysics();
350
-
351
379
  this.mainRenderBundle.forEach((meItem, index) => {
352
380
  if(index === 0) {
353
381
  if(meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'clear';
@@ -360,7 +388,6 @@ export default class MatrixEngineWGPU {
360
388
  // Set up view per object
361
389
  meItem.renderPassDescriptor.colorAttachments[0].view =
362
390
  this.context.getCurrentTexture().createView();
363
-
364
391
  const passEncoder = commandEncoder.beginRenderPass(meItem.renderPassDescriptor);
365
392
  passEncoder.executeBundles([meItem.renderBundle]); // ✅ Use only this bundle
366
393
  passEncoder.end();
@@ -368,9 +395,7 @@ export default class MatrixEngineWGPU {
368
395
  meItem.draw(commandEncoder); // fallback if no renderBundle
369
396
  }
370
397
  });
371
-
372
398
  this.device.queue.submit([commandEncoder.finish()]);
373
399
  requestAnimationFrame(this.frame);
374
400
  }
375
-
376
401
  }