matrix-engine-wgpu 1.3.6 → 1.3.7

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/index.js CHANGED
@@ -6,7 +6,13 @@
6
6
  // import {degToRad, radToDeg} from "./utils";
7
7
  import {downloadMeshes} from "./src/engine/loader-obj.js";
8
8
  import MatrixEngineWGPU from "./src/world.js";
9
- import {addRaycastsAABBListener, addRaycastListener, getRayFromMouse, rayIntersectsSphere} from "./src/engine/raycast.js";
9
+ import {
10
+ addRaycastsAABBListener,
11
+ addRaycastListener, getRayFromMouse,
12
+ getRayFromMouse2, rayIntersectsSphere,
13
+ computeWorldVertsAndAABB, rayIntersectsAABB,
14
+ computeAABB
15
+ } from "./src/engine/raycast.js";
10
16
 
11
17
  var about = () => {
12
18
  console.log("Hi npm. matrix-engine for webgpu is ready...")
@@ -15,16 +21,20 @@ var about = () => {
15
21
  console.log(" - Loading obj files with uvs")
16
22
  console.log(" - Scene camera use -z front")
17
23
  console.log(" - position, rotation - same like matrix-engine")
18
- console.log(" - Physics used Ammo.js build")
19
- console.log(" - Raycaster HIT/CLICK on object scene")
24
+ console.log(" - Physics used Ammo.js build")
25
+ console.log(" - Raycaster HIT/CLICK on object scene")
20
26
  }
21
27
 
22
28
  export {
23
29
  MatrixEngineWGPU,
24
30
  downloadMeshes,
25
- rayIntersectsSphere,
26
- getRayFromMouse,
27
- addRaycastListener,
31
+ rayIntersectsSphere,
32
+ getRayFromMouse,
33
+ getRayFromMouse2,
34
+ addRaycastListener,
28
35
  addRaycastsAABBListener,
36
+ rayIntersectsAABB,
37
+ computeAABB,
38
+ computeWorldVertsAndAABB,
29
39
  about
30
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matrix-engine-wgpu",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
4
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": [
package/readme.md CHANGED
@@ -71,6 +71,10 @@ mainCameraParams: {
71
71
 
72
72
  ### Object Position
73
73
 
74
+ Best way for access physics body object:
75
+ app.matrixAmmo.getBodyByName(name)
76
+ also app.matrixAmmo.getNameByBody
77
+
74
78
  Control object position:
75
79
 
76
80
  ```js
@@ -164,13 +168,17 @@ window.addEventListener('click', (event) => {
164
168
  Automatic raycast listener:
165
169
 
166
170
  ```js
167
- addRaycastListener();
171
+ addRaycastListener();
168
172
 
169
173
  window.addEventListener('ray.hit.event', (event) => {
170
174
  console.log('Ray hit:', event.detail.hitObject);
171
175
  });
172
176
  ```
173
-
177
+ Engine also exports (box):
178
+ - addRaycastsAABBListener
179
+ - rayIntersectsAABB,
180
+ - computeAABB,
181
+ - computeWorldVertsAndAABB,
174
182
  ---
175
183
 
176
184
  ### How to Load `.obj` Models
@@ -36,8 +36,8 @@ export default class MEMeshObj {
36
36
  // ObjSequence animation
37
37
  if(typeof o.objAnim !== 'undefined' && o.objAnim != null) {
38
38
  this.objAnim = o.objAnim;
39
- for (var key in this.objAnim.animations){
40
- if (key != 'active') this.objAnim.animations[key].speedCounter = 0;
39
+ for(var key in this.objAnim.animations) {
40
+ if(key != 'active') this.objAnim.animations[key].speedCounter = 0;
41
41
  }
42
42
  console.log(`%c Mesh objAnim exist: ${o.objAnim}`, LOG_FUNNY_SMALL);
43
43
  this.drawElements = this.drawElementsAnim;
@@ -428,6 +428,25 @@ export default class MEMeshObj {
428
428
  return this.modelViewProjectionMatrix;
429
429
  }
430
430
 
431
+ this.getModelMatrix = (pos) => {
432
+ let modelMatrix = mat4.identity();
433
+ mat4.translate(modelMatrix, [pos.x, pos.y, pos.z], modelMatrix);
434
+ if(this.itIsPhysicsBody) {
435
+ mat4.rotate(modelMatrix,
436
+ [this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z],
437
+ degToRad(this.rotation.angle),
438
+ modelMatrix
439
+ );
440
+ } else {
441
+ mat4.rotateX(modelMatrix, this.rotation.getRotX(), modelMatrix);
442
+ mat4.rotateY(modelMatrix, this.rotation.getRotY(), modelMatrix);
443
+ mat4.rotateZ(modelMatrix, this.rotation.getRotZ(), modelMatrix);
444
+ }
445
+ // Apply scale if you have it, e.g.:
446
+ // mat4.scale(modelMatrix, modelMatrix, [this.scale.x, this.scale.y, this.scale.z]);
447
+ return modelMatrix;
448
+ };
449
+
431
450
  this.upVector = vec3.fromValues(0, 1, 0);
432
451
  this.origin = vec3.fromValues(0, 0, 0);
433
452
 
@@ -609,6 +628,7 @@ export default class MEMeshObj {
609
628
  draw = (commandEncoder) => {
610
629
  if(this.done == false) return;
611
630
  const transformationMatrix = this.getTransformationMatrix(this.position);
631
+
612
632
  this.device.queue.writeBuffer(
613
633
  this.sceneUniformBuffer,
614
634
  64,
@@ -713,7 +733,7 @@ export default class MEMeshObj {
713
733
  renderPass.setIndexBuffer(mesh.indexBuffer, 'uint16');
714
734
  renderPass.drawIndexed(mesh.indexCount);
715
735
  if(this.objAnim.playing == true) {
716
- if (this.objAnim.animations[this.objAnim.animations.active].speedCounter >= this.objAnim.animations[this.objAnim.animations.active].speed) {
736
+ if(this.objAnim.animations[this.objAnim.animations.active].speedCounter >= this.objAnim.animations[this.objAnim.animations.active].speed) {
717
737
  this.objAnim.currentAni++;
718
738
  this.objAnim.animations[this.objAnim.animations.active].speedCounter = 0;
719
739
  } else {
@@ -62,6 +62,43 @@ export function getRayFromMouse(event, canvas, camera) {
62
62
  return {rayOrigin, rayDirection};
63
63
  }
64
64
 
65
+ export function getRayFromMouse2(event, canvas, camera) {
66
+ const rect = canvas.getBoundingClientRect();
67
+ let x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
68
+ let y = ((event.clientY - rect.top) / rect.height) * 2 - 1;
69
+ // simple invert
70
+ y = -y;
71
+ const fov = Math.PI / 4;
72
+ const aspect = canvas.width / canvas.height;
73
+ const near = 0.1;
74
+ const far = 1000;
75
+ camera.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 1000.0);
76
+ const invProjection = mat4.inverse(camera.projectionMatrix);
77
+ console.log("camera.view:" + camera.view)
78
+ const invView = mat4.inverse(camera.view);
79
+ const ndc = [x, y, 1, 1];
80
+ let worldPos = multiplyMatrixVector(invProjection, ndc);
81
+ worldPos = multiplyMatrixVector(invView, worldPos);
82
+ let world;
83
+ if(worldPos[3] !== 0) {
84
+ world = [
85
+ worldPos[0] / worldPos[3],
86
+ worldPos[1] / worldPos[3],
87
+ worldPos[2] / worldPos[3]
88
+ ];
89
+ } else {
90
+ console.log("[raycaster]special case 0.");
91
+ world = [
92
+ worldPos[0],
93
+ worldPos[1],
94
+ worldPos[2]
95
+ ];
96
+ }
97
+ const rayOrigin = [camera.position[0], camera.position[1], camera.position[2]];
98
+ const rayDirection = vec3.normalize(vec3.subtract(world, rayOrigin));
99
+ return {rayOrigin, rayDirection};
100
+ }
101
+
65
102
  export function rayIntersectsSphere(rayOrigin, rayDirection, sphereCenter, sphereRadius) {
66
103
  const pos = [sphereCenter.x, sphereCenter.y, sphereCenter.z];
67
104
  const oc = vec3.subtract(rayOrigin, pos);
@@ -78,12 +115,15 @@ export function addRaycastListener(canvasId = "canvas1") {
78
115
  let camera = app.cameras.WASD;
79
116
  const {rayOrigin, rayDirection} = getRayFromMouse(event, canvasDom, camera);
80
117
  for(const object of app.mainRenderBundle) {
118
+ if(object.raycast.enabled == false) return;
81
119
  if(rayIntersectsSphere(rayOrigin, rayDirection, object.position, object.raycast.radius)) {
82
120
  console.log('Object clicked:', object.name);
83
121
  // Just like in matrix-engine webGL version "ray.hit.event"
84
122
  dispatchEvent(new CustomEvent('ray.hit.event', {
85
123
  detail: {
86
- hitObject: object
124
+ hitObject: object,
125
+ rayOrigin: rayOrigin,
126
+ rayDirection: rayDirection
87
127
  }
88
128
  }))
89
129
  }
@@ -91,12 +131,26 @@ export function addRaycastListener(canvasId = "canvas1") {
91
131
  });
92
132
  }
93
133
 
94
- export function rayIntersectsAABB(
95
- rayOrigin,
96
- rayDirection,
97
- boxMin,
98
- boxMax
99
- ) {
134
+ // Compute AABB from flat vertices array [x,y,z, x,y,z, ...]
135
+ export function computeAABB(vertices) {
136
+ const min = [Infinity, Infinity, Infinity];
137
+ const max = [-Infinity, -Infinity, -Infinity];
138
+
139
+ for(let i = 0;i < vertices.length;i += 3) {
140
+ min[0] = Math.min(min[0], vertices[i]);
141
+ min[1] = Math.min(min[1], vertices[i + 1]);
142
+ min[2] = Math.min(min[2], vertices[i + 2]);
143
+
144
+ max[0] = Math.max(max[0], vertices[i]);
145
+ max[1] = Math.max(max[1], vertices[i + 1]);
146
+ max[2] = Math.max(max[2], vertices[i + 2]);
147
+ }
148
+
149
+ return [min, max];
150
+ }
151
+
152
+ // Ray-AABB intersection using slabs method
153
+ export function rayIntersectsAABB(rayOrigin, rayDirection, boxMin, boxMax) {
100
154
  let tmin = (boxMin[0] - rayOrigin[0]) / rayDirection[0];
101
155
  let tmax = (boxMax[0] - rayOrigin[0]) / rayDirection[0];
102
156
  if(tmin > tmax) [tmin, tmax] = [tmax, tmin];
@@ -105,7 +159,7 @@ export function rayIntersectsAABB(
105
159
  let tymax = (boxMax[1] - rayOrigin[1]) / rayDirection[1];
106
160
  if(tymin > tymax) [tymin, tymax] = [tymax, tymin];
107
161
 
108
- if(tmin > tymax || tymin > tmax) return false;
162
+ if((tmin > tymax) || (tymin > tmax)) return false;
109
163
  if(tymin > tmin) tmin = tymin;
110
164
  if(tymax < tmax) tmax = tymax;
111
165
 
@@ -113,54 +167,30 @@ export function rayIntersectsAABB(
113
167
  let tzmax = (boxMax[2] - rayOrigin[2]) / rayDirection[2];
114
168
  if(tzmin > tzmax) [tzmin, tzmax] = [tzmax, tzmin];
115
169
 
116
- if(tmin > tzmax || tzmin > tmax) return false;
170
+ if((tmin > tzmax) || (tzmin > tmax)) return false;
117
171
 
118
172
  return true;
119
173
  }
120
174
 
121
- export function computeAABBFromVertices(vertices) {
122
- const min = [Infinity, Infinity, Infinity];
123
- const max = [-Infinity, -Infinity, -Infinity];
124
-
125
- for(let i = 0;i < vertices.length;i += 3) {
126
- const x = vertices[i];
127
- const y = vertices[i + 1];
128
- const z = vertices[i + 2];
129
-
130
- min[0] = Math.min(min[0], x);
131
- min[1] = Math.min(min[1], y);
132
- min[2] = Math.min(min[2], z);
133
-
134
- max[0] = Math.max(max[0], x);
135
- max[1] = Math.max(max[1], y);
136
- max[2] = Math.max(max[2], z);
175
+ export function computeWorldVertsAndAABB(object) {
176
+ const modelMatrix = object.getModelMatrix(object.position);
177
+ const worldVerts = [];
178
+ for(let i = 0;i < object.mesh.vertices.length;i += 3) {
179
+ const local = vec3.fromValues(
180
+ object.mesh.vertices[i],
181
+ object.mesh.vertices[i + 1],
182
+ object.mesh.vertices[i + 2]
183
+ );
184
+ const world = vec3.transformMat4(local, modelMatrix); // OK
185
+ worldVerts.push(world[0], world[1], world[2]);
137
186
  }
138
-
139
- return [min, max];
140
- }
141
-
142
- export function computeWorldAABB(vertices, modelMatrix) {
143
- const min = [Infinity, Infinity, Infinity];
144
- const max = [-Infinity, -Infinity, -Infinity];
145
- const v = [0, 0, 0];
146
-
147
- for (let i = 0; i < vertices.length; i += 3) {
148
- v[0] = vertices[i];
149
- v[1] = vertices[i + 1];
150
- v[2] = vertices[i + 2];
151
-
152
- const worldV = vec3.transformMat4([], v, modelMatrix);
153
-
154
- min[0] = Math.min(min[0], worldV[0]);
155
- min[1] = Math.min(min[1], worldV[1]);
156
- min[2] = Math.min(min[2], worldV[2]);
157
-
158
- max[0] = Math.max(max[0], worldV[0]);
159
- max[1] = Math.max(max[1], worldV[1]);
160
- max[2] = Math.max(max[2], worldV[2]);
161
- }
162
-
163
- return [min, max];
187
+ const [boxMin, boxMax] = computeAABB(worldVerts);
188
+ return {
189
+ modelMatrix,
190
+ worldVerts,
191
+ boxMin,
192
+ boxMax,
193
+ };
164
194
  }
165
195
 
166
196
  export function addRaycastsAABBListener(canvasId = "canvas1") {
@@ -172,46 +202,18 @@ export function addRaycastsAABBListener(canvasId = "canvas1") {
172
202
 
173
203
  canvasDom.addEventListener('click', (event) => {
174
204
  const camera = app.cameras.WASD;
175
- const {rayOrigin, rayDirection} = getRayFromMouse(event, canvasDom, camera);
176
-
205
+ const {rayOrigin, rayDirection} = getRayFromMouse2(event, canvasDom, camera);
177
206
  for(const object of app.mainRenderBundle) {
178
- // Compute AABB min/max from object position and size
179
- const pos = [object.position.x,object.position.y,object.position.z]; // [x,y,z]
180
- // Works only for 0,0,0 static object
181
- // const [boxMinLocal, boxMaxLocal] = computeAABBFromVertices(object.mesh.vertices);
182
- const [boxMin, boxMax] = computeWorldAABB(object.mesh.vertices, object.viewMatrix);
183
- // Optionally transform to world space using object.position
184
- // const pos = object.position;
185
- // const boxMin = [
186
- // boxMinLocal[0] + pos[0],
187
- // boxMinLocal[1] + pos[1],
188
- // boxMinLocal[2] + pos[2]
189
- // ];
190
- // const boxMax = [
191
- // boxMaxLocal[0] + pos[0],
192
- // boxMaxLocal[1] + pos[1],
193
- // boxMaxLocal[2] + pos[2]
194
- // ];
195
- //////////////
196
- // const size = object.size || [1, 1, 1]; // Replace with actual object size or default 1x1x1
197
- // const boxMin = [
198
- // pos[0] - size[0] / 2,
199
- // pos[1] - size[1] / 2,
200
- // pos[2] - size[2] / 2
201
- // ];
202
- // const boxMax = [
203
- // pos[0] + size[0] / 2,
204
- // pos[1] + size[1] / 2,
205
- // pos[2] + size[2] / 2
206
- // ];
207
-
207
+ const {boxMin, boxMax} = computeWorldVertsAndAABB(object);
208
+ if(object.raycast.enabled == false) return;
208
209
  if(rayIntersectsAABB(rayOrigin, rayDirection, boxMin, boxMax)) {
209
- console.log('AABB hit:', object.name);
210
-
210
+ // console.log('AABB hit:', object.name);
211
211
  canvasDom.dispatchEvent(new CustomEvent('ray.hit.event', {
212
- detail: {hitObject: object}
212
+ detail: {hitObject: object},
213
+ rayOrigin: rayOrigin,
214
+ rayDirection: rayDirection
213
215
  }));
214
216
  }
215
217
  }
216
218
  });
217
- }
219
+ }