matrix-engine-wgpu 1.0.6 → 1.1.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.
Files changed (69) hide show
  1. package/.codesandbox/tasks.json +46 -0
  2. package/.devcontainer/devcontainer.json +22 -0
  3. package/.github/dependabot.yml +12 -0
  4. package/REFERENCE.md +3 -5
  5. package/dev.md +460 -0
  6. package/empty.js +7 -6
  7. package/examples/games/jamb/jamb.js +1127 -0
  8. package/examples/load-obj-file.js +65 -28
  9. package/examples/unlit-textures.js +26 -23
  10. package/examples.js +35 -3
  11. package/main.js +442 -48
  12. package/non-project-files/dev.txt +21 -0
  13. package/non-project-files/image1.png +0 -0
  14. package/non-project-files/image6.png +0 -0
  15. package/package.json +28 -13
  16. package/public/app.js +11405 -9375
  17. package/public/css/style.css +371 -110
  18. package/public/empty.html +1 -1
  19. package/public/empty.js +9887 -9264
  20. package/public/examples.html +10 -8
  21. package/public/examples.js +553 -193
  22. package/public/index.html +3 -5
  23. package/public/manifest copy.web +35 -0
  24. package/public/res/audios/block.mp3 +0 -0
  25. package/public/res/audios/dice1.mp3 +0 -0
  26. package/public/res/audios/dice2.mp3 +0 -0
  27. package/public/res/audios/start.mp3 +0 -0
  28. package/public/res/meshes/jamb/bg.blend +0 -0
  29. package/public/res/meshes/jamb/bg.blend1 +0 -0
  30. package/public/res/meshes/jamb/bg.mtl +12 -0
  31. package/public/res/meshes/jamb/bg.obj +17 -0
  32. package/public/res/meshes/jamb/bg.png +0 -0
  33. package/public/res/meshes/jamb/dice-default.png +0 -0
  34. package/public/res/meshes/jamb/dice-mark.png +0 -0
  35. package/public/res/meshes/jamb/dice.mtl +12 -0
  36. package/public/res/meshes/jamb/dice.obj +40 -0
  37. package/public/res/meshes/jamb/dice.png +0 -0
  38. package/public/res/meshes/jamb/jamb-title.mtl +12 -0
  39. package/public/res/meshes/jamb/jamb-title.obj +26008 -0
  40. package/public/res/meshes/jamb/jamb.blend +0 -0
  41. package/public/res/meshes/jamb/jamb.blend1 +0 -0
  42. package/public/res/meshes/jamb/logo.png +0 -0
  43. package/public/res/meshes/jamb/nidzaDice.blend +0 -0
  44. package/public/res/meshes/jamb/nidzaDice.blend1 +0 -0
  45. package/public/res/meshes/jamb/pile.blend +0 -0
  46. package/public/res/meshes/jamb/simpleCube.blend +0 -0
  47. package/public/res/meshes/jamb/simpleCube.blend1 +0 -0
  48. package/public/res/meshes/jamb/sounds/roll1.wav +0 -0
  49. package/public/res/meshes/jamb/text.png +0 -0
  50. package/public/res/multilang/en.json +27 -0
  51. package/public/res/multilang/sr.json +27 -0
  52. package/public/test.html +636 -0
  53. package/public/three-test.js +165 -0
  54. package/public/worker.html +1 -1
  55. package/readme.md +189 -115
  56. package/src/engine/cube.js +10 -1
  57. package/src/engine/engine.js +1 -5
  58. package/src/engine/loader-obj.js +9 -6
  59. package/src/engine/matrix-class.js +237 -204
  60. package/src/engine/mesh-obj.js +605 -515
  61. package/src/engine/raycast-test.js +93 -0
  62. package/src/engine/utils.js +69 -3
  63. package/src/multilang/lang.js +35 -0
  64. package/src/physics/matrix-ammo.js +168 -15
  65. package/src/shaders/fragment.wgsl.js +4 -2
  66. package/src/shaders/shaders.js +1 -1
  67. package/src/shaders/vertexShadow.wgsl.js +1 -1
  68. package/src/sounds/sounds.js +47 -0
  69. package/src/world.js +311 -248
@@ -4,521 +4,611 @@ import {createInputHandler} from "./engine";
4
4
  import {vertexShadowWGSL} from '../shaders/vertexShadow.wgsl';
5
5
  import {fragmentWGSL} from '../shaders/fragment.wgsl';
6
6
  import {vertexWGSL} from '../shaders/vertex.wgsl';
7
- import {degToRad, LOG_INFO} from './utils';
7
+ import {degToRad, genName, LOG_FUNNY, LOG_FUNNY_SMALL, LOG_INFO} from './utils';
8
+ import {checkingProcedure, checkingRay, touchCoordinate} from './raycast-test';
8
9
 
9
10
  export default class MEMeshObj {
10
-
11
- constructor(canvas, device, context, o) {
12
-
13
- this.done = false;
14
- this.device = device;
15
- this.context = context;
16
- this.entityArgPass = o.entityArgPass;
17
-
18
- // Mesh stuff
19
- this.mesh = o.mesh;
20
- this.mesh.uvs = this.mesh.textures;
21
- console.log(`%c Mesh loaded: ${o.name}`, LOG_INFO);
22
-
23
- this.inputHandler = createInputHandler(window, canvas);
24
- this.cameras = o.cameras;
25
-
26
- this.mainCameraParams = {
27
- type: o.mainCameraParams.type,
28
- responseCoef: o.mainCameraParams.responseCoef
29
- }
30
-
31
- this.lastFrameMS = 0;
32
- this.texturesPaths = [];
33
- o.texturesPaths.forEach((t) => {this.texturesPaths.push(t)})
34
-
35
- this.presentationFormat = navigator.gpu.getPreferredCanvasFormat();
36
-
37
- this.position = new Position(o.position.x, o.position.y, o.position.z);
38
- this.rotation = new Rotation(o.rotation.x, o.rotation.y, o.rotation.z);
39
- this.rotation.rotationSpeed.x = o.rotationSpeed.x;
40
- this.rotation.rotationSpeed.y = o.rotationSpeed.y;
41
- this.rotation.rotationSpeed.z = o.rotationSpeed.z;
42
- this.scale = o.scale;
43
-
44
- this.runProgram = () => {
45
- return new Promise(async (resolve) => {
46
- this.shadowDepthTextureSize = 1024;
47
- const aspect = canvas.width / canvas.height;
48
- this.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 2000.0);
49
- this.modelViewProjectionMatrix = mat4.create();
50
- // console.log('cube added texturesPaths: ', this.texturesPaths)
51
- this.loadTex0(this.texturesPaths, device).then(() => {
52
- // console.log('loaded tex buffer for mesh:', this.texture0)
53
- resolve()
54
- })
55
- })
56
- }
57
-
58
- this.runProgram().then(() => {
59
- const aspect = canvas.width / canvas.height;
60
- const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
61
- this.context.configure({
62
- device: this.device,
63
- format: presentationFormat,
64
- alphaMode: 'premultiplied',
65
- });
66
-
67
- // Create the model vertex buffer.
68
- this.vertexBuffer = this.device.createBuffer({
69
- size: this.mesh.vertices.length * Float32Array.BYTES_PER_ELEMENT,
70
- usage: GPUBufferUsage.VERTEX,
71
- mappedAtCreation: true,
72
- });
73
- {
74
- // const mapping = new Float32Array(this.vertexBuffer.getMappedRange());
75
- // // for(let i = 0;i < this.mesh.vertices.length;++i) {
76
- // // mapping.set(this.mesh.vertices[i], 6 * i);
77
- // // mapping.set(this.mesh.normals[i], 6 * i + 3);
78
- // // }
79
- // this.vertexBuffer.unmap();
80
- new Float32Array(this.vertexBuffer.getMappedRange()).set(this.mesh.vertices);
81
- this.vertexBuffer.unmap();
82
- }
83
-
84
- // NIDZA TEST SECOUND BUFFER
85
- // Create the model vertex buffer.
86
- this.vertexNormalsBuffer = this.device.createBuffer({
87
- size: this.mesh.vertexNormals.length * Float32Array.BYTES_PER_ELEMENT,
88
- usage: GPUBufferUsage.VERTEX,
89
- mappedAtCreation: true,
90
- });
91
- {
92
- new Float32Array(this.vertexNormalsBuffer.getMappedRange()).set(this.mesh.vertexNormals);
93
- this.vertexNormalsBuffer.unmap();
94
- }
95
-
96
- this.vertexTexCoordsBuffer = this.device.createBuffer({
97
- size: this.mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
98
- usage: GPUBufferUsage.VERTEX,
99
- mappedAtCreation: true,
100
- });
101
- {
102
- new Float32Array(this.vertexTexCoordsBuffer.getMappedRange()).set(this.mesh.textures);
103
- this.vertexTexCoordsBuffer.unmap();
104
- }
105
-
106
- // Create the model index buffer.
107
- this.indexCount = this.mesh.indices.length;
108
- this.indexBuffer = this.device.createBuffer({
109
- size: this.indexCount * Uint16Array.BYTES_PER_ELEMENT,
110
- usage: GPUBufferUsage.INDEX,
111
- mappedAtCreation: true,
112
- });
113
- {
114
- // const mapping = new Uint16Array(this.indexBuffer.getMappedRange());
115
- // for(let i = 0;i < this.mesh.indices.length;++i) {
116
- // mapping.set(this.mesh.indices[i], i);
117
- // }
118
- new Uint16Array(this.indexBuffer.getMappedRange()).set(this.mesh.indices);
119
- this.indexBuffer.unmap();
120
- }
121
-
122
- // Create the depth texture for rendering/sampling the shadow map.
123
- this.shadowDepthTexture = this.device.createTexture({
124
- size: [this.shadowDepthTextureSize, this.shadowDepthTextureSize, 1],
125
- usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
126
- format: 'depth32float',
127
- });
128
- this.shadowDepthTextureView = this.shadowDepthTexture.createView();
129
-
130
- // Create some common descriptors used for both the shadow pipeline
131
- // and the color rendering pipeline.
132
- this.vertexBuffers = [
133
- {
134
- arrayStride: Float32Array.BYTES_PER_ELEMENT * 3,
135
- attributes: [
136
- {
137
- // position
138
- shaderLocation: 0,
139
- offset: 0,
140
- format: "float32x3",
141
- }
142
- ],
143
- },
144
- {
145
- arrayStride: Float32Array.BYTES_PER_ELEMENT * 3,
146
- attributes: [
147
- {
148
- // normal
149
- shaderLocation: 1,
150
- offset: 0,
151
- format: "float32x3",
152
- },
153
- ],
154
- },
155
- {
156
- arrayStride: Float32Array.BYTES_PER_ELEMENT * 2,
157
- attributes: [
158
- {
159
- // uvs
160
- shaderLocation: 2,
161
- offset: 0,
162
- format: "float32x2",
163
- },
164
- ],
165
- },
166
- ];
167
-
168
- const primitive = {
169
- topology: 'triangle-list',
170
- cullMode: 'back',
171
- };
172
-
173
- this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
174
- entries: [
175
- {
176
- binding: 0,
177
- visibility: GPUShaderStage.VERTEX,
178
- buffer: {
179
- type: 'uniform',
180
- },
181
- },
182
- ],
183
- });
184
-
185
- this.shadowPipeline = this.device.createRenderPipeline({
186
- layout: this.device.createPipelineLayout({
187
- bindGroupLayouts: [
188
- this.uniformBufferBindGroupLayout,
189
- this.uniformBufferBindGroupLayout,
190
- ],
191
- }),
192
- vertex: {
193
- module: this.device.createShaderModule({
194
- code: vertexShadowWGSL,
195
- }),
196
- buffers: this.vertexBuffers,
197
- },
198
- depthStencil: {
199
- depthWriteEnabled: true,
200
- depthCompare: 'less',
201
- format: 'depth32float',
202
- },
203
- primitive,
204
- });
205
-
206
- // Create a bind group layout which holds the scene uniforms and
207
- // the texture+sampler for depth. We create it manually because the WebPU
208
- // implementation doesn't infer this from the shader (yet).
209
- this.bglForRender = this.device.createBindGroupLayout({
210
- entries: [
211
- {
212
- binding: 0,
213
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
214
- buffer: {
215
- type: 'uniform',
216
- },
217
- },
218
- {
219
- binding: 1,
220
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
221
- texture: {
222
- sampleType: 'depth',
223
- },
224
- },
225
- {
226
- binding: 2,
227
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
228
- sampler: {
229
- type: 'comparison',
230
- },
231
- },
232
- {
233
- binding: 3,
234
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
235
- texture: {
236
- sampleType: 'float',
237
- }
238
- },
239
- {
240
- binding: 4,
241
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
242
- sampler: {
243
- type: 'filtering',
244
- }
245
- }
246
- ]
247
- });
248
-
249
- this.pipeline = this.device.createRenderPipeline({
250
- layout: this.device.createPipelineLayout({
251
- bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout],
252
- }),
253
- vertex: {
254
- module: this.device.createShaderModule({
255
- code: vertexWGSL,
256
- }),
257
- buffers: this.vertexBuffers,
258
- },
259
- fragment: {
260
- module: this.device.createShaderModule({
261
- code: fragmentWGSL,
262
- }),
263
- targets: [
264
- {
265
- format: presentationFormat,
266
- },
267
- ],
268
- constants: {
269
- shadowDepthTextureSize: this.shadowDepthTextureSize,
270
- },
271
- },
272
- depthStencil: {
273
- depthWriteEnabled: true,
274
- depthCompare: 'less',
275
- format: 'depth24plus-stencil8',
276
- },
277
- primitive,
278
- });
279
-
280
- const depthTexture = this.device.createTexture({
281
- size: [canvas.width, canvas.height],
282
- format: 'depth24plus-stencil8',
283
- usage: GPUTextureUsage.RENDER_ATTACHMENT,
284
- });
285
-
286
- this.renderPassDescriptor = {
287
- colorAttachments: [
288
- {
289
- // view is acquired and set in render loop.
290
- view: undefined,
291
- clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
292
- loadOp: 'load',
293
- storeOp: 'store',
294
- },
295
- ],
296
- depthStencilAttachment: {
297
- view: depthTexture.createView(),
298
- depthClearValue: 1.0,
299
- depthLoadOp: 'clear',
300
- depthStoreOp: 'store',
301
- stencilClearValue: 0,
302
- stencilLoadOp: 'clear',
303
- stencilStoreOp: 'store',
304
- },
305
- };
306
-
307
- this.modelUniformBuffer = this.device.createBuffer({
308
- size: 4 * 16, // 4x4 matrix
309
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
310
- });
311
-
312
- this.sceneUniformBuffer = this.device.createBuffer({
313
- // Two 4x4 viewProj matrices,
314
- // one for the camera and one for the light.
315
- // Then a vec3 for the light position.
316
- // Rounded to the nearest multiple of 16.
317
- size: 2 * 4 * 16 + 4 * 4,
318
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
319
- });
320
-
321
- this.sceneBindGroupForShadow = this.device.createBindGroup({
322
- layout: this.uniformBufferBindGroupLayout,
323
- entries: [
324
- {
325
- binding: 0,
326
- resource: {
327
- buffer: this.sceneUniformBuffer,
328
- },
329
- },
330
- ],
331
- });
332
-
333
- this.sceneBindGroupForRender = this.device.createBindGroup({
334
- layout: this.bglForRender,
335
- entries: [
336
- {
337
- binding: 0,
338
- resource: {
339
- buffer: this.sceneUniformBuffer,
340
- },
341
- },
342
- {
343
- binding: 1,
344
- resource: this.shadowDepthTextureView,
345
- },
346
- {
347
- binding: 2,
348
- resource: this.device.createSampler({
349
- compare: 'less',
350
- }),
351
- },
352
- {
353
- binding: 3,
354
- resource: this.texture0.createView(),
355
- },
356
- {
357
- binding: 4,
358
- resource: this.sampler,
359
- },
360
- ],
361
- });
362
-
363
- this.modelBindGroup = this.device.createBindGroup({
364
- layout: this.uniformBufferBindGroupLayout,
365
- entries: [
366
- {
367
- binding: 0,
368
- resource: {
369
- buffer: this.modelUniformBuffer,
370
- },
371
- },
372
- ],
373
- });
374
-
375
- // Rotates the camera around the origin based on time.
376
- this.getTransformationMatrix = (pos) => {
377
- const now = Date.now();
378
- const deltaTime = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
379
- this.lastFrameMS = now;
380
- // const this.viewMatrix = mat4.identity()
381
- const camera = this.cameras[this.mainCameraParams.type];
382
- this.viewMatrix = camera.update(deltaTime, this.inputHandler());
383
- mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
384
- mat4.rotate(
385
- this.viewMatrix,
386
- vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
387
- degToRad(this.rotation.angle), this.viewMatrix)
388
- // mat4.rotateX(this.viewMatrix, this.rotation.getRotX(), this.viewMatrix);
389
- // mat4.rotateY(this.viewMatrix, this.rotation.getRotY(), this.viewMatrix);
390
- // mat4.rotateZ(this.viewMatrix, this.rotation.getRotZ(), this.viewMatrix);
391
- mat4.multiply(this.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
392
- return this.modelViewProjectionMatrix;
393
- }
394
-
395
- this.upVector = vec3.fromValues(0, 1, 0);
396
- this.origin = vec3.fromValues(0, 0, 0);
397
-
398
- const lightPosition = vec3.fromValues(50, 100, -100);
399
- const lightViewMatrix = mat4.lookAt(lightPosition, this.origin, this.upVector);
400
- const lightProjectionMatrix = mat4.create();
401
- {
402
- const left = -80;
403
- const right = 80;
404
- const bottom = -80;
405
- const top = 80;
406
- const near = -200;
407
- const far = 300;
408
- mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);
409
- }
410
-
411
- const lightViewProjMatrix = mat4.multiply(
412
- lightProjectionMatrix,
413
- lightViewMatrix
414
- );
415
-
416
- // looks like affect on transformations for now const 0
417
- const modelMatrix = mat4.translation([0, 0, 0]);
418
- // The camera/light aren't moving, so write them into buffers now.
419
- {
420
- const lightMatrixData = lightViewProjMatrix; // as Float32Array;
421
- this.device.queue.writeBuffer(
422
- this.sceneUniformBuffer,
423
- 0,
424
- lightMatrixData.buffer,
425
- lightMatrixData.byteOffset,
426
- lightMatrixData.byteLength
427
- );
428
-
429
- const lightData = lightPosition;
430
- this.device.queue.writeBuffer(
431
- this.sceneUniformBuffer,
432
- 128,
433
- lightData.buffer,
434
- lightData.byteOffset,
435
- lightData.byteLength
436
- );
437
-
438
- const modelData = modelMatrix;
439
- this.device.queue.writeBuffer(
440
- this.modelUniformBuffer,
441
- 0,
442
- modelData.buffer,
443
- modelData.byteOffset,
444
- modelData.byteLength
445
- );
446
- }
447
-
448
- this.shadowPassDescriptor = {
449
- colorAttachments: [],
450
- depthStencilAttachment: {
451
- view: this.shadowDepthTextureView,
452
- depthClearValue: 1.0,
453
- depthLoadOp: 'clear',
454
- depthStoreOp: 'store',
455
- },
456
- };
457
-
458
- this.done = true;
459
- })
460
- }
461
-
462
- async loadTex0(texturesPaths, device) {
463
-
464
- this.sampler = device.createSampler({
465
- magFilter: 'linear',
466
- minFilter: 'linear',
467
- });
468
-
469
- return new Promise(async (resolve) => {
470
- const response = await fetch(texturesPaths[0]);
471
- const imageBitmap = await createImageBitmap(await response.blob());
472
- this.texture0 = device.createTexture({
473
- size: [imageBitmap.width, imageBitmap.height, 1],
474
- format: 'rgba8unorm',
475
- usage:
476
- GPUTextureUsage.TEXTURE_BINDING |
477
- GPUTextureUsage.COPY_DST |
478
- GPUTextureUsage.RENDER_ATTACHMENT,
479
- });
480
-
481
- device.queue.copyExternalImageToTexture(
482
- {source: imageBitmap},
483
- {texture: this.texture0},
484
- [imageBitmap.width, imageBitmap.height]
485
- );
486
- resolve()
487
- })
488
- }
489
-
490
- draw = (commandEncoder) => {
491
- if(this.done == false) return;
492
- const transformationMatrix = this.getTransformationMatrix(this.position);
493
- this.device.queue.writeBuffer(
494
- this.sceneUniformBuffer,
495
- 64,
496
- transformationMatrix.buffer,
497
- transformationMatrix.byteOffset,
498
- transformationMatrix.byteLength
499
- );
500
- this.renderPassDescriptor.colorAttachments[0].view = this.context
501
- .getCurrentTexture()
502
- .createView();
503
- }
504
-
505
- drawElements = (renderPass) => {
506
- renderPass.setBindGroup(0, this.sceneBindGroupForRender);
507
- renderPass.setBindGroup(1, this.modelBindGroup);
508
- renderPass.setVertexBuffer(0, this.vertexBuffer);
509
- renderPass.setVertexBuffer(1, this.vertexNormalsBuffer);
510
- renderPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
511
- renderPass.setIndexBuffer(this.indexBuffer, 'uint16');
512
- renderPass.drawIndexed(this.indexCount);
513
- }
514
-
515
- drawShadows = (shadowPass) => {
516
- shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
517
- shadowPass.setBindGroup(1, this.modelBindGroup);
518
- shadowPass.setVertexBuffer(0, this.vertexBuffer);
519
- shadowPass.setVertexBuffer(1, this.vertexNormalsBuffer);
520
- shadowPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
521
- shadowPass.setIndexBuffer(this.indexBuffer, 'uint16');
522
- shadowPass.drawIndexed(this.indexCount);
523
- }
11
+ constructor(canvas, device, context, o) {
12
+ if(typeof o.name === 'undefined') o.name = genName(9);
13
+ if(typeof o.raycast === 'undefined') {
14
+ this.raycast = {enabled: false};
15
+ } else {
16
+ this.raycast = o.raycast;
17
+ }
18
+
19
+ this.name = o.name;
20
+ this.done = false;
21
+ this.device = device;
22
+ this.context = context;
23
+ this.entityArgPass = o.entityArgPass;
24
+
25
+ // Mesh stuff
26
+ this.mesh = o.mesh;
27
+ this.mesh.uvs = this.mesh.textures;
28
+ console.log(`%c Mesh loaded: ${o.name}`, LOG_FUNNY_SMALL);
29
+
30
+ this.inputHandler = createInputHandler(window, canvas);
31
+ this.cameras = o.cameras;
32
+
33
+ this.mainCameraParams = {
34
+ type: o.mainCameraParams.type,
35
+ responseCoef: o.mainCameraParams.responseCoef
36
+ }
37
+
38
+ // test raycast
39
+ // fullscreen for now
40
+ // window.addEventListener('mousedown', (e) => {
41
+ // checkingProcedure(e);
42
+ // });
43
+ touchCoordinate.enabled = true;
44
+
45
+ this.lastFrameMS = 0;
46
+ this.texturesPaths = [];
47
+ o.texturesPaths.forEach((t) => {this.texturesPaths.push(t)})
48
+
49
+ this.presentationFormat = navigator.gpu.getPreferredCanvasFormat();
50
+
51
+ this.position = new Position(o.position.x, o.position.y, o.position.z);
52
+ this.rotation = new Rotation(o.rotation.x, o.rotation.y, o.rotation.z);
53
+ this.rotation.rotationSpeed.x = o.rotationSpeed.x;
54
+ this.rotation.rotationSpeed.y = o.rotationSpeed.y;
55
+ this.rotation.rotationSpeed.z = o.rotationSpeed.z;
56
+ this.scale = o.scale;
57
+
58
+ this.runProgram = () => {
59
+ return new Promise(async (resolve) => {
60
+ this.shadowDepthTextureSize = 1024;
61
+ const aspect = canvas.width / canvas.height;
62
+ this.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 2000.0);
63
+ this.modelViewProjectionMatrix = mat4.create();
64
+ // console.log('cube added texturesPaths: ', this.texturesPaths)
65
+ this.loadTex0(this.texturesPaths, device).then(() => {
66
+ // console.log('loaded tex buffer for mesh:', this.texture0)
67
+ resolve()
68
+ })
69
+ })
70
+ }
71
+
72
+ this.runProgram().then(() => {
73
+ const aspect = canvas.width / canvas.height;
74
+ const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
75
+ this.context.configure({
76
+ device: this.device,
77
+ format: presentationFormat,
78
+ alphaMode: 'premultiplied',
79
+ });
80
+
81
+ // Create the model vertex buffer.
82
+ this.vertexBuffer = this.device.createBuffer({
83
+ size: this.mesh.vertices.length * Float32Array.BYTES_PER_ELEMENT,
84
+ usage: GPUBufferUsage.VERTEX,
85
+ mappedAtCreation: true,
86
+ });
87
+ {
88
+ // const mapping = new Float32Array(this.vertexBuffer.getMappedRange());
89
+ // // for(let i = 0;i < this.mesh.vertices.length;++i) {
90
+ // // mapping.set(this.mesh.vertices[i], 6 * i);
91
+ // // mapping.set(this.mesh.normals[i], 6 * i + 3);
92
+ // // }
93
+ // this.vertexBuffer.unmap();
94
+ new Float32Array(this.vertexBuffer.getMappedRange()).set(this.mesh.vertices);
95
+ this.vertexBuffer.unmap();
96
+ }
97
+
98
+ // NIDZA TEST SECOUND BUFFER
99
+ // Create the model vertex buffer.
100
+ this.vertexNormalsBuffer = this.device.createBuffer({
101
+ size: this.mesh.vertexNormals.length * Float32Array.BYTES_PER_ELEMENT,
102
+ usage: GPUBufferUsage.VERTEX,
103
+ mappedAtCreation: true,
104
+ });
105
+ {
106
+ new Float32Array(this.vertexNormalsBuffer.getMappedRange()).set(this.mesh.vertexNormals);
107
+ this.vertexNormalsBuffer.unmap();
108
+ }
109
+
110
+ this.vertexTexCoordsBuffer = this.device.createBuffer({
111
+ size: this.mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
112
+ usage: GPUBufferUsage.VERTEX,
113
+ mappedAtCreation: true,
114
+ });
115
+ {
116
+ new Float32Array(this.vertexTexCoordsBuffer.getMappedRange()).set(this.mesh.textures);
117
+ this.vertexTexCoordsBuffer.unmap();
118
+ }
119
+
120
+ // Create the model index buffer.
121
+ this.indexCount = this.mesh.indices.length;
122
+ this.indexBuffer = this.device.createBuffer({
123
+ size: this.indexCount * Uint16Array.BYTES_PER_ELEMENT,
124
+ usage: GPUBufferUsage.INDEX,
125
+ mappedAtCreation: true,
126
+ });
127
+ {
128
+ // const mapping = new Uint16Array(this.indexBuffer.getMappedRange());
129
+ // for(let i = 0;i < this.mesh.indices.length;++i) {
130
+ // mapping.set(this.mesh.indices[i], i);
131
+ // }
132
+ new Uint16Array(this.indexBuffer.getMappedRange()).set(this.mesh.indices);
133
+ this.indexBuffer.unmap();
134
+ }
135
+
136
+ // Create the depth texture for rendering/sampling the shadow map.
137
+ this.shadowDepthTexture = this.device.createTexture({
138
+ size: [this.shadowDepthTextureSize, this.shadowDepthTextureSize, 1],
139
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
140
+ format: 'depth32float',
141
+ });
142
+ this.shadowDepthTextureView = this.shadowDepthTexture.createView();
143
+
144
+ // Create some common descriptors used for both the shadow pipeline
145
+ // and the color rendering pipeline.
146
+ this.vertexBuffers = [
147
+ {
148
+ arrayStride: Float32Array.BYTES_PER_ELEMENT * 3,
149
+ attributes: [
150
+ {
151
+ // position
152
+ shaderLocation: 0,
153
+ offset: 0,
154
+ format: "float32x3",
155
+ }
156
+ ],
157
+ },
158
+ {
159
+ arrayStride: Float32Array.BYTES_PER_ELEMENT * 3,
160
+ attributes: [
161
+ {
162
+ // normal
163
+ shaderLocation: 1,
164
+ offset: 0,
165
+ format: "float32x3",
166
+ },
167
+ ],
168
+ },
169
+ {
170
+ arrayStride: Float32Array.BYTES_PER_ELEMENT * 2,
171
+ attributes: [
172
+ {
173
+ // uvs
174
+ shaderLocation: 2,
175
+ offset: 0,
176
+ format: "float32x2",
177
+ },
178
+ ],
179
+ },
180
+ ];
181
+
182
+ const primitive = {
183
+ topology: 'triangle-list',
184
+ cullMode: 'back',
185
+ };
186
+
187
+ this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
188
+ entries: [
189
+ {
190
+ binding: 0,
191
+ visibility: GPUShaderStage.VERTEX,
192
+ buffer: {
193
+ type: 'uniform',
194
+ },
195
+ },
196
+ ],
197
+ });
198
+
199
+ this.shadowPipeline = this.device.createRenderPipeline({
200
+ layout: this.device.createPipelineLayout({
201
+ bindGroupLayouts: [
202
+ this.uniformBufferBindGroupLayout,
203
+ this.uniformBufferBindGroupLayout,
204
+ ],
205
+ }),
206
+ vertex: {
207
+ module: this.device.createShaderModule({
208
+ code: vertexShadowWGSL,
209
+ }),
210
+ buffers: this.vertexBuffers,
211
+ },
212
+ depthStencil: {
213
+ depthWriteEnabled: true,
214
+ depthCompare: 'less',
215
+ format: 'depth32float',
216
+ },
217
+ primitive,
218
+ });
219
+
220
+ // Create a bind group layout which holds the scene uniforms and
221
+ // the texture+sampler for depth. We create it manually because the WebPU
222
+ // implementation doesn't infer this from the shader (yet).
223
+ this.bglForRender = this.device.createBindGroupLayout({
224
+ entries: [
225
+ {
226
+ binding: 0,
227
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
228
+ buffer: {
229
+ type: 'uniform',
230
+ },
231
+ },
232
+ {
233
+ binding: 1,
234
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
235
+ texture: {
236
+ sampleType: 'depth',
237
+ },
238
+ },
239
+ {
240
+ binding: 2,
241
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
242
+ sampler: {
243
+ type: 'comparison',
244
+ },
245
+ },
246
+ {
247
+ binding: 3,
248
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
249
+ texture: {
250
+ sampleType: 'float',
251
+ }
252
+ },
253
+ {
254
+ binding: 4,
255
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
256
+ sampler: {
257
+ type: 'filtering',
258
+ }
259
+ }
260
+ ]
261
+ });
262
+
263
+ this.pipeline = this.device.createRenderPipeline({
264
+ layout: this.device.createPipelineLayout({
265
+ bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout],
266
+ }),
267
+ vertex: {
268
+ module: this.device.createShaderModule({
269
+ code: vertexWGSL,
270
+ }),
271
+ buffers: this.vertexBuffers,
272
+ },
273
+ fragment: {
274
+ module: this.device.createShaderModule({
275
+ code: fragmentWGSL,
276
+ }),
277
+ targets: [
278
+ {
279
+ format: presentationFormat,
280
+ },
281
+ ],
282
+ constants: {
283
+ shadowDepthTextureSize: this.shadowDepthTextureSize,
284
+ },
285
+ },
286
+ depthStencil: {
287
+ depthWriteEnabled: true,
288
+ depthCompare: 'less',
289
+ format: 'depth24plus-stencil8',
290
+ },
291
+ primitive,
292
+ });
293
+
294
+ const depthTexture = this.device.createTexture({
295
+ size: [canvas.width, canvas.height],
296
+ format: 'depth24plus-stencil8',
297
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
298
+ });
299
+
300
+ this.renderPassDescriptor = {
301
+ colorAttachments: [
302
+ {
303
+ // view is acquired and set in render loop.
304
+ view: undefined,
305
+ clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
306
+ loadOp: 'load',
307
+ storeOp: 'store',
308
+ },
309
+ ],
310
+ depthStencilAttachment: {
311
+ view: depthTexture.createView(),
312
+ depthClearValue: 1.0,
313
+ depthLoadOp: 'clear',
314
+ depthStoreOp: 'store',
315
+ stencilClearValue: 0,
316
+ stencilLoadOp: 'clear',
317
+ stencilStoreOp: 'store',
318
+ },
319
+ };
320
+
321
+ this.modelUniformBuffer = this.device.createBuffer({
322
+ size: 4 * 16, // 4x4 matrix
323
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
324
+ });
325
+
326
+ this.sceneUniformBuffer = this.device.createBuffer({
327
+ // Two 4x4 viewProj matrices,
328
+ // one for the camera and one for the light.
329
+ // Then a vec3 for the light position.
330
+ // Rounded to the nearest multiple of 16.
331
+ size: 2 * 4 * 16 + 4 * 4,
332
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
333
+ });
334
+
335
+ this.sceneBindGroupForShadow = this.device.createBindGroup({
336
+ layout: this.uniformBufferBindGroupLayout,
337
+ entries: [
338
+ {
339
+ binding: 0,
340
+ resource: {
341
+ buffer: this.sceneUniformBuffer,
342
+ },
343
+ },
344
+ ],
345
+ });
346
+
347
+ this.sceneBindGroupForRender = this.device.createBindGroup({
348
+ layout: this.bglForRender,
349
+ entries: [
350
+ {
351
+ binding: 0,
352
+ resource: {
353
+ buffer: this.sceneUniformBuffer,
354
+ },
355
+ },
356
+ {
357
+ binding: 1,
358
+ resource: this.shadowDepthTextureView,
359
+ },
360
+ {
361
+ binding: 2,
362
+ resource: this.device.createSampler({
363
+ compare: 'less',
364
+ }),
365
+ },
366
+ {
367
+ binding: 3,
368
+ resource: this.texture0.createView(),
369
+ },
370
+ {
371
+ binding: 4,
372
+ resource: this.sampler,
373
+ },
374
+ ],
375
+ });
376
+
377
+ this.modelBindGroup = this.device.createBindGroup({
378
+ layout: this.uniformBufferBindGroupLayout,
379
+ entries: [
380
+ {
381
+ binding: 0,
382
+ resource: {
383
+ buffer: this.modelUniformBuffer,
384
+ },
385
+ },
386
+ ],
387
+ });
388
+
389
+ // Rotates the camera around the origin based on time.
390
+ this.getTransformationMatrix = (pos) => {
391
+ const now = Date.now();
392
+ const deltaTime = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
393
+ this.lastFrameMS = now;
394
+ // const this.viewMatrix = mat4.identity()
395
+ const camera = this.cameras[this.mainCameraParams.type];
396
+ this.viewMatrix = camera.update(deltaTime, this.inputHandler());
397
+ mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
398
+ mat4.rotate(
399
+ this.viewMatrix,
400
+ vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
401
+ degToRad(this.rotation.angle), this.viewMatrix)
402
+
403
+ // console.info('angle: ', this.rotation.angle, ' axis ' , this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
404
+ mat4.multiply(this.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
405
+ return this.modelViewProjectionMatrix;
406
+ }
407
+
408
+ this.upVector = vec3.fromValues(0, 1, 0);
409
+ this.origin = vec3.fromValues(0, 0, 0);
410
+
411
+ this.lightPosition = vec3.fromValues(0, 0, 0);
412
+ this.lightViewMatrix = mat4.lookAt(this.lightPosition, this.origin, this.upVector);
413
+ const lightProjectionMatrix = mat4.create();
414
+
415
+ var myLMargin = 100;
416
+ {
417
+ const left = -myLMargin;
418
+ const right = myLMargin;
419
+ const bottom = -myLMargin;
420
+ const top = myLMargin;
421
+ const near = -200;
422
+ const far = 300;
423
+ mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);
424
+ // test
425
+ // mat4.ortho(right, left, top, bottom, near, far, lightProjectionMatrix);
426
+ }
427
+
428
+ this.lightViewProjMatrix = mat4.multiply(
429
+ lightProjectionMatrix,
430
+ this.lightViewMatrix
431
+ );
432
+
433
+ // looks like affect on transformations for now const 0
434
+ const modelMatrix = mat4.translation([0, 0, 0]);
435
+ // The camera/light aren't moving, so write them into buffers now.
436
+ {
437
+ const lightMatrixData = this.lightViewProjMatrix; // as Float32Array;
438
+ this.device.queue.writeBuffer(
439
+ this.sceneUniformBuffer,
440
+ 0,
441
+ lightMatrixData.buffer,
442
+ lightMatrixData.byteOffset,
443
+ lightMatrixData.byteLength
444
+ );
445
+
446
+ const lightData = this.lightPosition;
447
+ this.device.queue.writeBuffer(
448
+ this.sceneUniformBuffer,
449
+ 128,
450
+ lightData.buffer,
451
+ lightData.byteOffset,
452
+ lightData.byteLength
453
+ );
454
+
455
+ const modelData = modelMatrix;
456
+ this.device.queue.writeBuffer(
457
+ this.modelUniformBuffer,
458
+ 0,
459
+ modelData.buffer,
460
+ modelData.byteOffset,
461
+ modelData.byteLength
462
+ );
463
+ }
464
+
465
+ this.shadowPassDescriptor = {
466
+ colorAttachments: [],
467
+ depthStencilAttachment: {
468
+ view: this.shadowDepthTextureView,
469
+ depthClearValue: 1.0,
470
+ depthLoadOp: 'clear',
471
+ depthStoreOp: 'store',
472
+ },
473
+ };
474
+
475
+ this.done = true;
476
+ })
477
+ }
478
+
479
+ updateLightsTest = (position) => {
480
+ console.log('Update light position.', position)
481
+ this.lightPosition = vec3.fromValues(position[0], position[1], position[2]);
482
+ this.lightViewMatrix = mat4.lookAt(this.lightPosition, this.origin, this.upVector);
483
+
484
+ const lightProjectionMatrix = mat4.create();
485
+ {
486
+ const left = -80;
487
+ const right = 80;
488
+ const bottom = -80;
489
+ const top = 80;
490
+ const near = -200;
491
+ const far = 300;
492
+ mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);
493
+ }
494
+
495
+ this.lightViewProjMatrix = mat4.multiply(
496
+ lightProjectionMatrix,
497
+ this.lightViewMatrix
498
+ );
499
+
500
+ // looks like affect on transformations for now const 0
501
+ const modelMatrix = mat4.translation([0, 0, 0]);
502
+ // The camera/light aren't moving, so write them into buffers now.
503
+ {
504
+ const lightMatrixData = this.lightViewProjMatrix; // as Float32Array;
505
+ this.device.queue.writeBuffer(
506
+ this.sceneUniformBuffer,
507
+ 0, // 0 ori
508
+ lightMatrixData.buffer,
509
+ lightMatrixData.byteOffset,
510
+ lightMatrixData.byteLength
511
+ );
512
+
513
+ const lightData = this.lightPosition;
514
+ this.device.queue.writeBuffer(
515
+ this.sceneUniformBuffer,
516
+ 256,
517
+ lightData.buffer,
518
+ lightData.byteOffset,
519
+ lightData.byteLength
520
+ );
521
+
522
+ const modelData = modelMatrix;
523
+ this.device.queue.writeBuffer(
524
+ this.modelUniformBuffer,
525
+ 0,
526
+ modelData.buffer,
527
+ modelData.byteOffset,
528
+ modelData.byteLength
529
+ );
530
+ }
531
+
532
+ this.shadowPassDescriptor = {
533
+ colorAttachments: [],
534
+ depthStencilAttachment: {
535
+ view: this.shadowDepthTextureView,
536
+ depthClearValue: 1.0, // ori 1.0
537
+ depthLoadOp: 'clear',
538
+ depthStoreOp: 'store',
539
+ },
540
+ };
541
+
542
+ ///////////////////////
543
+ }
544
+
545
+ async loadTex0(texturesPaths, device) {
546
+
547
+ this.sampler = device.createSampler({
548
+ magFilter: 'linear',
549
+ minFilter: 'linear',
550
+ });
551
+
552
+ return new Promise(async (resolve) => {
553
+ const response = await fetch(texturesPaths[0]);
554
+ const imageBitmap = await createImageBitmap(await response.blob());
555
+ this.texture0 = device.createTexture({
556
+ size: [imageBitmap.width, imageBitmap.height, 1],
557
+ format: 'rgba8unorm',
558
+ usage:
559
+ GPUTextureUsage.TEXTURE_BINDING |
560
+ GPUTextureUsage.COPY_DST |
561
+ GPUTextureUsage.RENDER_ATTACHMENT,
562
+ });
563
+
564
+ device.queue.copyExternalImageToTexture(
565
+ {source: imageBitmap},
566
+ {texture: this.texture0},
567
+ [imageBitmap.width, imageBitmap.height]
568
+ );
569
+ resolve()
570
+ })
571
+ }
572
+
573
+ draw = (commandEncoder) => {
574
+ if(this.done == false) return;
575
+ const transformationMatrix = this.getTransformationMatrix(this.position);
576
+ this.device.queue.writeBuffer(
577
+ this.sceneUniformBuffer,
578
+ 64,
579
+ transformationMatrix.buffer,
580
+ transformationMatrix.byteOffset,
581
+ transformationMatrix.byteLength
582
+ );
583
+ this.renderPassDescriptor.colorAttachments[0].view = this.context
584
+ .getCurrentTexture()
585
+ .createView();
586
+ }
587
+
588
+ drawElements = (renderPass) => {
589
+ renderPass.setBindGroup(0, this.sceneBindGroupForRender);
590
+ renderPass.setBindGroup(1, this.modelBindGroup);
591
+ renderPass.setVertexBuffer(0, this.vertexBuffer);
592
+ renderPass.setVertexBuffer(1, this.vertexNormalsBuffer);
593
+ renderPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
594
+ renderPass.setIndexBuffer(this.indexBuffer, 'uint16');
595
+ renderPass.drawIndexed(this.indexCount);
596
+
597
+ // test ray
598
+
599
+ // try{ OLD
600
+ // if(this.raycast.enabled == true) checkingRay(this)
601
+ // } catch(e) {}
602
+
603
+ }
604
+
605
+ drawShadows = (shadowPass) => {
606
+ shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
607
+ shadowPass.setBindGroup(1, this.modelBindGroup);
608
+ shadowPass.setVertexBuffer(0, this.vertexBuffer);
609
+ shadowPass.setVertexBuffer(1, this.vertexNormalsBuffer);
610
+ shadowPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
611
+ shadowPass.setIndexBuffer(this.indexBuffer, 'uint16');
612
+ shadowPass.drawIndexed(this.indexCount);
613
+ }
524
614
  }