matrix-engine-wgpu 1.4.1 → 1.4.4

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 CHANGED
@@ -45,7 +45,9 @@ Published on npm as: **`matrix-engine-wgpu`**
45
45
  ```js
46
46
  app.mainRenderBundle[0];
47
47
  ```
48
- or
48
+
49
+ or
50
+
49
51
  ```js
50
52
  app.getSceneObjectByName("Sphere1");
51
53
  ```
@@ -154,17 +156,36 @@ SpotLight – Emits light in a cone shape with configurable cutoff angles.
154
156
 
155
157
  Features
156
158
 
157
- ✅ Supports multiple lights (4 max), ~20 for next update.
159
+ ✅ Supports multiple lights (4 max), ~20 for next update.
158
160
  ✅ Shadow-ready (spotlight0 shadows implemented, extendable to others)
159
161
 
160
- Required:
162
+ Important Required to be added manual:
163
+
161
164
  ```js
162
- engine.addLight()
165
+ engine.addLight();
163
166
  ```
164
167
 
165
168
  Access lights with array lightContainer:
169
+
166
170
  ```js
167
- app.lightContainer[0]
171
+ app.lightContainer[0];
172
+ ```
173
+
174
+ Small behavior object.
175
+ - For now just one ocs0 object
176
+ Everytime if called than updated (light.position[0] = light.behavior.setPath0())
177
+ behavior.setOsc0(min, max, step);
178
+ app.lightContainer[0].behavior.osc0.on_maximum_value = function() {/* what ever*/};
179
+ app.lightContainer[0].behavior.osc0.on_minimum_value = function() {/* what ever*/};
180
+
181
+ Make light move by x.
182
+ ```js
183
+ loadObjFile.addLight();
184
+ loadObjFile.lightContainer[0].behavior.setOsc0(-1, 1, 0.01);
185
+ loadObjFile.lightContainer[0].behavior.value_ = -1;
186
+ loadObjFile.lightContainer[0].updater.push(light => {
187
+ light.position[0] = light.behavior.setPath0();
188
+ });
168
189
  ```
169
190
 
170
191
  ### Object Interaction (Raycasting)
@@ -292,63 +313,65 @@ This example shows how to load and animate a sequence of .obj files to simulate
292
313
 
293
314
  ```js
294
315
  import MatrixEngineWGPU from "../src/world.js";
295
- import { downloadMeshes, makeObjSeqArg } from "../src/engine/loader-obj.js";
296
- import { LOG_MATRIX } from "../src/engine/utils.js";
316
+ import {downloadMeshes, makeObjSeqArg} from "../src/engine/loader-obj.js";
317
+ import {LOG_MATRIX} from "../src/engine/utils.js";
297
318
 
298
319
  export var loadObjsSequence = function () {
299
- let loadObjFile = new MatrixEngineWGPU({
300
- useSingleRenderPass: true,
301
- canvasSize: "fullscreen",
302
- mainCameraParams: {
303
- type: "WASD",
304
- responseCoef: 1000,
320
+ let loadObjFile = new MatrixEngineWGPU(
321
+ {
322
+ useSingleRenderPass: true,
323
+ canvasSize: "fullscreen",
324
+ mainCameraParams: {
325
+ type: "WASD",
326
+ responseCoef: 1000,
327
+ },
305
328
  },
306
- }, () => {
307
-
308
- addEventListener("AmmoReady", () => {
309
- downloadMeshes(
310
- makeObjSeqArg({
311
- id: "swat-walk-pistol",
312
- path: "res/meshes/objs-sequence/swat-walk-pistol",
313
- from: 1,
314
- to: 20,
315
- }),
316
- onLoadObj,
317
- { scale: [10, 10, 10] }
318
- );
319
- });
320
-
321
- function onLoadObj(m) {
322
- console.log(`%c Loaded objs: ${m} `, LOG_MATRIX);
323
- var objAnim = {
324
- id: "swat-walk-pistol",
325
- meshList: m,
326
- currentAni: 1,
327
- animations: {
328
- active: "walk",
329
- walk: { from: 1, to: 20, speed: 3 },
330
- walkPistol: { from: 36, to: 60, speed: 3 },
331
- },
332
- };
333
-
334
- loadObjFile.addMeshObj({
335
- position: { x: 0, y: 2, z: -10 },
336
- rotation: { x: 0, y: 0, z: 0 },
337
- rotationSpeed: { x: 0, y: 0, z: 0 },
338
- scale: [100, 100, 100],
339
- texturesPaths: ["./res/meshes/blender/cube.png"],
340
- name: "swat",
341
- mesh: m["swat-walk-pistol"],
342
- physics: {
343
- enabled: false,
344
- geometry: "Cube",
345
- },
346
- objAnim: objAnim,
329
+ () => {
330
+ addEventListener("AmmoReady", () => {
331
+ downloadMeshes(
332
+ makeObjSeqArg({
333
+ id: "swat-walk-pistol",
334
+ path: "res/meshes/objs-sequence/swat-walk-pistol",
335
+ from: 1,
336
+ to: 20,
337
+ }),
338
+ onLoadObj,
339
+ {scale: [10, 10, 10]}
340
+ );
347
341
  });
348
342
 
349
- app.mainRenderBundle[0].objAnim.play("walk");
343
+ function onLoadObj(m) {
344
+ console.log(`%c Loaded objs: ${m} `, LOG_MATRIX);
345
+ var objAnim = {
346
+ id: "swat-walk-pistol",
347
+ meshList: m,
348
+ currentAni: 1,
349
+ animations: {
350
+ active: "walk",
351
+ walk: {from: 1, to: 20, speed: 3},
352
+ walkPistol: {from: 36, to: 60, speed: 3},
353
+ },
354
+ };
355
+
356
+ loadObjFile.addMeshObj({
357
+ position: {x: 0, y: 2, z: -10},
358
+ rotation: {x: 0, y: 0, z: 0},
359
+ rotationSpeed: {x: 0, y: 0, z: 0},
360
+ scale: [100, 100, 100],
361
+ texturesPaths: ["./res/meshes/blender/cube.png"],
362
+ name: "swat",
363
+ mesh: m["swat-walk-pistol"],
364
+ physics: {
365
+ enabled: false,
366
+ geometry: "Cube",
367
+ },
368
+ objAnim: objAnim,
369
+ });
370
+
371
+ app.mainRenderBundle[0].objAnim.play("walk");
372
+ }
350
373
  }
351
- });
374
+ );
352
375
 
353
376
  window.app = loadObjFile;
354
377
  };
@@ -358,23 +381,23 @@ export var loadObjsSequence = function () {
358
381
 
359
382
  ```js
360
383
  TEST.loadVideoTexture({
361
- type: 'video', // video , camera //not tested yet canvas2d , canvas2dinline
362
- src: 'res/videos/tunel.mp4'
384
+ type: "video", // video , camera //not tested yet canvas2d , canvas2dinline
385
+ src: "res/videos/tunel.mp4",
363
386
  });
364
387
  ```
365
388
 
366
389
  For canvasinline attach this to arg (example for direct draw on canvas2d and passing intro webgpu pipeline):
390
+
367
391
  ```js
368
392
  canvaInlineProgram: (ctx, canvas) => {
369
- ctx.fillStyle = 'black';
393
+ ctx.fillStyle = "black";
370
394
  ctx.fillRect(0, 0, canvas.width, canvas.height);
371
- ctx.fillStyle = 'white';
372
- ctx.font = '20px Orbitron';
395
+ ctx.fillStyle = "white";
396
+ ctx.font = "20px Orbitron";
373
397
  ctx.fillText(`FPS: ${Math.round(performance.now() % 60)}`, 10, 30);
374
- }
398
+ };
375
399
  ```
376
400
 
377
-
378
401
  <pre>
379
402
  | Scenario | Best Approach |
380
403
  | ------------------------------ | ---------------------------------- |
@@ -384,6 +407,7 @@ canvaInlineProgram: (ctx, canvas) => {
384
407
  </pre>
385
408
 
386
409
  ### Note
410
+
387
411
  If this happen less then 15 times (Loading procces) then it is ok probably...
388
412
 
389
413
  ```json
@@ -394,11 +418,11 @@ Draw func (err):TypeError: Failed to execute 'beginRenderPass' on 'GPUCommandEnc
394
418
 
395
419
  It is possible for 1 or 2 warn in middle time when mesh switch to the videoTexture.
396
420
  Will be fixxed in next update.
421
+
397
422
  ```js
398
423
  Dimension (TextureViewDimension::e2DArray) of [TextureView of Texture "shadowTextureArray[GLOBAL] num of light 1"] doesn't match the expected dimension (TextureViewDimension::e2D).
399
424
  ```
400
425
 
401
-
402
426
  ## About URLParams
403
427
 
404
428
  Buildin Url Param check for multiLang.
@@ -0,0 +1,35 @@
1
+ import {OSCILLATOR} from "./utils";
2
+
3
+ /**
4
+ * @description
5
+ * Can be reuse for any other tasks.
6
+ * @author Nikola Lukic
7
+ */
8
+
9
+ export default class Behavior {
10
+
11
+ status = "Only oscillator";
12
+
13
+ constructor() {
14
+ this.osc0 = new OSCILLATOR(0, 5, 0.01);
15
+ }
16
+
17
+ setOsc0(min,max, step){
18
+ this.osc0.min =min;
19
+ this.osc0.max =max;
20
+ this.osc0.step =step;
21
+ }
22
+
23
+ // apend - keep init origin
24
+ addPath(NUMBER) {
25
+ let inc = this.osc0.UPDATE();
26
+ console.log('test inc' ,inc)
27
+ console.log('test inc + number' ,(NUMBER + inc))
28
+ return (inc + NUMBER);
29
+ }
30
+
31
+ setPath0() {
32
+ return this.osc0.UPDATE();
33
+ }
34
+
35
+ }
@@ -1,5 +1,7 @@
1
1
  import {mat4, vec3} from 'wgpu-matrix';
2
2
  import {vertexShadowWGSL} from '../shaders/vertexShadow.wgsl';
3
+ import Behavior from './behavior';
4
+
3
5
  /**
4
6
  * @description
5
7
  * Spot light with shodow cast.
@@ -209,10 +211,16 @@ export class SpotLight {
209
211
  });
210
212
  return this.mainPassBindGroupContainer[index];
211
213
  }
214
+
215
+ // Only osc values +-
216
+ this.behavior = new Behavior();
217
+
218
+ // put here only func
219
+ this.updater = [];
212
220
  }
213
221
 
214
222
  update() {
215
- // this.target = vec3.create(x, y, z); // new target
223
+ this.updater.forEach((update) => {update(this)})
216
224
  this.direction = vec3.normalize(vec3.subtract(this.target, this.position));
217
225
  const target = vec3.add(this.position, this.direction);
218
226
  this.viewMatrix = mat4.lookAt(this.position, target, this.up);
@@ -8,7 +8,7 @@ import Materials from './materials';
8
8
  import {fragmentVideoWGSL} from '../shaders/fragment.video.wgsl';
9
9
 
10
10
  export default class MEMeshObj extends Materials {
11
- constructor(canvas, device, context, o, inputHandler) {
11
+ constructor(canvas, device, context, o, inputHandler, globalAmbient) {
12
12
  super(device);
13
13
  if(typeof o.name === 'undefined') o.name = genName(3);
14
14
  if(typeof o.raycast === 'undefined') {
@@ -24,6 +24,7 @@ export default class MEMeshObj extends Materials {
24
24
  this.clearColor = "red";
25
25
  this.video = null;
26
26
  this.FINISH_VIDIO_INIT = false;
27
+ this.globalAmbient = globalAmbient;
27
28
 
28
29
  // Mesh stuff - for single mesh or t-posed (fiktive-first in loading order)
29
30
  this.mesh = o.mesh;
@@ -184,7 +185,7 @@ export default class MEMeshObj extends Materials {
184
185
 
185
186
  this.sceneUniformBuffer = this.device.createBuffer({
186
187
  label: 'sceneUniformBuffer per mesh',
187
- size: 160,
188
+ size: 176,
188
189
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
189
190
  });
190
191
 
@@ -222,7 +223,7 @@ export default class MEMeshObj extends Materials {
222
223
  ],
223
224
  });
224
225
 
225
-
226
+
226
227
 
227
228
  // Rotates the camera around the origin based on time.
228
229
  this.getTransformationMatrix = (mainRenderBundle, spotLight) => {
@@ -235,23 +236,31 @@ export default class MEMeshObj extends Materials {
235
236
  const camVP = mat4.multiply(camera.projectionMatrix, camera.view);
236
237
 
237
238
  for(const mesh of mainRenderBundle) {
238
- // Flattened buffer: lightVP(16) + camVP(16) + cameraPos(3+pad) + lightPos(3+pad)
239
- const sceneData = new Float32Array(16 + 16 + 4 + 4); // 16+16+4+4 = 40 floats
239
+ const sceneData = new Float32Array(44);
240
240
 
241
- // Light ViewProj
241
+ // Light VP
242
242
  sceneData.set(spotLight.viewProjMatrix, 0);
243
243
 
244
244
  // Camera VP
245
245
  sceneData.set(camVP, 16);
246
246
 
247
247
  // Camera position + padding
248
- sceneData.set([camera.position.x, camera.position.y, camera.position.z, 0.0], 32);
248
+ sceneData.set(
249
+ [camera.position.x, camera.position.y, camera.position.z, 0.0],
250
+ 32
251
+ );
249
252
 
250
253
  // Light position + padding
251
- sceneData.set([spotLight.position[0], spotLight.position[1], spotLight.position[2], 0.0], 36);
254
+ sceneData.set(
255
+ [spotLight.position[0], spotLight.position[1], spotLight.position[2], 0.0],
256
+ 36
257
+ );
258
+
259
+ // Global ambient + padding
260
+ sceneData.set([this.globalAmbient[0], this.globalAmbient[1], this.globalAmbient[2], 0.0], 40);
252
261
 
253
262
  device.queue.writeBuffer(
254
- mesh.sceneUniformBuffer, // or shared buffer
263
+ mesh.sceneUniformBuffer,
255
264
  0,
256
265
  sceneData.buffer,
257
266
  sceneData.byteOffset,
@@ -460,15 +460,7 @@ export function OSCILLATOR(min, max, step) {
460
460
  }
461
461
  };
462
462
  } else {
463
- console.log(
464
- "SYS : warning for procedure 'SYS.MATH.OSCILLATOR' Desciption : Replace object with string or number, min >> " +
465
- typeof min +
466
- ' and max >>' +
467
- typeof max +
468
- ' and step >>' +
469
- typeof step +
470
- ' << must be string or number.'
471
- );
463
+ console.log("OSCILLATOR ERROR");
472
464
  }
473
465
  }
474
466
 
@@ -9,6 +9,8 @@ struct Scene {
9
9
  padding2 : f32, // align to 16 bytes
10
10
  lightPos : vec3f,
11
11
  padding : f32, // align to 16 bytes
12
+ globalAmbient : vec3f, // <--- new
13
+ padding3 : f32, // keep alignment (16 bytes)
12
14
  };
13
15
 
14
16
  struct SpotLight {
@@ -114,7 +116,7 @@ fn main(input: FragmentInput) -> @location(0) vec4f {
114
116
  // let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
115
117
 
116
118
  var lightContribution = vec3f(0.0);
117
- var ambient = vec3f(0.0);
119
+ var ambient = vec3f(0.5);
118
120
 
119
121
  for (var i: u32 = 0u; i < MAX_SPOTLIGHTS; i = i + 1u) {
120
122
  let sc = spotlights[i].lightViewProj * vec4<f32>(input.fragPos, 1.0);
@@ -128,10 +130,10 @@ fn main(input: FragmentInput) -> @location(0) vec4f {
128
130
  let visibility = sampleShadow(uv, i32(i), depthRef - bias, norm, lightDir);
129
131
  let contrib = computeSpotLight(spotlights[i], norm, input.fragPos, viewDir);
130
132
  lightContribution += contrib * visibility;
131
- ambient += spotlights[i].ambientFactor * spotlights[i].color;
133
+ // ambient += spotlights[i].ambientFactor * spotlights[i].color;
132
134
  }
133
-
135
+ // ambient /= f32(MAX_SPOTLIGHTS); PREVENT OVER NEXT FEATURE ON SWICHER
134
136
  let texColor = textureSample(meshTexture, meshSampler, input.uv);
135
- let finalColor = texColor.rgb * (ambient + lightContribution); // * albedo;
137
+ let finalColor = texColor.rgb * (scene.globalAmbient + lightContribution); // * albedo;
136
138
  return vec4f(finalColor, 1.0);
137
139
  }`;
package/src/world.js CHANGED
@@ -127,6 +127,7 @@ export default class MatrixEngineWGPU {
127
127
  this.frame = this.framePassPerObject;
128
128
  }
129
129
 
130
+ this.globalAmbient = vec3.create(0.5, 0.5, 0.5);
130
131
  this.MAX_SPOTLIGHTS = 20;
131
132
  this.inputHandler = createInputHandler(window, canvas);
132
133
  this.createGlobalStuff();
@@ -379,7 +380,7 @@ export default class MatrixEngineWGPU {
379
380
  }
380
381
  }
381
382
  }
382
- let myMesh1 = new MEMeshObj(this.canvas, this.device, this.context, o, this.inputHandler);
383
+ let myMesh1 = new MEMeshObj(this.canvas, this.device, this.context, o, this.inputHandler, this.globalAmbient);
383
384
  myMesh1.spotlightUniformBuffer = this.spotlightUniformBuffer;
384
385
  myMesh1.clearColor = clearColor;
385
386
  if(o.physics.enabled == true) {
@@ -447,20 +448,16 @@ export default class MatrixEngineWGPU {
447
448
  // 1️⃣ Update light data (position, direction, uniforms)
448
449
  for(const light of this.lightContainer) {
449
450
  light.update()
450
- // light.updateSceneUniforms(this.mainRenderBundle, this.cameras.WASD);
451
451
  this.mainRenderBundle.forEach((meItem, index) => {
452
452
  meItem.position.update()
453
453
  meItem.updateModelUniformBuffer()
454
- // if(meItem.isVideo != true) {
455
454
  meItem.getTransformationMatrix(this.mainRenderBundle, light)
456
- // }
457
455
  })
458
456
  }
459
457
  if(this.matrixAmmo) this.matrixAmmo.updatePhysics();
460
458
 
461
459
  for(let i = 0;i < this.lightContainer.length;i++) {
462
460
  const light = this.lightContainer[i];
463
-
464
461
  let ViewPerLightRenderShadowPass = this.shadowTextureArray.createView({
465
462
  dimension: '2d',
466
463
  baseArrayLayer: i,
@@ -499,30 +496,24 @@ export default class MatrixEngineWGPU {
499
496
  if(!mesh.sceneBindGroupForRender || (mesh.FINISH_VIDIO_INIT == false && mesh.isVideo == true)) {
500
497
  for(const m of this.mainRenderBundle) {
501
498
  if(m.isVideo == true) {
502
- console.log('✅✅✅ set shadowVideoView', this.shadowVideoView)
499
+ console.log('shadowVideoView', this.shadowVideoView)
503
500
  m.shadowDepthTextureView = this.shadowVideoView;
504
501
  m.FINISH_VIDIO_INIT = true;
505
502
  m.setupPipeline();
506
503
  } else {
507
- console.log('✅ NORMAL shadowArrayView')
508
504
  m.shadowDepthTextureView = this.shadowArrayView;
505
+ m.setupPipeline();
509
506
  }
510
507
  }
511
508
  }
512
509
  mesh.drawElements(pass, this.lightContainer);
513
510
  }
514
-
515
- // End render pass
516
511
  pass.end();
517
512
  this.device.queue.submit([commandEncoder.finish()]);
518
513
  requestAnimationFrame(this.frame);
519
514
  } catch(err) {
520
515
  console.log('%cLoop(err):' + err, LOG_WARN)
521
- // if(pass) pass.end();
522
- // this.device.queue.submit([commandEncoder.finish()]);
523
516
  requestAnimationFrame(this.frame);
524
- } finally {
525
- //requestAnimationFrame(this.frame);
526
517
  }
527
518
  }
528
519