matrix-engine-wgpu 1.3.17 → 1.3.19

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 (273) 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 +59 -0
  5. package/app-worker.js +45 -0
  6. package/dev.md +541 -0
  7. package/empty.js +17 -0
  8. package/examples/camera-texture.js +60 -0
  9. package/examples/games/jamb/html-content.js +128 -0
  10. package/examples/games/jamb/jamb.js +1341 -0
  11. package/examples/games/jamb/readme.md +3 -0
  12. package/examples/load-jamb.js +6 -0
  13. package/examples/load-obj-file.js +95 -0
  14. package/examples/load-objs-sequence.js +68 -0
  15. package/examples/unlit-textures.js +31 -0
  16. package/examples/video-texture.js +61 -0
  17. package/examples.js +73 -0
  18. package/main.js +635 -0
  19. package/non-project-files/cubebuffer-example.js +51 -0
  20. package/non-project-files/dev.txt +21 -0
  21. package/non-project-files/image1.png +0 -0
  22. package/non-project-files/image6.png +0 -0
  23. package/package.json +1 -4
  24. package/public/ammojs/ammo.js +957 -0
  25. package/public/ammojs/ammo.wasm.js +921 -0
  26. package/public/ammojs/ammo.wasm.wasm +0 -0
  27. package/public/app-worker.js +47 -0
  28. package/public/app.js +12744 -0
  29. package/public/css/style.css +711 -0
  30. package/public/empty.html +25 -0
  31. package/public/empty.js +10453 -0
  32. package/public/examples.html +30 -0
  33. package/public/examples.js +11217 -0
  34. package/public/index.html +20 -0
  35. package/public/manifest copy.web +35 -0
  36. package/public/manifest.web +25 -0
  37. package/public/res/audios/block.mp3 +0 -0
  38. package/public/res/audios/dice-roll.mp3 +0 -0
  39. package/public/res/audios/dice1.mp3 +0 -0
  40. package/public/res/audios/dice2.mp3 +0 -0
  41. package/public/res/audios/kenney/Kenney.url +2 -0
  42. package/public/res/audios/kenney/License.txt +22 -0
  43. package/public/res/audios/kenney/Patreon.url +2 -0
  44. package/public/res/audios/kenney/audios/back_001.ogg +0 -0
  45. package/public/res/audios/kenney/audios/back_002.ogg +0 -0
  46. package/public/res/audios/kenney/audios/back_003.ogg +0 -0
  47. package/public/res/audios/kenney/audios/back_004.ogg +0 -0
  48. package/public/res/audios/kenney/audios/bong_001.ogg +0 -0
  49. package/public/res/audios/kenney/audios/click_001.ogg +0 -0
  50. package/public/res/audios/kenney/audios/click_002.ogg +0 -0
  51. package/public/res/audios/kenney/audios/click_003.ogg +0 -0
  52. package/public/res/audios/kenney/audios/click_004.ogg +0 -0
  53. package/public/res/audios/kenney/audios/click_005.ogg +0 -0
  54. package/public/res/audios/kenney/audios/close_001.ogg +0 -0
  55. package/public/res/audios/kenney/audios/close_002.ogg +0 -0
  56. package/public/res/audios/kenney/audios/close_003.ogg +0 -0
  57. package/public/res/audios/kenney/audios/close_004.ogg +0 -0
  58. package/public/res/audios/kenney/audios/confirmation_001.ogg +0 -0
  59. package/public/res/audios/kenney/audios/confirmation_002.ogg +0 -0
  60. package/public/res/audios/kenney/audios/confirmation_003.ogg +0 -0
  61. package/public/res/audios/kenney/audios/confirmation_004.ogg +0 -0
  62. package/public/res/audios/kenney/audios/drop_001.ogg +0 -0
  63. package/public/res/audios/kenney/audios/drop_002.ogg +0 -0
  64. package/public/res/audios/kenney/audios/drop_003.ogg +0 -0
  65. package/public/res/audios/kenney/audios/drop_004.ogg +0 -0
  66. package/public/res/audios/kenney/audios/error_001.ogg +0 -0
  67. package/public/res/audios/kenney/audios/error_002.ogg +0 -0
  68. package/public/res/audios/kenney/audios/error_003.ogg +0 -0
  69. package/public/res/audios/kenney/audios/error_004.ogg +0 -0
  70. package/public/res/audios/kenney/audios/error_005.ogg +0 -0
  71. package/public/res/audios/kenney/audios/error_006.ogg +0 -0
  72. package/public/res/audios/kenney/audios/error_007.ogg +0 -0
  73. package/public/res/audios/kenney/audios/error_008.ogg +0 -0
  74. package/public/res/audios/kenney/audios/glass_001.ogg +0 -0
  75. package/public/res/audios/kenney/audios/glass_002.ogg +0 -0
  76. package/public/res/audios/kenney/audios/glass_003.ogg +0 -0
  77. package/public/res/audios/kenney/audios/glass_004.ogg +0 -0
  78. package/public/res/audios/kenney/audios/glass_005.ogg +0 -0
  79. package/public/res/audios/kenney/audios/glass_006.ogg +0 -0
  80. package/public/res/audios/kenney/audios/glitch_001.ogg +0 -0
  81. package/public/res/audios/kenney/audios/glitch_002.ogg +0 -0
  82. package/public/res/audios/kenney/audios/glitch_003.ogg +0 -0
  83. package/public/res/audios/kenney/audios/glitch_004.ogg +0 -0
  84. package/public/res/audios/kenney/audios/maximize_001.ogg +0 -0
  85. package/public/res/audios/kenney/audios/maximize_002.ogg +0 -0
  86. package/public/res/audios/kenney/audios/maximize_003.ogg +0 -0
  87. package/public/res/audios/kenney/audios/maximize_004.ogg +0 -0
  88. package/public/res/audios/kenney/audios/maximize_005.ogg +0 -0
  89. package/public/res/audios/kenney/audios/maximize_006.ogg +0 -0
  90. package/public/res/audios/kenney/audios/maximize_007.ogg +0 -0
  91. package/public/res/audios/kenney/audios/maximize_008.ogg +0 -0
  92. package/public/res/audios/kenney/audios/maximize_009.ogg +0 -0
  93. package/public/res/audios/kenney/audios/minimize_001.ogg +0 -0
  94. package/public/res/audios/kenney/audios/minimize_002.ogg +0 -0
  95. package/public/res/audios/kenney/audios/minimize_003.ogg +0 -0
  96. package/public/res/audios/kenney/audios/minimize_004.ogg +0 -0
  97. package/public/res/audios/kenney/audios/minimize_005.ogg +0 -0
  98. package/public/res/audios/kenney/audios/minimize_006.ogg +0 -0
  99. package/public/res/audios/kenney/audios/minimize_007.ogg +0 -0
  100. package/public/res/audios/kenney/audios/minimize_008.ogg +0 -0
  101. package/public/res/audios/kenney/audios/minimize_009.ogg +0 -0
  102. package/public/res/audios/kenney/audios/open_001.ogg +0 -0
  103. package/public/res/audios/kenney/audios/open_002.ogg +0 -0
  104. package/public/res/audios/kenney/audios/open_003.ogg +0 -0
  105. package/public/res/audios/kenney/audios/open_004.ogg +0 -0
  106. package/public/res/audios/kenney/audios/pluck_001.ogg +0 -0
  107. package/public/res/audios/kenney/audios/pluck_002.ogg +0 -0
  108. package/public/res/audios/kenney/audios/question_001.ogg +0 -0
  109. package/public/res/audios/kenney/audios/question_002.ogg +0 -0
  110. package/public/res/audios/kenney/audios/question_003.ogg +0 -0
  111. package/public/res/audios/kenney/audios/question_004.ogg +0 -0
  112. package/public/res/audios/kenney/audios/scratch_001.ogg +0 -0
  113. package/public/res/audios/kenney/audios/scratch_002.ogg +0 -0
  114. package/public/res/audios/kenney/audios/scratch_003.ogg +0 -0
  115. package/public/res/audios/kenney/audios/scratch_004.ogg +0 -0
  116. package/public/res/audios/kenney/audios/scratch_005.ogg +0 -0
  117. package/public/res/audios/kenney/audios/scroll_001.ogg +0 -0
  118. package/public/res/audios/kenney/audios/scroll_002.ogg +0 -0
  119. package/public/res/audios/kenney/audios/scroll_003.ogg +0 -0
  120. package/public/res/audios/kenney/audios/scroll_004.ogg +0 -0
  121. package/public/res/audios/kenney/audios/scroll_005.ogg +0 -0
  122. package/public/res/audios/kenney/audios/select_001.ogg +0 -0
  123. package/public/res/audios/kenney/audios/select_002.ogg +0 -0
  124. package/public/res/audios/kenney/audios/select_003.ogg +0 -0
  125. package/public/res/audios/kenney/audios/select_004.ogg +0 -0
  126. package/public/res/audios/kenney/audios/select_005.ogg +0 -0
  127. package/public/res/audios/kenney/audios/select_006.ogg +0 -0
  128. package/public/res/audios/kenney/audios/select_007.ogg +0 -0
  129. package/public/res/audios/kenney/audios/select_008.ogg +0 -0
  130. package/public/res/audios/kenney/audios/switch_001.ogg +0 -0
  131. package/public/res/audios/kenney/audios/switch_002.ogg +0 -0
  132. package/public/res/audios/kenney/audios/switch_003.ogg +0 -0
  133. package/public/res/audios/kenney/audios/switch_004.ogg +0 -0
  134. package/public/res/audios/kenney/audios/switch_005.ogg +0 -0
  135. package/public/res/audios/kenney/audios/switch_006.ogg +0 -0
  136. package/public/res/audios/kenney/audios/switch_007.ogg +0 -0
  137. package/public/res/audios/kenney/audios/tick_001.ogg +0 -0
  138. package/public/res/audios/kenney/audios/tick_002.ogg +0 -0
  139. package/public/res/audios/kenney/audios/tick_004.ogg +0 -0
  140. package/public/res/audios/kenney/audios/toggle_001.ogg +0 -0
  141. package/public/res/audios/kenney/audios/toggle_002.ogg +0 -0
  142. package/public/res/audios/kenney/audios/toggle_003.ogg +0 -0
  143. package/public/res/audios/kenney/audios/toggle_004.ogg +0 -0
  144. package/public/res/audios/start.mp3 +0 -0
  145. package/public/res/audios/toggle_002.mp3 +0 -0
  146. package/public/res/fonts/Accuratist.ttf +0 -0
  147. package/public/res/fonts/Closeness.ttf +0 -0
  148. package/public/res/fonts/WARGAMES.TTF +0 -0
  149. package/public/res/fonts/readme.txt +5 -0
  150. package/public/res/fonts/stormfaze.ttf +0 -0
  151. package/public/res/icons/512.png +0 -0
  152. package/public/res/icons/webgpu-horizontal.svg +45 -0
  153. package/public/res/meshes/blender/cube.blend +0 -0
  154. package/public/res/meshes/blender/cube.blend1 +0 -0
  155. package/public/res/meshes/blender/cube.mtl +12 -0
  156. package/public/res/meshes/blender/cube.obj +46 -0
  157. package/public/res/meshes/blender/cube.png +0 -0
  158. package/public/res/meshes/blender/cubeSmartUV.blend +0 -0
  159. package/public/res/meshes/blender/cubeSmartUV.mtl +12 -0
  160. package/public/res/meshes/blender/cubeSmartUV.obj +46 -0
  161. package/public/res/meshes/blender/lopta.mtl +10 -0
  162. package/public/res/meshes/blender/lopta.obj +3402 -0
  163. package/public/res/meshes/blender/piramyd.blend +0 -0
  164. package/public/res/meshes/blender/piramyd.blend1 +0 -0
  165. package/public/res/meshes/blender/piramyd.js +42 -0
  166. package/public/res/meshes/blender/piramyd.mtl +10 -0
  167. package/public/res/meshes/blender/piramyd.obj +18696 -0
  168. package/public/res/meshes/blender/piramyd1.js +42 -0
  169. package/public/res/meshes/blender/sphepe.blend +0 -0
  170. package/public/res/meshes/blender/sphepe.blend1 +0 -0
  171. package/public/res/meshes/blender/sphere.mtl +10 -0
  172. package/public/res/meshes/blender/sphere.obj +3402 -0
  173. package/public/res/meshes/blender/welcomeTextblend.blend +0 -0
  174. package/public/res/meshes/dragon/stanfordDragonData.js +5 -0
  175. package/public/res/meshes/jamb/bg.blend +0 -0
  176. package/public/res/meshes/jamb/bg.blend1 +0 -0
  177. package/public/res/meshes/jamb/bg.mtl +12 -0
  178. package/public/res/meshes/jamb/bg.obj +17 -0
  179. package/public/res/meshes/jamb/bg.png +0 -0
  180. package/public/res/meshes/jamb/dice-default.png +0 -0
  181. package/public/res/meshes/jamb/dice-mark.png +0 -0
  182. package/public/res/meshes/jamb/dice.mtl +12 -0
  183. package/public/res/meshes/jamb/dice.obj +40 -0
  184. package/public/res/meshes/jamb/dice.png +0 -0
  185. package/public/res/meshes/jamb/jamb-title.mtl +12 -0
  186. package/public/res/meshes/jamb/jamb-title.obj +26008 -0
  187. package/public/res/meshes/jamb/jamb.blend +0 -0
  188. package/public/res/meshes/jamb/jamb.blend1 +0 -0
  189. package/public/res/meshes/jamb/logo.png +0 -0
  190. package/public/res/meshes/jamb/nidzaDice.blend +0 -0
  191. package/public/res/meshes/jamb/nidzaDice.blend1 +0 -0
  192. package/public/res/meshes/jamb/pile.blend +0 -0
  193. package/public/res/meshes/jamb/simpleCube.blend +0 -0
  194. package/public/res/meshes/jamb/simpleCube.blend1 +0 -0
  195. package/public/res/meshes/jamb/sounds/roll1.wav +0 -0
  196. package/public/res/meshes/jamb/text.png +0 -0
  197. package/public/res/meshes/obj/armor.obj +319 -0
  198. package/public/res/meshes/obj/armor.png +0 -0
  199. package/public/res/meshes/objs-sequence/swat-walk-pistol_000001.mtl +22 -0
  200. package/public/res/meshes/objs-sequence/swat-walk-pistol_000001.obj +23264 -0
  201. package/public/res/meshes/objs-sequence/swat-walk-pistol_000002.mtl +22 -0
  202. package/public/res/meshes/objs-sequence/swat-walk-pistol_000002.obj +23261 -0
  203. package/public/res/meshes/objs-sequence/swat-walk-pistol_000003.mtl +22 -0
  204. package/public/res/meshes/objs-sequence/swat-walk-pistol_000003.obj +23264 -0
  205. package/public/res/meshes/objs-sequence/swat-walk-pistol_000004.mtl +22 -0
  206. package/public/res/meshes/objs-sequence/swat-walk-pistol_000004.obj +23261 -0
  207. package/public/res/meshes/objs-sequence/swat-walk-pistol_000005.mtl +22 -0
  208. package/public/res/meshes/objs-sequence/swat-walk-pistol_000005.obj +23261 -0
  209. package/public/res/meshes/objs-sequence/swat-walk-pistol_000006.mtl +22 -0
  210. package/public/res/meshes/objs-sequence/swat-walk-pistol_000006.obj +23261 -0
  211. package/public/res/meshes/objs-sequence/swat-walk-pistol_000007.mtl +22 -0
  212. package/public/res/meshes/objs-sequence/swat-walk-pistol_000007.obj +23264 -0
  213. package/public/res/meshes/objs-sequence/swat-walk-pistol_000008.mtl +22 -0
  214. package/public/res/meshes/objs-sequence/swat-walk-pistol_000008.obj +23263 -0
  215. package/public/res/meshes/objs-sequence/swat-walk-pistol_000009.mtl +22 -0
  216. package/public/res/meshes/objs-sequence/swat-walk-pistol_000009.obj +23264 -0
  217. package/public/res/meshes/objs-sequence/swat-walk-pistol_000010.mtl +22 -0
  218. package/public/res/meshes/objs-sequence/swat-walk-pistol_000010.obj +23260 -0
  219. package/public/res/meshes/objs-sequence/swat-walk-pistol_000011.mtl +22 -0
  220. package/public/res/meshes/objs-sequence/swat-walk-pistol_000011.obj +23262 -0
  221. package/public/res/meshes/objs-sequence/swat-walk-pistol_000012.mtl +22 -0
  222. package/public/res/meshes/objs-sequence/swat-walk-pistol_000012.obj +23262 -0
  223. package/public/res/meshes/objs-sequence/swat-walk-pistol_000013.mtl +22 -0
  224. package/public/res/meshes/objs-sequence/swat-walk-pistol_000013.obj +23263 -0
  225. package/public/res/meshes/objs-sequence/swat-walk-pistol_000014.mtl +22 -0
  226. package/public/res/meshes/objs-sequence/swat-walk-pistol_000014.obj +23262 -0
  227. package/public/res/meshes/objs-sequence/swat-walk-pistol_000015.mtl +22 -0
  228. package/public/res/meshes/objs-sequence/swat-walk-pistol_000015.obj +23263 -0
  229. package/public/res/meshes/objs-sequence/swat-walk-pistol_000016.mtl +22 -0
  230. package/public/res/meshes/objs-sequence/swat-walk-pistol_000016.obj +23264 -0
  231. package/public/res/meshes/objs-sequence/swat-walk-pistol_000017.mtl +22 -0
  232. package/public/res/meshes/objs-sequence/swat-walk-pistol_000017.obj +23263 -0
  233. package/public/res/meshes/objs-sequence/swat-walk-pistol_000018.mtl +22 -0
  234. package/public/res/meshes/objs-sequence/swat-walk-pistol_000018.obj +23261 -0
  235. package/public/res/meshes/objs-sequence/swat-walk-pistol_000019.mtl +22 -0
  236. package/public/res/meshes/objs-sequence/swat-walk-pistol_000019.obj +23263 -0
  237. package/public/res/meshes/objs-sequence/swat-walk-pistol_000020.mtl +22 -0
  238. package/public/res/meshes/objs-sequence/swat-walk-pistol_000020.obj +23261 -0
  239. package/public/res/meshes/shapes/star1.obj +60 -0
  240. package/public/res/multilang/en.json +39 -0
  241. package/public/res/multilang/sr.json +39 -0
  242. package/public/res/textures/default.png +0 -0
  243. package/public/res/textures/rust.jpg +0 -0
  244. package/public/res/textures/tex1.jpg +0 -0
  245. package/public/res/videos/readme.txt +2 -0
  246. package/public/res/videos/tunel.mp4 +0 -0
  247. package/public/test.html +636 -0
  248. package/public/three-test.js +165 -0
  249. package/public/worker.html +25 -0
  250. package/src/engine/ball.js +482 -0
  251. package/src/engine/cube.js +496 -0
  252. package/src/engine/engine.js +404 -0
  253. package/src/engine/final/adaptJSON1.js +53 -0
  254. package/src/engine/final/utils2.js +63 -0
  255. package/src/engine/lights.js +153 -0
  256. package/src/engine/loader-obj.js +473 -0
  257. package/src/engine/materials.js +295 -0
  258. package/src/engine/matrix-class.js +252 -0
  259. package/src/engine/mesh-obj.js +574 -0
  260. package/src/engine/raycast.js +218 -0
  261. package/src/engine/utils.js +881 -0
  262. package/src/libs/mat.js +0 -0
  263. package/src/multilang/lang.js +35 -0
  264. package/src/physics/matrix-ammo.js +363 -0
  265. package/src/shaders/fragment.video.wgsl.js +83 -0
  266. package/src/shaders/fragment.wgsl.js +75 -0
  267. package/src/shaders/shaders.js +51 -0
  268. package/src/shaders/standard-matrix-engine-shaders/standard-matrix-engine-fs.glsl +56 -0
  269. package/src/shaders/standard-matrix-engine-shaders/standard-matrix-engine-vs.glsl +75 -0
  270. package/src/shaders/vertex.wgsl.js +54 -0
  271. package/src/shaders/vertexShadow.wgsl.js +20 -0
  272. package/src/sounds/sounds.js +69 -0
  273. package/src/world.js +474 -0
@@ -0,0 +1,75 @@
1
+ #version 300 es
2
+ in vec3 aVertexPosition;
3
+ in vec3 aVertexNormal;
4
+ in vec2 aTextureCoord;
5
+
6
+ uniform mat4 uMVMatrix;
7
+ uniform mat4 uPMatrix;
8
+ uniform mat3 uNMatrix;
9
+ uniform vec3 uAmbientColor;
10
+ uniform vec3 uLightingDirection;
11
+ uniform vec3 uDirectionalColor;
12
+ uniform bool uUseLighting;
13
+ out vec2 vTextureCoord;
14
+ out vec3 vLightWeighting;
15
+
16
+ // Spot
17
+ uniform vec3 u_lightWorldPosition;
18
+ out vec3 v_normal;
19
+ // out vec3 v_normal_cubemap;
20
+ out vec3 v_surfaceToLight;
21
+ out vec3 v_surfaceToView;
22
+
23
+ // Specular
24
+ out mat4 uMVMatrixINTER;
25
+ out mat3 uNMatrixINTER;
26
+ out mat4 uPMatrixINNTER;
27
+
28
+ in vec4 specularColor;
29
+ out vec4 vColor;
30
+ out vec3 vNormal;
31
+ out vec4 vPosition;
32
+ out float vDist;
33
+
34
+ void main(void) {
35
+ uMVMatrixINTER = uMVMatrix;
36
+ uNMatrixINTER = uNMatrix;
37
+ uPMatrixINNTER = uPMatrix;
38
+
39
+ // GLOBAL POS SPECULAR
40
+ vColor = specularColor;
41
+ vNormal = normalize(uNMatrix * vec3(aVertexNormal));
42
+ // Calculate the modelView of the model, and set the vPosition
43
+ // mat4 modelViewMatrix = uViewMatrix * uModelMatrix;
44
+ vPosition = uMVMatrix * vec4(1, 1, 1, 1);
45
+ vDist = gl_Position.w;
46
+
47
+ // SPOT
48
+ // orient the normals and pass to the fragment shader
49
+ v_normal = mat3(uNMatrix) * aVertexNormal;
50
+
51
+ // normalize
52
+ // v_normal_cubemap = normalize(aVertexPosition.xyz);
53
+
54
+ // compute the world position of the surfoace
55
+ vec3 surfaceWorldPosition = (uNMatrix * aVertexPosition).xyz;
56
+
57
+ // compute the vector of the surface to the light
58
+ // and pass it to the fragment shader
59
+ v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;
60
+
61
+ // compute the vector of the surface to the view/camera
62
+ // and pass it to the fragment shader
63
+ v_surfaceToView = (uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0f)).xyz - surfaceWorldPosition;
64
+
65
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0f);
66
+ vTextureCoord = aTextureCoord;
67
+
68
+ if(!uUseLighting) {
69
+ vLightWeighting = vec3(1.0f, 1.0f, 1.0f);
70
+ } else {
71
+ vec3 transformedNormal = uNMatrix * aVertexNormal;
72
+ float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0f);
73
+ vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
74
+ }
75
+ }
@@ -0,0 +1,54 @@
1
+ export let vertexWGSL = `struct Scene {
2
+ lightViewProjMatrix: mat4x4f,
3
+ cameraViewProjMatrix: mat4x4f,
4
+ lightPos: vec3f,
5
+ }
6
+
7
+ struct Model {
8
+ modelMatrix: mat4x4f,
9
+ }
10
+
11
+ @group(0) @binding(0) var<uniform> scene : Scene;
12
+ @group(1) @binding(0) var<uniform> model : Model;
13
+
14
+ struct VertexOutput {
15
+ @location(0) shadowPos: vec3f,
16
+ @location(1) fragPos: vec3f,
17
+ @location(2) fragNorm: vec3f,
18
+ @location(3) uv : vec2f,
19
+
20
+ @builtin(position) Position: vec4f,
21
+ }
22
+
23
+ @vertex
24
+ fn main(
25
+ @location(0) position: vec3f,
26
+ @location(1) normal: vec3f,
27
+ @location(2) uv : vec2f
28
+ ) -> VertexOutput {
29
+ var output : VertexOutput;
30
+
31
+ // XY is in (-1, 1) space, Z is in (0, 1) space
32
+ let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
33
+
34
+ // Convert XY to (0, 1)
35
+ // Y is flipped because texture coords are Y-down.
36
+ output.shadowPos = vec3(
37
+ posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),
38
+ posFromLight.z
39
+ );
40
+
41
+ // follewed camera code
42
+ // output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
43
+ // output.fragPos = output.Position.xyz;
44
+ // output.fragNorm = normal;
45
+
46
+ let worldPos = model.modelMatrix * vec4(position, 1.0);
47
+ output.Position = scene.cameraViewProjMatrix * worldPos;
48
+ output.fragPos = worldPos.xyz; // ✅ world space
49
+
50
+ output.fragNorm = normalize((model.modelMatrix * vec4(normal, 0.0)).xyz);
51
+ output.uv = uv;
52
+ return output;
53
+ }
54
+ `;
@@ -0,0 +1,20 @@
1
+ export let vertexShadowWGSL = `struct Scene {
2
+ lightViewProjMatrix: mat4x4f,
3
+ cameraViewProjMatrix: mat4x4f,
4
+ lightPos: vec3f,
5
+ }
6
+
7
+ struct Model {
8
+ modelMatrix: mat4x4f,
9
+ }
10
+
11
+ @group(0) @binding(0) var<uniform> scene : Scene;
12
+ @group(1) @binding(0) var<uniform> model : Model;
13
+
14
+ @vertex
15
+ fn main(
16
+ @location(0) position: vec3f
17
+ ) -> @builtin(position) vec4f {
18
+ return scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1);
19
+ }
20
+ `
@@ -0,0 +1,69 @@
1
+ export class MatrixSounds {
2
+
3
+ constructor() {
4
+ this.volume = 0.5;
5
+ this.audios = {};
6
+ this.enabled = true; // 🔇 global flag to mute/allow audio
7
+ }
8
+
9
+ muteAll() {
10
+ this.enabled = false;
11
+ Object.values(this.audios).forEach(audio => audio.pause());
12
+ }
13
+
14
+ unmuteAll() {
15
+ this.enabled = true;
16
+ }
17
+
18
+ createClones(c, name, path) {
19
+ for(let x = 1;x < c;x++) {
20
+ const a = new Audio(path);
21
+ a.id = name + x;
22
+ a.volume = this.volume;
23
+ this.audios[name + x] = a;
24
+ document.body.append(a);
25
+ }
26
+ }
27
+
28
+ createAudio(name, path, useClones) {
29
+ const a = new Audio(path);
30
+ a.id = name;
31
+ a.volume = this.volume;
32
+ this.audios[name] = a;
33
+ document.body.append(a);
34
+ if(typeof useClones !== 'undefined') {
35
+ this.createClones(useClones, name, path);
36
+ }
37
+ }
38
+
39
+ play(name) {
40
+ if(!this.enabled) return; // 🔇 prevent playing if muted
41
+
42
+ const audio = this.audios[name];
43
+ if(!audio) return;
44
+
45
+ if(audio.paused) {
46
+ audio.play().catch((e) => {
47
+ if(e.name !== 'NotAllowedError') console.warn("sounds error:", e);
48
+ });
49
+ } else {
50
+ this.tryClone(name);
51
+ }
52
+ }
53
+
54
+ tryClone(name) {
55
+ if(!this.enabled) return; // 🔇 prevent playing clones
56
+
57
+ let cc = 1;
58
+ try {
59
+ while(this.audios[name + cc] && this.audios[name + cc].paused === false) {
60
+ cc++;
61
+ }
62
+ if(this.audios[name + cc]) {
63
+ this.audios[name + cc].play();
64
+ }
65
+ } catch(err) {
66
+ console.warn("Clone play failed:", err);
67
+ }
68
+ }
69
+ }
package/src/world.js ADDED
@@ -0,0 +1,474 @@
1
+ import {mat4, vec3} from "wgpu-matrix";
2
+ import MEBall from "./engine/ball.js";
3
+ import MECube from './engine/cube.js';
4
+ import {ArcballCamera, WASDCamera} from "./engine/engine.js";
5
+ import {createInputHandler} from "./engine/engine.js";
6
+ import MEMeshObj from "./engine/mesh-obj.js";
7
+ import MatrixAmmo from "./physics/matrix-ammo.js";
8
+ import {LOG_WARN, genName, mb, scriptManager, urlQuery} from "./engine/utils.js";
9
+ import {MultiLang} from "./multilang/lang.js";
10
+ import {MatrixSounds} from "./sounds/sounds.js";
11
+ import {play} from "./engine/loader-obj.js";
12
+ import {SpotLight} from "./engine/lights.js";
13
+
14
+ export default class MatrixEngineWGPU {
15
+
16
+ mainRenderBundle = [];
17
+ lightContainer = [];
18
+ frame = () => {};
19
+
20
+ entityHolder = [];
21
+
22
+ entityArgPass = {
23
+ loadOp: 'clear',
24
+ storeOp: 'store',
25
+ depthLoadOp: 'clear',
26
+ depthStoreOp: 'store'
27
+ }
28
+
29
+ matrixAmmo = new MatrixAmmo();
30
+ matrixSounds = new MatrixSounds();
31
+
32
+ // The input handler
33
+ constructor(options, callback) {
34
+ // console.log('typeof options ', typeof options )
35
+ if(typeof options == 'undefined' || typeof options == "function") {
36
+ this.options = {
37
+ useSingleRenderPass: true,
38
+ canvasSize: 'fullscreen',
39
+ canvasId: 'canvas1',
40
+ mainCameraParams: {
41
+ type: 'WASD',
42
+ responseCoef: 2000
43
+ },
44
+ clearColor: {r: 0.584, g: 0, b: 0.239, a: 1.0}
45
+ }
46
+ callback = options;
47
+ }
48
+ if(typeof options.clearColor === 'undefined') {
49
+ options.clearColor = {r: 0.584, g: 0, b: 0.239, a: 1.0};
50
+ }
51
+ if(typeof options.canvasId === 'undefined') {
52
+ options.canvasId = 'canvas1';
53
+ }
54
+ if(typeof options.mainCameraParams === 'undefined') {
55
+ options.mainCameraParams = {
56
+ type: 'WASD',
57
+ responseCoef: 2000
58
+ }
59
+ }
60
+ this.options = options;
61
+ this.mainCameraParams = options.mainCameraParams;
62
+
63
+ const target = this.options.appendTo || document.body;
64
+ var canvas = document.createElement('canvas')
65
+ canvas.id = this.options.canvasId;
66
+ if(this.options.canvasSize == 'fullscreen') {
67
+ canvas.width = window.innerWidth;
68
+ canvas.height = window.innerHeight;
69
+ } else {
70
+ canvas.width = this.options.canvasSize.w;
71
+ canvas.height = this.options.canvasSize.h;
72
+ }
73
+ target.append(canvas);
74
+
75
+ // The camera types
76
+ const initialCameraPosition = vec3.create(0, 0, 0);
77
+ // console.log('passed : o.mainCameraParams.responseCoef ', o.mainCameraParams.responseCoef)
78
+ this.mainCameraParams = {
79
+ type: this.options.mainCameraParams.type,
80
+ responseCoef: this.options.mainCameraParams.responseCoef
81
+ }
82
+
83
+ this.cameras = {
84
+ arcball: new ArcballCamera({position: initialCameraPosition}),
85
+ WASD: new WASDCamera({position: initialCameraPosition}),
86
+ };
87
+
88
+ this.label = new MultiLang()
89
+ if(urlQuery.lang != null) {
90
+ this.label.loadMultilang(urlQuery.lang).then((r) => {
91
+ this.label.get = r;
92
+ });
93
+ } else {
94
+ this.label.loadMultilang().then((r) => {
95
+ this.label.get = r;
96
+ });
97
+ }
98
+
99
+ this.init({canvas, callback})
100
+ }
101
+
102
+ init = async ({canvas, callback}) => {
103
+ this.canvas = canvas;
104
+ this.adapter = await navigator.gpu.requestAdapter();
105
+ this.device = await this.adapter.requestDevice({
106
+ extensions: ["ray_tracing"]
107
+ });
108
+
109
+ // Maybe works in ssl with webworkers...
110
+ // const adapterInfo = await this.adapter.requestAdapterInfo();
111
+ // var test = this.adapter.features()
112
+ // console.log(adapterInfo.vendor);
113
+ // console.log('test' + test);
114
+ // console.log("FEATURES : " + this.adapter.features)
115
+
116
+ this.context = canvas.getContext('webgpu');
117
+
118
+ const devicePixelRatio = window.devicePixelRatio;
119
+ canvas.width = canvas.clientWidth * devicePixelRatio;
120
+ canvas.height = canvas.clientHeight * devicePixelRatio;
121
+ const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
122
+
123
+ this.context.configure({
124
+ device: this.device,
125
+ format: presentationFormat,
126
+ alphaMode: 'premultiplied',
127
+ });
128
+
129
+ if(this.options.useSingleRenderPass == true) {
130
+ this.frame = this.frameSinglePass;
131
+ } else {
132
+ this.frame = this.framePassPerObject;
133
+ }
134
+
135
+ // Global SCENE BUFFER Good idea for future
136
+ // this.sceneUniformBuffer = this.device.createBuffer({
137
+ // // Two 4x4 viewProj matrices,
138
+ // // one for the camera and one for the light.
139
+ // // Then a vec3 for the light position.
140
+ // // Rounded to the nearest multiple of 16.
141
+ // size: 2 * 4 * 16 + 4 * 4,
142
+ // usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
143
+ // });
144
+
145
+ this.inputHandler = createInputHandler(window, canvas);
146
+
147
+ this.run(callback)
148
+ };
149
+
150
+ getSceneObjectByName(name) {
151
+ return this.mainRenderBundle.find((sceneObject) => sceneObject.name === name)
152
+ }
153
+
154
+ // Not in use for now
155
+ addCube = (o) => {
156
+ if(typeof o === 'undefined') {
157
+ var o = {
158
+ scale: 1,
159
+ position: {x: 0, y: 0, z: -4},
160
+ texturesPaths: ['./res/textures/default.png'],
161
+ rotation: {x: 0, y: 0, z: 0},
162
+ rotationSpeed: {x: 0, y: 0, z: 0},
163
+ entityArgPass: this.entityArgPass,
164
+ cameras: this.cameras,
165
+ mainCameraParams: this.mainCameraParams
166
+ }
167
+ } else {
168
+ if(typeof o.position === 'undefined') {o.position = {x: 0, y: 0, z: -4}}
169
+ if(typeof o.rotation === 'undefined') {o.rotation = {x: 0, y: 0, z: 0}}
170
+ if(typeof o.rotationSpeed === 'undefined') {o.rotationSpeed = {x: 0, y: 0, z: 0}}
171
+ if(typeof o.texturesPaths === 'undefined') {o.texturesPaths = ['./res/textures/default.png']}
172
+ if(typeof o.scale === 'undefined') {o.scale = 1;}
173
+ if(typeof o.mainCameraParams === 'undefined') {o.mainCameraParams = this.mainCameraParams}
174
+ o.entityArgPass = this.entityArgPass;
175
+ o.cameras = this.cameras;
176
+ }
177
+
178
+ if(typeof o.physics === 'undefined') {
179
+ o.physics = {
180
+ scale: [1, 1, 1],
181
+ enabled: true,
182
+ geometry: "Sphere",
183
+ radius: o.scale,
184
+ name: o.name,
185
+ rotation: o.rotation
186
+ }
187
+ }
188
+ if(typeof o.position !== 'undefined') {o.physics.position = o.position;}
189
+ if(typeof o.physics.enabled === 'undefined') {o.physics.enabled = true}
190
+ if(typeof o.physics.geometry === 'undefined') {o.physics.geometry = "Sphere"}
191
+ if(typeof o.physics.radius === 'undefined') {o.physics.radius = o.scale}
192
+ if(typeof o.physics.mass === 'undefined') {o.physics.mass = 1;}
193
+ if(typeof o.physics.name === 'undefined') {o.physics.name = o.name;}
194
+ if(typeof o.physics.scale === 'undefined') {o.physics.scale = o.scale;}
195
+ if(typeof o.physics.rotation === 'undefined') {o.physics.rotation = o.rotation;}
196
+
197
+ let myCube1 = new MECube(this.canvas, this.device, this.context, o)
198
+ if(o.physics.enabled == true) {
199
+ this.matrixAmmo.addPhysics(myCube1, o.physics);
200
+ }
201
+ this.mainRenderBundle.push(myCube1);
202
+ }
203
+
204
+ // Not in use for now
205
+ addBall = (o) => {
206
+ if(typeof o === 'undefined') {
207
+ var o = {
208
+ scale: 1,
209
+ position: {x: 0, y: 0, z: -4},
210
+ texturesPaths: ['./res/textures/default.png'],
211
+ rotation: {x: 0, y: 0, z: 0},
212
+ rotationSpeed: {x: 0, y: 0, z: 0},
213
+ entityArgPass: this.entityArgPass,
214
+ cameras: this.cameras,
215
+ mainCameraParams: this.mainCameraParams
216
+ }
217
+ } else {
218
+ if(typeof o.position === 'undefined') {o.position = {x: 0, y: 0, z: -4}}
219
+ if(typeof o.rotation === 'undefined') {o.rotation = {x: 0, y: 0, z: 0}}
220
+ if(typeof o.rotationSpeed === 'undefined') {o.rotationSpeed = {x: 0, y: 0, z: 0}}
221
+ if(typeof o.texturesPaths === 'undefined') {o.texturesPaths = ['./res/textures/default.png']}
222
+ if(typeof o.mainCameraParams === 'undefined') {o.mainCameraParams = this.mainCameraParams}
223
+ if(typeof o.scale === 'undefined') {o.scale = 1;}
224
+ o.entityArgPass = this.entityArgPass;
225
+ o.cameras = this.cameras;
226
+ }
227
+
228
+ if(typeof o.physics === 'undefined') {
229
+ o.physics = {
230
+ scale: [1, 1, 1],
231
+ enabled: true,
232
+ geometry: "Sphere",
233
+ radius: o.scale,
234
+ name: o.name,
235
+ rotation: o.rotation
236
+ }
237
+ }
238
+ if(typeof o.position !== 'undefined') {o.physics.position = o.position;}
239
+ if(typeof o.physics.enabled === 'undefined') {o.physics.enabled = true}
240
+ if(typeof o.physics.geometry === 'undefined') {o.physics.geometry = "Sphere"}
241
+ if(typeof o.physics.radius === 'undefined') {o.physics.radius = o.scale}
242
+ if(typeof o.physics.mass === 'undefined') {o.physics.mass = 1;}
243
+ if(typeof o.physics.name === 'undefined') {o.physics.name = o.name;}
244
+ if(typeof o.physics.scale === 'undefined') {o.physics.scale = o.scale;}
245
+ if(typeof o.physics.rotation === 'undefined') {o.physics.rotation = o.rotation;}
246
+
247
+ let myBall1 = new MEBall(this.canvas, this.device, this.context, o);
248
+ if(o.physics.enabled == true) {
249
+ this.matrixAmmo.addPhysics(myBall1, o.physics)
250
+ }
251
+ this.mainRenderBundle.push(myBall1);
252
+ }
253
+
254
+ addLight(o) {
255
+ // test light global; entity
256
+ const camera = this.cameras[this.mainCameraParams.type];
257
+ let newLight = new SpotLight(camera, this.inputHandler);
258
+ newLight.prepareBuffer(this.device);
259
+ this.lightContainer.push(newLight);
260
+ console.log('Add light : ', newLight);
261
+ }
262
+
263
+ addMeshObj = (o, clearColor = this.options.clearColor) => {
264
+ if(typeof o.name === 'undefined') {o.name = genName(9)}
265
+ if(typeof o.position === 'undefined') {o.position = {x: 0, y: 0, z: -4}}
266
+ if(typeof o.rotation === 'undefined') {o.rotation = {x: 0, y: 0, z: 0}}
267
+ if(typeof o.rotationSpeed === 'undefined') {o.rotationSpeed = {x: 0, y: 0, z: 0}}
268
+ if(typeof o.texturesPaths === 'undefined') {o.texturesPaths = ['./res/textures/default.png']}
269
+ if(typeof o.mainCameraParams === 'undefined') {o.mainCameraParams = this.mainCameraParams}
270
+ if(typeof o.scale === 'undefined') {o.scale = [1, 1, 1];}
271
+ if(typeof o.raycast === 'undefined') {o.raycast = {enabled: false, radius: 2}}
272
+ o.entityArgPass = this.entityArgPass;
273
+ o.cameras = this.cameras;
274
+ if(typeof o.physics === 'undefined') {
275
+ o.physics = {
276
+ scale: [1, 1, 1],
277
+ enabled: true,
278
+ geometry: "Sphere",// must be fixed<<
279
+ radius: (typeof o.scale == Number ? o.scale : o.scale[0]),
280
+ name: o.name,
281
+ rotation: o.rotation
282
+ }
283
+ }
284
+ if(typeof o.physics.enabled === 'undefined') {o.physics.enabled = true}
285
+ if(typeof o.physics.geometry === 'undefined') {o.physics.geometry = "Cube"}
286
+ if(typeof o.physics.radius === 'undefined') {o.physics.radius = o.scale}
287
+ if(typeof o.physics.mass === 'undefined') {o.physics.mass = 1;}
288
+ if(typeof o.physics.name === 'undefined') {o.physics.name = o.name;}
289
+ if(typeof o.physics.scale === 'undefined') {o.physics.scale = o.scale;}
290
+ if(typeof o.physics.rotation === 'undefined') {o.physics.rotation = o.rotation;}
291
+ o.physics.position = o.position;
292
+ // console.log('Mesh procedure', o)
293
+ // TEST OBJS SEQ ANIMS
294
+ if(typeof o.objAnim == 'undefined' || typeof o.objAnim == null) {
295
+ o.objAnim = null;
296
+ } else {
297
+ // console.log('o.anim', o.objAnim)
298
+ if(typeof o.objAnim.animations !== 'undefined') {
299
+ o.objAnim.play = play;
300
+ }
301
+ // no need for single test it in future
302
+ o.objAnim.meshList = o.objAnim.meshList;
303
+
304
+ if(typeof o.mesh === 'undefined') {
305
+ o.mesh = o.objAnim.meshList[0];
306
+ console.info('objSeq animation is active.');
307
+ }
308
+ // scale for all second option!
309
+ o.objAnim.scaleAll = function(s) {
310
+ for(var k in this.meshList) {
311
+ console.log('SCALE');
312
+ this.meshList[k].setScale(s);
313
+ }
314
+ }
315
+ }
316
+ let myMesh1 = new MEMeshObj(this.canvas, this.device, this.context, o);
317
+ myMesh1.lightContainer = this.lightContainer;
318
+ myMesh1.inputHandler = this.inputHandler;
319
+ myMesh1.clearColor = clearColor;
320
+ if(o.physics.enabled == true) {
321
+ this.matrixAmmo.addPhysics(myMesh1, o.physics)
322
+ }
323
+ this.mainRenderBundle.push(myMesh1);
324
+ }
325
+
326
+ run(callback) {
327
+ setTimeout(() => {requestAnimationFrame(this.frame)}, 500)
328
+ setTimeout(() => {callback(this)}, 20)
329
+ }
330
+
331
+ destroyProgram = () => {
332
+ this.mainRenderBundle = [];
333
+ this.canvas.remove();
334
+ }
335
+
336
+ test = () => {
337
+ const now = Date.now();
338
+ // First frame safety
339
+ let dt = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
340
+ if(!this.lastFrameMS) {dt = 16;}
341
+ this.lastFrameMS = now;
342
+ const camera = this.cameras[this.mainCameraParams.type];
343
+
344
+ // engine, once per frame
345
+ // const camera = this.cameras[this.mainCameraParams.type];
346
+ camera.update(dt, this.inputHandler());
347
+ const camVP = mat4.multiply(camera.projectionMatrix, camera.view); // P * V
348
+
349
+ for(const mesh of this.mainRenderBundle) {
350
+ // scene buffer layout = 0..63 lightVP, 64..127 camVP, 128..143 lightPos(+pad)
351
+ this.device.queue.writeBuffer(
352
+ mesh.sceneUniformBuffer,
353
+ 64, // cameraViewProjMatrix offset
354
+ camVP.buffer,
355
+ camVP.byteOffset,
356
+ camVP.byteLength
357
+ );
358
+ }
359
+ // engine frame
360
+ // camera.update(dt, this.inputHandler());
361
+ // const camVP = mat4.multiply(camera.projectionMatrix, camera.view);
362
+
363
+ // for(const mesh of this.mainRenderBundle) {
364
+ // // Light’s viewProj should come from your SpotLight
365
+ // // If you have multiple lights, you’ll need an array UBO or multiple passes.
366
+ // const sceneData = new Float32Array(16 + 16 + 4); // lightVP, camVP, lightPos(+pad)
367
+ // sceneData.set(this.lightContainer[0].viewProjMatrix, 0);
368
+ // sceneData.set(camVP, 16);
369
+ // sceneData.set(this.lightContainer[0].position, 32);
370
+
371
+ // // sceneUniformBuffer
372
+ // this.device.queue.writeBuffer(
373
+ // mesh.sceneUniformBuffer, // or a shared one if/when you centralize it
374
+ // 0,
375
+ // sceneData.buffer,
376
+ // sceneData.byteOffset,
377
+ // sceneData.byteLength
378
+ // );
379
+ // }
380
+ }
381
+
382
+ frameSinglePass = () => {
383
+ if(typeof this.mainRenderBundle == 'undefined' || this.mainRenderBundle.length == 0) {
384
+ setTimeout(() => {requestAnimationFrame(this.frame)}, 200);
385
+ return;
386
+ }
387
+ try {
388
+ let shadowPass = null;
389
+ let renderPass;
390
+ let commandEncoder = this.device.createCommandEncoder();
391
+
392
+ this.test()
393
+ // 1️⃣ Update light data (position, direction, uniforms)
394
+ for(const light of this.lightContainer) {
395
+ light.updateLightBuffer();
396
+ this.mainRenderBundle.forEach((meItem, index) => {
397
+ light.updateSceneUniforms(this.mainRenderBundle, this.cameras.WASD);
398
+ })
399
+ }
400
+
401
+ this.mainRenderBundle.forEach((meItem, index) => {meItem.position.update()})
402
+ if(this.matrixAmmo) this.matrixAmmo.updatePhysics();
403
+
404
+ // no cast WORKING
405
+ // this.mainRenderBundle.forEach((meItem, index) => {
406
+ // meItem.draw(commandEncoder);
407
+
408
+ // shadowPass = commandEncoder.beginRenderPass(meItem.shadowPassDescriptor);
409
+ // shadowPass.setPipeline(meItem.shadowPipeline);
410
+ // meItem.drawShadows(shadowPass);
411
+ // shadowPass.end();
412
+ // })
413
+
414
+ // cast!
415
+ const firstItem = this.mainRenderBundle[0];
416
+ shadowPass = commandEncoder.beginRenderPass(firstItem.shadowPassDescriptor);
417
+ shadowPass.setPipeline(firstItem.shadowPipeline);
418
+ for(const meItem of this.mainRenderBundle) {
419
+ // meItem.draw(commandEncoder);
420
+ meItem.drawShadows(shadowPass); // Draw ALL objects
421
+ }
422
+ shadowPass.end();
423
+
424
+ this.mainRenderBundle.forEach((meItem, index) => {
425
+ if(index == 0) {
426
+ meItem.draw(commandEncoder);
427
+ meItem.renderPassDescriptor.colorAttachments[0].view =
428
+ this.context.getCurrentTexture().createView();
429
+ renderPass = commandEncoder.beginRenderPass(meItem.renderPassDescriptor);
430
+ renderPass.setPipeline(meItem.pipeline);
431
+ } else {
432
+ meItem.draw(commandEncoder);
433
+ }
434
+ })
435
+
436
+ this.mainRenderBundle.forEach((meItem, index) => {
437
+ meItem.drawElements(renderPass);
438
+ })
439
+ if(renderPass) renderPass.end();
440
+
441
+ this.device.queue.submit([commandEncoder.finish()]);
442
+ requestAnimationFrame(this.frame);
443
+ } catch(err) {
444
+ console.log('%cDraw func (err):' + err, LOG_WARN)
445
+ requestAnimationFrame(this.frame);
446
+ }
447
+ }
448
+
449
+ framePassPerObject = () => {
450
+ let commandEncoder = this.device.createCommandEncoder();
451
+ this.matrixAmmo.updatePhysics();
452
+ this.mainRenderBundle.forEach((meItem, index) => {
453
+ if(index === 0) {
454
+ if(meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'clear';
455
+ } else {
456
+ if(meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'load';
457
+ }
458
+ // Update transforms, physics, etc. (optional)
459
+ meItem.draw(commandEncoder); // optional: if this does per-frame updates
460
+ if(meItem.renderBundle) {
461
+ // Set up view per object
462
+ meItem.renderPassDescriptor.colorAttachments[0].view =
463
+ this.context.getCurrentTexture().createView();
464
+ const passEncoder = commandEncoder.beginRenderPass(meItem.renderPassDescriptor);
465
+ passEncoder.executeBundles([meItem.renderBundle]); // ✅ Use only this bundle
466
+ passEncoder.end();
467
+ } else {
468
+ meItem.draw(commandEncoder); // fallback if no renderBundle
469
+ }
470
+ });
471
+ this.device.queue.submit([commandEncoder.finish()]);
472
+ requestAnimationFrame(this.frame);
473
+ }
474
+ }