matrix-engine-wgpu 1.3.19 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/readme.md CHANGED
@@ -162,7 +162,7 @@ Features
162
162
 
163
163
  ✅ Supports multiple lights (attach as many as you want to the scene)
164
164
 
165
- ✅ Shadow-ready (spotlight shadows implemented, extendable to others)
165
+ ✅ Shadow-ready (spotlight0 shadows implemented, extendable to others)
166
166
 
167
167
 
168
168
  ### Object Interaction (Raycasting)
@@ -30,11 +30,7 @@ export class SpotLight {
30
30
  inputHandler,
31
31
  position = vec3.create(0, 5, -10),
32
32
  target = vec3.create(0, 0, 0),
33
- fov = 45,
34
- aspect = 1.0,
35
- near = 0.1,
36
- far = 200
37
- ) {
33
+ fov = 45, aspect = 1.0, near = 0.1, far = 200) {
38
34
  this.camera = camera;
39
35
  this.inputHandler = inputHandler;
40
36
 
@@ -42,6 +38,8 @@ export class SpotLight {
42
38
  this.target = target;
43
39
  this.up = vec3.create(0, 1, 0);
44
40
  this.direction = vec3.normalize(vec3.subtract(target, position));
41
+ this.intensity = 1.0;
42
+ this.color = vec3.create(1.0, 1.0, 1.0); // white
45
43
 
46
44
  this.viewMatrix = mat4.lookAt(position, target, this.up);
47
45
  this.projectionMatrix = mat4.perspective(
@@ -59,14 +57,12 @@ export class SpotLight {
59
57
 
60
58
  this.innerCutoff = Math.cos((Math.PI / 180) * 12.5);
61
59
  this.outerCutoff = Math.cos((Math.PI / 180) * 17.5);
60
+
61
+ this.ambientFactor = 0.5;
62
+ this.range = 200.0; // example max distance
62
63
  }
63
64
 
64
65
  update() {
65
- // this.direction = vec3.normalize(vec3.subtract(this.target, this.position));
66
- // this.viewMatrix = mat4.lookAt(this.position, this.target, this.up);
67
- // this.viewProjMatrix = mat4.multiply(this.projectionMatrix, this.viewMatrix);
68
- // console.log('test light update this.target : ', this.target)
69
- // Use the existing direction
70
66
  const target = vec3.add(this.position, this.direction);
71
67
  this.viewMatrix = mat4.lookAt(this.position, target, this.up);
72
68
  this.viewProjMatrix = mat4.multiply(this.projectionMatrix, this.viewMatrix);
@@ -92,29 +88,14 @@ export class SpotLight {
92
88
  camVP.byteLength
93
89
  );
94
90
  }
95
- // const camVP = mat4.multiply(camera.projectionMatrix, camera.view);
96
- // const sceneData = new Float32Array(36); // 16 + 16 + 4
97
- // sceneData.set(this.viewProjMatrix, 0);
98
- // sceneData.set(camVP, 16);
99
- // sceneData.set(this.position, 32);
100
- // if(!this.device) {
101
- // console.warn("Device not set for SpotLight");
102
- // return;
103
- // }
104
- // this.device.queue.writeBuffer(
105
- // sceneUniformBuffer,
106
- // // this.spotlightUniformBuffer,
107
- // 0,
108
- // sceneData.buffer,
109
- // sceneData.byteOffset,
110
- // sceneData.byteLength
111
- // );
112
91
  }
113
92
 
93
+ // DEPLACED
114
94
  prepareBuffer(device) {
115
95
  if(!this.device) this.device = device;
116
96
  this.spotlightUniformBuffer = this.device.createBuffer({
117
- size: 16 * 4, // 64 bytes
97
+ label: 'spotlightUniformBuffer',
98
+ size: 80,
118
99
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
119
100
  });
120
101
 
@@ -128,6 +109,7 @@ export class SpotLight {
128
109
  );
129
110
  }
130
111
 
112
+ // DEPLACED
131
113
  updateLightBuffer() {
132
114
  if(!this.device || !this.spotlightUniformBuffer) {return;}
133
115
  const spotlightData = this.getLightDataBuffer();
@@ -141,13 +123,18 @@ export class SpotLight {
141
123
  }
142
124
 
143
125
  getLightDataBuffer() {
144
- return new Float32Array([
145
- ...this.position, 0.0,
146
- ...this.direction, 0.0,
147
- this.innerCutoff,
148
- this.outerCutoff,
149
- 0.0,
150
- 0.0,
151
- ]);
126
+ return new Float32Array([
127
+ ...this.position, 0.0,
128
+ ...this.direction, 0.0,
129
+ this.innerCutoff,
130
+ this.outerCutoff,
131
+ this.intensity,
132
+ 0.0,
133
+ ...this.color,
134
+ 0.0,
135
+ this.range,
136
+ this.ambientFactor, // new
137
+ 0.0, 0.0, // padding
138
+ ]);
152
139
  }
153
140
  }
@@ -30,10 +30,10 @@ export default class Materials {
30
30
 
31
31
  // Dymmy buffer
32
32
  this.dummySpotlightUniformBuffer = this.device.createBuffer({
33
- size: 64, // Must match size in shader
33
+ size: 80, // Must match size in shader
34
34
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
35
35
  });
36
- this.device.queue.writeBuffer(this.dummySpotlightUniformBuffer, 0, new Float32Array(16));
36
+ this.device.queue.writeBuffer(this.dummySpotlightUniformBuffer, 0, new Float32Array(16));
37
37
  }
38
38
 
39
39
  updatePostFXMode(mode) {
@@ -155,7 +155,7 @@ export default class Materials {
155
155
  // ✅ Now
156
156
  this.createLayoutForRender();
157
157
  this.setupPipeline();
158
- setTimeout(() => this.createBindGroupForRender(), 1500);
158
+
159
159
  }
160
160
 
161
161
  updateVideoTexture() {
@@ -172,7 +172,6 @@ export default class Materials {
172
172
  console.warn("❗Missing res skipping...");
173
173
  return;
174
174
  }
175
- // console.log('what is this.lightContainer.length ', this.lightContainer.length)
176
175
  if(this.isVideo == true) {
177
176
  this.sceneBindGroupForRender = this.device.createBindGroup({
178
177
  layout: this.bglForRender,
@@ -226,8 +225,8 @@ export default class Materials {
226
225
  },
227
226
  {
228
227
  binding: 5,
229
- resource: {buffer: this.lightContainer.length == 0 ? this.dummySpotlightUniformBuffer : this.lightContainer[0].spotlightUniformBuffer},
230
- },
228
+ resource: {buffer: !this.spotlightUniformBuffer ? this.dummySpotlightUniformBuffer : this.spotlightUniformBuffer},
229
+ }
231
230
  ],
232
231
  });
233
232
  }
@@ -10,16 +10,12 @@ import {fragmentVideoWGSL} from '../shaders/fragment.video.wgsl';
10
10
  export default class MEMeshObj extends Materials {
11
11
  constructor(canvas, device, context, o, sceneUniformBuffer) {
12
12
  super(device);
13
- if(typeof o.name === 'undefined') o.name = genName(9);
13
+ if(typeof o.name === 'undefined') o.name = genName(3);
14
14
  if(typeof o.raycast === 'undefined') {
15
- this.raycast = {
16
- enabled: false,
17
- radius: 2
18
- };
15
+ this.raycast = {enabled: false, radius: 2};
19
16
  } else {
20
17
  this.raycast = o.raycast;
21
18
  }
22
-
23
19
  this.name = o.name;
24
20
  this.done = false;
25
21
  this.device = device;
@@ -45,7 +41,6 @@ export default class MEMeshObj extends Materials {
45
41
 
46
42
  this.inputHandler = null;
47
43
  this.cameras = o.cameras;
48
-
49
44
  this.mainCameraParams = {
50
45
  type: o.mainCameraParams.type,
51
46
  responseCoef: o.mainCameraParams.responseCoef
@@ -65,7 +60,6 @@ export default class MEMeshObj extends Materials {
65
60
  this.runProgram = () => {
66
61
  return new Promise(async (resolve) => {
67
62
  this.shadowDepthTextureSize = 1024;
68
- // const aspect = canvas.width / canvas.height;
69
63
  this.modelViewProjectionMatrix = mat4.create();
70
64
  this.loadTex0(this.texturesPaths).then(() => {
71
65
  resolve()
@@ -74,7 +68,6 @@ export default class MEMeshObj extends Materials {
74
68
  }
75
69
 
76
70
  this.runProgram().then(() => {
77
- // const aspect = canvas.width / canvas.height;
78
71
  this.context.configure({
79
72
  device: this.device,
80
73
  format: this.presentationFormat,
@@ -395,20 +388,21 @@ export default class MEMeshObj extends Materials {
395
388
  }
396
389
 
397
390
  setupPipeline = () => {
398
- console.log('test >>>>>>>>>>>>>>>>>>>FORMAT>✅' + this.presentationFormat);
391
+ console.log('Set Pipeline✅');
399
392
  this.pipeline = this.device.createRenderPipeline({
393
+ label: 'Mesh Pipeline ✅',
400
394
  layout: this.device.createPipelineLayout({
401
395
  bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout],
402
396
  }),
403
397
  vertex: {
404
- entryPoint: 'main', // ✅ Add this
398
+ entryPoint: 'main',
405
399
  module: this.device.createShaderModule({
406
400
  code: vertexWGSL,
407
401
  }),
408
402
  buffers: this.vertexBuffers,
409
403
  },
410
404
  fragment: {
411
- entryPoint: 'main', // ✅ Add this
405
+ entryPoint: 'main',
412
406
  module: this.device.createShaderModule({
413
407
  code: (this.isVideo == true ? fragmentVideoWGSL : fragmentWGSL),
414
408
  }),
@@ -424,7 +418,6 @@ export default class MEMeshObj extends Materials {
424
418
  depthStencil: {
425
419
  depthWriteEnabled: true,
426
420
  depthCompare: 'less',
427
- // format: 'depth24plus-stencil8',
428
421
  format: 'depth24plus',
429
422
  },
430
423
  primitive: this.primitive,
@@ -432,17 +425,7 @@ export default class MEMeshObj extends Materials {
432
425
  }
433
426
 
434
427
  draw = () => {
435
- // This code -> light follow camera. can be used like options later!
436
- // if(this.done == false) return;
437
- // const transformationMatrix = this.getTransformationMatrix(this.position);
438
- // this.device.queue.writeBuffer(this.sceneUniformBuffer, 64, transformationMatrix.buffer, transformationMatrix.byteOffset, transformationMatrix.byteLength);
439
- // this.renderPassDescriptor.colorAttachments[0].view = this.context
440
- // .getCurrentTexture()
441
- // .createView();
442
-
443
- // test
444
428
  if(this.done == false) return;
445
-
446
429
  // Per-object model matrix only
447
430
  const modelMatrix = this.getModelMatrix(this.position);
448
431
  this.device.queue.writeBuffer(
@@ -452,7 +435,6 @@ export default class MEMeshObj extends Materials {
452
435
  modelMatrix.byteOffset,
453
436
  modelMatrix.byteLength
454
437
  );
455
-
456
438
  // Acquire swapchain view for the pass
457
439
  this.renderPassDescriptor.colorAttachments[0].view =
458
440
  this.context.getCurrentTexture().createView();
@@ -516,7 +498,6 @@ export default class MEMeshObj extends Materials {
516
498
  });
517
499
  new Float32Array(mesh.vertexNormalsBuffer.getMappedRange()).set(mesh.vertexNormals);
518
500
  mesh.vertexNormalsBuffer.unmap();
519
-
520
501
  // UVs
521
502
  mesh.vertexTexCoordsBuffer = this.device.createBuffer({
522
503
  size: mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
@@ -525,7 +506,6 @@ export default class MEMeshObj extends Materials {
525
506
  });
526
507
  new Float32Array(mesh.vertexTexCoordsBuffer.getMappedRange()).set(mesh.textures);
527
508
  mesh.vertexTexCoordsBuffer.unmap();
528
-
529
509
  // Indices
530
510
  const indexCount = mesh.indices.length;
531
511
  const indexSize = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
@@ -76,7 +76,6 @@ export default class MatrixAmmo {
76
76
  }
77
77
 
78
78
  let Ammo = this.Ammo;
79
- console.log(pOptions.radius + "<<pOptions.radius")
80
79
  var colShape = new Ammo.btSphereShape(Array.isArray(pOptions.radius) ? pOptions.radius[0] : pOptions.radius),
81
80
  startTransform = new Ammo.btTransform();
82
81
  startTransform.setIdentity();
@@ -234,10 +233,8 @@ export default class MatrixAmmo {
234
233
  return;
235
234
  this.lastRoll = '';
236
235
  this.presentScore = '';
237
-
238
236
  let dispatcher = this.dynamicsWorld.getDispatcher();
239
237
  let numManifolds = dispatcher.getNumManifolds();
240
-
241
238
  for(let i = 0;i < numManifolds;i++) {
242
239
  let contactManifold = dispatcher.getManifoldByIndexInternal(i);
243
240
  // let numContacts = contactManifold.getNumContacts();
@@ -245,51 +242,12 @@ export default class MatrixAmmo {
245
242
  // if(item.kB == contactManifold.getBody0().kB) {
246
243
  // // console.log('Detected body0 =', item.name)
247
244
  // }
248
- // if(item.kB == contactManifold.getBody1().kB) {
249
- // // console.log('Detected body1 =', item.name)
250
- // }
251
- // })
252
-
253
245
  if(this.ground.kB == contactManifold.getBody0().kB &&
254
246
  this.getNameByBody(contactManifold.getBody1()) == 'CubePhysics1') {
255
247
  // console.log(this.ground ,'GROUND IS IN CONTACT WHO IS BODY1 ', contactManifold.getBody1())
256
248
  // console.log('GROUND IS IN CONTACT WHO IS BODY1 getNameByBody ', this.getNameByBody(contactManifold.getBody1()))
257
249
  // CHECK ROTATION
258
250
  var testR = contactManifold.getBody1().getWorldTransform().getRotation();
259
- if(Math.abs(testR.y()) < 0.00001) {
260
- this.lastRoll += " 4 +";
261
- this.presentScore += 4;
262
- dispatchEvent(new CustomEvent('dice-1', {}));
263
- }
264
- if(Math.abs(testR.x()) < 0.00001) {
265
- this.lastRoll += " 3 +";
266
- this.presentScore += 3;
267
- dispatchEvent(new CustomEvent('dice-4', {}));
268
- }
269
- if(testR.x().toString().substring(0, 5) == testR.y().toString().substring(1, 6)) {
270
- this.lastRoll += " 2 +";
271
- this.presentScore += 2;
272
- dispatchEvent(new CustomEvent('dice-6', {}));
273
- }
274
-
275
- if(testR.x().toString().substring(0, 5) == testR.y().toString().substring(0, 5)) {
276
- this.lastRoll += " 1 +";
277
- this.presentScore += 1;
278
- dispatchEvent(new CustomEvent('dice-2', {}));
279
- }
280
-
281
- if(testR.z().toString().substring(0, 5) == testR.y().toString().substring(1, 6)) {
282
- this.lastRoll += " 6 +";
283
- this.presentScore += 6;
284
- dispatchEvent(new CustomEvent('dice-5', {}));
285
- }
286
-
287
- if(testR.z().toString().substring(0, 5) == testR.y().toString().substring(0, 5)) {
288
- this.lastRoll += " 5 +";
289
- this.presentScore += 5;
290
- dispatchEvent(new CustomEvent('dice-3', {}));
291
- }
292
-
293
251
  console.log('this.lastRoll = ', this.lastRoll, ' presentScore = ', this.presentScore)
294
252
  }
295
253
  }
@@ -1,75 +1,107 @@
1
1
  export let fragmentWGSL = `override shadowDepthTextureSize: f32 = 1024.0;
2
2
 
3
3
  struct Scene {
4
- lightViewProjMatrix : mat4x4f,
5
- cameraViewProjMatrix : mat4x4f,
6
- lightPos : vec3f,
7
- padding : f32, // Required for alignment
4
+ lightViewProjMatrix : mat4x4f,
5
+ cameraViewProjMatrix : mat4x4f,
6
+ lightPos : vec3f,
7
+ padding : f32, // Required for alignment
8
8
  }
9
9
 
10
10
  struct SpotLight {
11
- position: vec3f,
12
- _pad1: f32,
13
- direction: vec3f,
14
- _pad2: f32,
15
- innerCutoff: f32,
16
- outerCutoff: f32,
17
- _pad3: vec2f,
18
- }
11
+ position : vec3f,
12
+ _pad1 : f32,
13
+
14
+ direction : vec3f,
15
+ _pad2 : f32,
16
+
17
+ innerCutoff : f32,
18
+ outerCutoff : f32,
19
+ intensity : f32,
20
+ _pad3 : f32,
21
+
22
+ color : vec3f,
23
+ _pad4 : f32,
24
+
25
+ range : f32,
26
+ ambientFactor: f32, // new
27
+ _pad5 : vec2f, // padding to align to 16 bytes
28
+ };
29
+
30
+ const MAX_SPOTLIGHTS = 20u; // adjust as needed
19
31
 
20
32
  @group(0) @binding(0) var<uniform> scene : Scene;
21
33
  @group(0) @binding(1) var shadowMap: texture_depth_2d;
22
34
  @group(0) @binding(2) var shadowSampler: sampler_comparison;
23
35
  @group(0) @binding(3) var meshTexture: texture_2d<f32>;
24
36
  @group(0) @binding(4) var meshSampler: sampler;
25
- @group(0) @binding(5) var<uniform> spotlight: SpotLight;
37
+ @group(0) @binding(5) var<uniform> spotlights: array<SpotLight, MAX_SPOTLIGHTS>;
38
+ // @group(0) @binding(6) var<uniform> spotlight1: SpotLight;
26
39
 
27
40
  struct FragmentInput {
28
- @location(0) shadowPos : vec3f,
29
- @location(1) fragPos : vec3f,
30
- @location(2) fragNorm : vec3f,
31
- @location(3) uv : vec2f,
41
+ @location(0) shadowPos : vec3f,
42
+ @location(1) fragPos : vec3f,
43
+ @location(2) fragNorm : vec3f,
44
+ @location(3) uv : vec2f,
32
45
  }
33
46
 
34
47
  const albedo = vec3f(0.9);
35
- const ambientFactor = 0.7;
48
+ // const ambientFactor = 0.7;
36
49
 
37
50
  fn calculateSpotlightFactor(light: SpotLight, fragPos: vec3f) -> f32 {
38
- let L = normalize(light.position - fragPos);
39
- let theta = dot(L, normalize(-light.direction));
40
- let epsilon = light.innerCutoff - light.outerCutoff;
41
- let intensity = clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
42
- return intensity;
51
+ let L = normalize(light.position - fragPos);
52
+ let theta = dot(L, normalize(-light.direction));
53
+ let epsilon = light.innerCutoff - light.outerCutoff;
54
+ return clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
55
+ }
56
+
57
+ fn computeSpotLight(light: SpotLight, normal: vec3f, fragPos: vec3f, viewDir: vec3f) -> vec3f {
58
+ let L = light.position - fragPos;
59
+ let distance = length(L);
60
+ let lightDir = normalize(L);
61
+
62
+ let spotFactor = calculateSpotlightFactor(light, fragPos);
63
+ let atten = clamp(1.0 - (distance / light.range), 0.0, 1.0);
64
+
65
+ let diff = max(dot(normal, lightDir), 0.0);
66
+ let halfwayDir = normalize(lightDir + viewDir);
67
+ let spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
68
+
69
+ let diffuse = diff * light.color * light.intensity * atten;
70
+ let specular = spec * light.color * light.intensity * atten;
71
+
72
+ return (diffuse + specular) * spotFactor;
43
73
  }
44
74
 
45
75
  @fragment
46
76
  fn main(input : FragmentInput) -> @location(0) vec4f {
47
- // Shadow PFC
48
- var visibility = 0.0;
49
- let oneOverSize = 1.0 / shadowDepthTextureSize;
50
- for (var y = -1; y <= 1; y++) {
51
- for (var x = -1; x <= 1; x++) {
52
- let offset = vec2f(vec2(x, y)) * oneOverSize;
53
- visibility += textureSampleCompare(
54
- shadowMap, shadowSampler,
55
- input.shadowPos.xy + offset, input.shadowPos.z - 0.007
56
- );
77
+ // Shadow PCF
78
+ var visibility = 0.0;
79
+ let oneOverSize = 1.0 / shadowDepthTextureSize;
80
+ for (var y = -1; y <= 1; y++) {
81
+ for (var x = -1; x <= 1; x++) {
82
+ let offset = vec2f(vec2(x, y)) * oneOverSize;
83
+ visibility += textureSampleCompare(
84
+ shadowMap, shadowSampler,
85
+ input.shadowPos.xy + offset, input.shadowPos.z - 0.007
86
+ );
87
+ }
57
88
  }
58
- }
59
- visibility /= 9.0;
89
+ visibility /= 9.0;
90
+ let norm = normalize(input.fragNorm);
91
+ let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
60
92
 
61
- // Lambert
62
- let norm = normalize(input.fragNorm);
63
- let lightDir = normalize(scene.lightPos - input.fragPos);
64
- let lambert = max(dot(norm, lightDir), 0.0);
93
+ // Spotlight contribution (diffuse + specular + cone + distance)
94
+ var lightContribution = vec3f(0.0);
95
+ var ambient = vec3f(0.0);
65
96
 
66
- // Spotlight effect
67
- let spotlightFactor = calculateSpotlightFactor(spotlight, input.fragPos);
97
+ for (var i = 0u; i < MAX_SPOTLIGHTS; i++) {
98
+ lightContribution += computeSpotLight(spotlights[i], norm, input.fragPos, viewDir);
99
+ ambient += spotlights[i].ambientFactor * spotlights[i].color;
100
+ }
68
101
 
69
- // Combine
70
- let lightIntensity = ambientFactor + lambert * visibility * spotlightFactor;
71
- let texColor = textureSample(meshTexture, meshSampler, input.uv);
102
+ let texColor = textureSample(meshTexture, meshSampler, input.uv);
103
+ let finalColor = texColor.rgb * (ambient + lightContribution * visibility) * albedo;
72
104
 
73
- return vec4f(texColor.rgb * lightIntensity * albedo, 1.0);
105
+ return vec4f(finalColor, 1.0);
74
106
  }
75
107
  `