matrix-engine-wgpu 1.2.14 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.1",
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
@@ -69,7 +69,7 @@ mainCameraParams: {
69
69
 
70
70
  ---
71
71
 
72
- ### Object Positioning
72
+ ### Object Position
73
73
 
74
74
  Control object position:
75
75
 
@@ -134,7 +134,7 @@ app.cameras.WASD.pitch = 0.2;
134
134
 
135
135
  ---
136
136
 
137
- ## Object Interaction (Raycasting)
137
+ ### Object Interaction (Raycasting)
138
138
 
139
139
  The raycast returns:
140
140
 
@@ -173,7 +173,7 @@ window.addEventListener('ray.hit.event', (event) => {
173
173
 
174
174
  ---
175
175
 
176
- ## How to Load `.obj` Models
176
+ ### How to Load `.obj` Models
177
177
 
178
178
  ```js
179
179
  import MatrixEngineWGPU from "./src/world.js";
@@ -234,6 +234,75 @@ 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
+ import MatrixEngineWGPU from "../src/world.js";
243
+ import { downloadMeshes, makeObjSeqArg } from "../src/engine/loader-obj.js";
244
+ import { LOG_MATRIX } from "../src/engine/utils.js";
245
+
246
+ export var loadObjsSequence = function () {
247
+ let loadObjFile = new MatrixEngineWGPU({
248
+ useSingleRenderPass: true,
249
+ canvasSize: "fullscreen",
250
+ mainCameraParams: {
251
+ type: "WASD",
252
+ responseCoef: 1000,
253
+ },
254
+ }, () => {
255
+
256
+ addEventListener("AmmoReady", () => {
257
+ downloadMeshes(
258
+ makeObjSeqArg({
259
+ id: "swat-walk-pistol",
260
+ path: "res/meshes/objs-sequence/swat-walk-pistol",
261
+ from: 1,
262
+ to: 20,
263
+ }),
264
+ onLoadObj,
265
+ { scale: [10, 10, 10] }
266
+ );
267
+ });
268
+
269
+ function onLoadObj(m) {
270
+ console.log(`%c Loaded objs: ${m} `, LOG_MATRIX);
271
+ var objAnim = {
272
+ id: "swat-walk-pistol",
273
+ meshList: m,
274
+ currentAni: 1,
275
+ animations: {
276
+ active: "walk",
277
+ walk: { from: 1, to: 20, speed: 3 },
278
+ walkPistol: { from: 36, to: 60, speed: 3 },
279
+ },
280
+ };
281
+
282
+ loadObjFile.addMeshObj({
283
+ position: { x: 0, y: 2, z: -10 },
284
+ rotation: { x: 0, y: 0, z: 0 },
285
+ rotationSpeed: { x: 0, y: 0, z: 0 },
286
+ scale: [100, 100, 100],
287
+ texturesPaths: ["./res/meshes/blender/cube.png"],
288
+ name: "swat",
289
+ mesh: m["swat-walk-pistol"],
290
+ physics: {
291
+ enabled: false,
292
+ geometry: "Cube",
293
+ },
294
+ objAnim: objAnim,
295
+ });
296
+
297
+ app.mainRenderBundle[0].objAnim.play("walk");
298
+ }
299
+ });
300
+
301
+ window.app = loadObjFile;
302
+ };
303
+
304
+ ### 📽️ Preview
305
+
237
306
  ## @Note
238
307
  If this happen less then 15 times (Loading procces) then it is ok probably...
239
308
  ```warn
@@ -278,6 +347,7 @@ Uses `watchify` to bundle JavaScript.
278
347
  ## Resources
279
348
 
280
349
  All resources and output go into the `./public` folder — everything you need in one place.
350
+ This is static file storage.
281
351
 
282
352
  ---
283
353
 
@@ -324,4 +394,4 @@ You may use, modify, and sell projects based on this code — just keep this not
324
394
 
325
395
  Top level main.js instance (Ultimate Yahtzee)
326
396
 
327
- ---
397
+ ---
@@ -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
  }
@@ -25,11 +25,21 @@ export default class MEMeshObj {
25
25
  this.context = context;
26
26
  this.entityArgPass = o.entityArgPass;
27
27
 
28
- // Mesh stuff
28
+ // Mesh stuff - for single mesh or t-posed (fiktive-first in loading order)
29
29
  this.mesh = o.mesh;
30
30
  this.mesh.uvs = this.mesh.textures;
31
31
  console.log(`%c Mesh loaded: ${o.name}`, LOG_FUNNY_SMALL);
32
32
 
33
+ // ObjSequence animation
34
+ if(typeof o.objAnim !== 'undefined' && o.objAnim != null) {
35
+ this.objAnim = o.objAnim;
36
+ for (var key in this.objAnim.animations){
37
+ if (key != 'active') this.objAnim.animations[key].speedCounter = 0;
38
+ }
39
+ console.log(`%c Mesh objAnim exist: ${o.objAnim}`, LOG_FUNNY_SMALL);
40
+ this.drawElements = this.drawElementsAnim;
41
+ }
42
+
33
43
  this.inputHandler = createInputHandler(window, canvas);
34
44
  this.cameras = o.cameras;
35
45
 
@@ -61,7 +71,7 @@ export default class MEMeshObj {
61
71
  this.modelViewProjectionMatrix = mat4.create();
62
72
  // console.log('cube added texturesPaths: ', this.texturesPaths)
63
73
  this.loadTex0(this.texturesPaths, device).then(() => {
64
- // console.log('loaded tex buffer for mesh:', this.texture0)
74
+ console.log('loaded tex buffer for mesh:', this.texture0)
65
75
  resolve()
66
76
  })
67
77
  })
@@ -117,19 +127,18 @@ export default class MEMeshObj {
117
127
 
118
128
  // Create the model index buffer.
119
129
  this.indexCount = this.mesh.indices.length;
130
+ const indexCount = this.mesh.indices.length;
131
+ const size = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
132
+
120
133
  this.indexBuffer = this.device.createBuffer({
121
- size: this.indexCount * Uint16Array.BYTES_PER_ELEMENT,
122
- usage: GPUBufferUsage.INDEX,
123
- mappedAtCreation: true,
134
+ size,
135
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
136
+ mappedAtCreation: true
124
137
  });
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
- }
138
+
139
+ new Uint16Array(this.indexBuffer.getMappedRange()).set(this.mesh.indices);
140
+ this.indexBuffer.unmap();
141
+ this.indexCount = indexCount;
133
142
 
134
143
  // Create the depth texture for rendering/sampling the shadow map.
135
144
  this.shadowDepthTexture = this.device.createTexture({
@@ -179,7 +188,8 @@ export default class MEMeshObj {
179
188
 
180
189
  const primitive = {
181
190
  topology: 'triangle-list',
182
- cullMode: 'back',
191
+ // cullMode: 'back', // ORI
192
+ cullMode: 'none', // ORI
183
193
  };
184
194
 
185
195
  this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
@@ -290,7 +300,7 @@ export default class MEMeshObj {
290
300
  });
291
301
 
292
302
  const depthTexture = this.device.createTexture({
293
- size: [canvas.width, canvas.height, 1],
303
+ size: [canvas.width, canvas.height],
294
304
  format: 'depth24plus-stencil8',
295
305
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
296
306
  });
@@ -301,7 +311,7 @@ export default class MEMeshObj {
301
311
  // view is acquired and set in render loop.
302
312
  view: undefined,
303
313
  clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
304
- loadOp: 'clear',
314
+ loadOp: 'clear', // load old fix for FF
305
315
  storeOp: 'store',
306
316
  },
307
317
  ],
@@ -326,8 +336,7 @@ export default class MEMeshObj {
326
336
  // one for the camera and one for the light.
327
337
  // Then a vec3 for the light position.
328
338
  // Rounded to the nearest multiple of 16.
329
- // size: 2 * 4 * 16 + 4 * 4,
330
- size: 160,
339
+ size: 2 * 4 * 16 + 4 * 4,
331
340
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
332
341
  });
333
342
 
@@ -393,16 +402,25 @@ export default class MEMeshObj {
393
402
  // const this.viewMatrix = mat4.identity()
394
403
  const camera = this.cameras[this.mainCameraParams.type];
395
404
  this.viewMatrix = camera.update(deltaTime, this.inputHandler());
405
+ const scaleVec = [1, 1, 1]; // your desired scale OPTION 1
406
+ const scaleMatrix = mat4.scaling(scaleVec);
407
+ // Apply scaling
408
+ mat4.multiply(scaleMatrix, this.viewMatrix, this.viewMatrix);
409
+
396
410
  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)
411
+
412
+ if(this.itIsPhysicsBody == true) {
413
+ mat4.rotate(
414
+ this.viewMatrix,
415
+ vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
416
+ degToRad(this.rotation.angle), this.viewMatrix)
417
+ // console.info('angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
418
+ } else {
419
+ mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
420
+ mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
421
+ mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
422
+ // console.info('NOT PHYSICS angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
423
+ }
406
424
  mat4.multiply(this.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
407
425
  return this.modelViewProjectionMatrix;
408
426
  }
@@ -475,6 +493,11 @@ export default class MEMeshObj {
475
493
  };
476
494
 
477
495
  this.done = true;
496
+ }).then(() => {
497
+ if(typeof this.objAnim !== 'undefined' && this.objAnim !== null) {
498
+ console.log('after all load configutr mesh list buffers')
499
+ this.updateMeshListBuffers()
500
+ }
478
501
  })
479
502
  }
480
503
 
@@ -553,9 +576,17 @@ export default class MEMeshObj {
553
576
 
554
577
  return new Promise(async (resolve) => {
555
578
  const response = await fetch(texturesPaths[0]);
579
+
580
+ // const blob = await response.blob();
581
+ // if(!blob.type.startsWith('image/')) {
582
+ // console.error("Unexpected texture response type:", blob.type);
583
+ // return;
584
+ // }
585
+
586
+ // const imageBitmap = await createImageBitmap(blob);
556
587
  const imageBitmap = await createImageBitmap(await response.blob());
557
588
  this.texture0 = device.createTexture({
558
- size: [imageBitmap.width, imageBitmap.height, 1],
589
+ size: [imageBitmap.width, imageBitmap.height, 1], // REMOVED 1
559
590
  format: 'rgba8unorm',
560
591
  usage:
561
592
  GPUTextureUsage.TEXTURE_BINDING |
@@ -574,7 +605,6 @@ export default class MEMeshObj {
574
605
 
575
606
  draw = (commandEncoder) => {
576
607
  if(this.done == false) return;
577
- // console.log('test draw for meshObj !')
578
608
  const transformationMatrix = this.getTransformationMatrix(this.position);
579
609
  this.device.queue.writeBuffer(
580
610
  this.sceneUniformBuffer,
@@ -598,6 +628,100 @@ export default class MEMeshObj {
598
628
  renderPass.drawIndexed(this.indexCount);
599
629
  }
600
630
 
631
+ // test
632
+ createGPUBuffer(dataArray, usage) {
633
+ if(!dataArray || typeof dataArray.length !== 'number') {
634
+ throw new Error('Invalid data array passed to createGPUBuffer');
635
+ }
636
+
637
+ const size = dataArray.length * dataArray.BYTES_PER_ELEMENT;
638
+ if(!Number.isFinite(size) || size <= 0) {
639
+ throw new Error(`Invalid buffer size: ${size}`);
640
+ }
641
+
642
+ const buffer = this.device.createBuffer({
643
+ size,
644
+ usage,
645
+ mappedAtCreation: true,
646
+ });
647
+
648
+ const writeArray = dataArray.constructor === Float32Array
649
+ ? new Float32Array(buffer.getMappedRange())
650
+ : new Uint16Array(buffer.getMappedRange());
651
+
652
+ writeArray.set(dataArray);
653
+ buffer.unmap();
654
+
655
+ return buffer;
656
+ }
657
+
658
+
659
+ updateMeshListBuffers() {
660
+ for(const key in this.objAnim.meshList) {
661
+ const mesh = this.objAnim.meshList[key];
662
+
663
+ mesh.vertexBuffer = this.device.createBuffer({
664
+ size: mesh.vertices.length * Float32Array.BYTES_PER_ELEMENT,
665
+ usage: GPUBufferUsage.VERTEX,
666
+ mappedAtCreation: true,
667
+ });
668
+ new Float32Array(mesh.vertexBuffer.getMappedRange()).set(mesh.vertices);
669
+ mesh.vertexBuffer.unmap();
670
+
671
+ // Normals
672
+ mesh.vertexNormalsBuffer = this.device.createBuffer({
673
+ size: mesh.vertexNormals.length * Float32Array.BYTES_PER_ELEMENT,
674
+ usage: GPUBufferUsage.VERTEX,
675
+ mappedAtCreation: true,
676
+ });
677
+ new Float32Array(mesh.vertexNormalsBuffer.getMappedRange()).set(mesh.vertexNormals);
678
+ mesh.vertexNormalsBuffer.unmap();
679
+
680
+ // UVs
681
+ mesh.vertexTexCoordsBuffer = this.device.createBuffer({
682
+ size: mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
683
+ usage: GPUBufferUsage.VERTEX,
684
+ mappedAtCreation: true,
685
+ });
686
+ new Float32Array(mesh.vertexTexCoordsBuffer.getMappedRange()).set(mesh.textures);
687
+ mesh.vertexTexCoordsBuffer.unmap();
688
+
689
+ // Indices
690
+ const indexCount = mesh.indices.length;
691
+ const indexSize = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
692
+ mesh.indexBuffer = this.device.createBuffer({
693
+ size: indexSize,
694
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
695
+ mappedAtCreation: true,
696
+ });
697
+ new Uint16Array(mesh.indexBuffer.getMappedRange()).set(mesh.indices);
698
+ mesh.indexBuffer.unmap();
699
+ mesh.indexCount = indexCount;
700
+ }
701
+ }
702
+
703
+ drawElementsAnim = (renderPass) => {
704
+ renderPass.setBindGroup(0, this.sceneBindGroupForRender);
705
+ renderPass.setBindGroup(1, this.modelBindGroup);
706
+ const mesh = this.objAnim.meshList[this.objAnim.id + this.objAnim.currentAni];
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
+ if (this.objAnim.animations[this.objAnim.animations.active].speedCounter >= this.objAnim.animations[this.objAnim.animations.active].speed) {
714
+ this.objAnim.currentAni++;
715
+ this.objAnim.animations[this.objAnim.animations.active].speedCounter = 0;
716
+ } else {
717
+ this.objAnim.animations[this.objAnim.animations.active].speedCounter++;
718
+ }
719
+ if(this.objAnim.currentAni >= this.objAnim.animations[this.objAnim.animations.active].to) {
720
+ this.objAnim.currentAni = this.objAnim.animations[this.objAnim.animations.active].from;
721
+ }
722
+ }
723
+ }
724
+
601
725
  drawShadows = (shadowPass) => {
602
726
  shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
603
727
  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
  }