@needle-tools/engine 4.5.5-next.f053174 → 4.5.6

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 (1044) hide show
  1. package/CHANGELOG.md +3740 -3740
  2. package/LICENSE.md +10 -10
  3. package/README.md +64 -64
  4. package/components.needle.json +1 -1
  5. package/dist/{needle-engine.bundle-DFfLpZpn.min.js → needle-engine.bundle-2nTaeeW3.min.js} +62 -62
  6. package/dist/{needle-engine.bundle-Dx2hV9Bu.umd.cjs → needle-engine.bundle-B3qVc_uH.umd.cjs} +54 -54
  7. package/dist/{needle-engine.bundle-DvRTYg0j.js → needle-engine.bundle-B9tUMvDR.js} +623 -623
  8. package/dist/{needle-engine.bundle-BxW8rOic.light.min.js → needle-engine.bundle-BWeBylyu.light.min.js} +62 -62
  9. package/dist/{needle-engine.bundle-5YrltOTW.light.umd.cjs → needle-engine.bundle-Bx32FU5Z.light.umd.cjs} +54 -54
  10. package/dist/{needle-engine.bundle-Bjtl-M4D.light.js → needle-engine.bundle-CAuuubKQ.light.js} +623 -623
  11. package/dist/needle-engine.d.ts +129 -130
  12. package/dist/needle-engine.js +2 -2
  13. package/dist/needle-engine.light.d.ts +129 -130
  14. package/dist/needle-engine.light.js +2 -2
  15. package/dist/needle-engine.light.min.js +1 -1
  16. package/dist/needle-engine.light.umd.cjs +1 -1
  17. package/dist/needle-engine.min.js +1 -1
  18. package/dist/needle-engine.umd.cjs +1 -1
  19. package/lib/asap/needle-asap.d.ts +1 -1
  20. package/lib/asap/needle-asap.js +95 -95
  21. package/lib/asap/sessiongranted.d.ts +3 -3
  22. package/lib/asap/sessiongranted.js +65 -65
  23. package/lib/asap/utils.d.ts +1 -1
  24. package/lib/asap/utils.js +3 -3
  25. package/lib/engine/analytics/index.d.ts +6 -6
  26. package/lib/engine/analytics/index.js +12 -12
  27. package/lib/engine/analytics/lcp.d.ts +3 -3
  28. package/lib/engine/analytics/lcp.js +34 -34
  29. package/lib/engine/api.d.ts +82 -82
  30. package/lib/engine/api.js +81 -81
  31. package/lib/engine/assets/index.d.ts +11 -11
  32. package/lib/engine/assets/index.js +47 -47
  33. package/lib/engine/assets/static.d.ts +1 -1
  34. package/lib/engine/assets/static.js +4 -4
  35. package/lib/engine/codegen/register_types.d.ts +1 -1
  36. package/lib/engine/codegen/register_types.js +300 -300
  37. package/lib/engine/debug/debug.d.ts +15 -15
  38. package/lib/engine/debug/debug.js +44 -44
  39. package/lib/engine/debug/debug_console.d.ts +2 -2
  40. package/lib/engine/debug/debug_console.js +307 -307
  41. package/lib/engine/debug/debug_overlay.d.ts +22 -22
  42. package/lib/engine/debug/debug_overlay.js +316 -316
  43. package/lib/engine/debug/debug_spatial_console.d.ts +2 -2
  44. package/lib/engine/debug/debug_spatial_console.js +390 -390
  45. package/lib/engine/debug/index.d.ts +2 -2
  46. package/lib/engine/debug/index.js +2 -2
  47. package/lib/engine/engine_addressables.d.ts +166 -166
  48. package/lib/engine/engine_addressables.js +608 -608
  49. package/lib/engine/engine_animation.d.ts +43 -43
  50. package/lib/engine/engine_animation.js +133 -133
  51. package/lib/engine/engine_application.d.ts +45 -45
  52. package/lib/engine/engine_application.js +104 -104
  53. package/lib/engine/engine_assetdatabase.d.ts +25 -25
  54. package/lib/engine/engine_assetdatabase.js +344 -344
  55. package/lib/engine/engine_audio.d.ts +4 -4
  56. package/lib/engine/engine_audio.js +23 -23
  57. package/lib/engine/engine_camera.d.ts +13 -13
  58. package/lib/engine/engine_camera.js +30 -30
  59. package/lib/engine/engine_components.d.ts +110 -110
  60. package/lib/engine/engine_components.js +374 -374
  61. package/lib/engine/engine_components_internal.d.ts +9 -9
  62. package/lib/engine/engine_components_internal.js +36 -36
  63. package/lib/engine/engine_constants.d.ts +10 -10
  64. package/lib/engine/engine_constants.js +41 -41
  65. package/lib/engine/engine_context.d.ts +472 -472
  66. package/lib/engine/engine_context.js +1664 -1664
  67. package/lib/engine/engine_context_registry.d.ts +71 -71
  68. package/lib/engine/engine_context_registry.js +117 -117
  69. package/lib/engine/engine_coroutine.d.ts +35 -35
  70. package/lib/engine/engine_coroutine.js +52 -52
  71. package/lib/engine/engine_create_objects.d.ts +119 -119
  72. package/lib/engine/engine_create_objects.js +320 -320
  73. package/lib/engine/engine_default_parameters.d.ts +2 -2
  74. package/lib/engine/engine_default_parameters.js +3 -3
  75. package/lib/engine/engine_editor-sync.d.ts +21 -21
  76. package/lib/engine/engine_editor-sync.js +4 -4
  77. package/lib/engine/engine_fileloader.d.ts +2 -2
  78. package/lib/engine/engine_fileloader.js +8 -8
  79. package/lib/engine/engine_gameobject.d.ts +68 -68
  80. package/lib/engine/engine_gameobject.js +616 -616
  81. package/lib/engine/engine_generic_utils.d.ts +1 -1
  82. package/lib/engine/engine_generic_utils.js +13 -13
  83. package/lib/engine/engine_gizmos.d.ts +149 -149
  84. package/lib/engine/engine_gizmos.js +530 -530
  85. package/lib/engine/engine_gltf.d.ts +12 -12
  86. package/lib/engine/engine_gltf.js +15 -15
  87. package/lib/engine/engine_gltf_builtin_components.d.ts +11 -11
  88. package/lib/engine/engine_gltf_builtin_components.js +341 -341
  89. package/lib/engine/engine_hot_reload.d.ts +8 -8
  90. package/lib/engine/engine_hot_reload.js +197 -197
  91. package/lib/engine/engine_input.d.ts +362 -362
  92. package/lib/engine/engine_input.js +1294 -1294
  93. package/lib/engine/engine_input_utils.d.ts +2 -2
  94. package/lib/engine/engine_input_utils.js +22 -22
  95. package/lib/engine/engine_instancing.d.ts +19 -19
  96. package/lib/engine/engine_instancing.js +39 -39
  97. package/lib/engine/engine_license.d.ts +11 -11
  98. package/lib/engine/engine_license.js +369 -369
  99. package/lib/engine/engine_lifecycle_api.d.ts +83 -83
  100. package/lib/engine/engine_lifecycle_api.js +106 -106
  101. package/lib/engine/engine_lifecycle_functions_internal.d.ts +32 -32
  102. package/lib/engine/engine_lifecycle_functions_internal.js +146 -146
  103. package/lib/engine/engine_lightdata.d.ts +23 -23
  104. package/lib/engine/engine_lightdata.js +91 -91
  105. package/lib/engine/engine_loaders.callbacks.d.ts +97 -97
  106. package/lib/engine/engine_loaders.callbacks.js +86 -86
  107. package/lib/engine/engine_loaders.d.ts +48 -48
  108. package/lib/engine/engine_loaders.gltf.d.ts +13 -13
  109. package/lib/engine/engine_loaders.gltf.js +62 -62
  110. package/lib/engine/engine_loaders.js +337 -337
  111. package/lib/engine/engine_lods.d.ts +31 -31
  112. package/lib/engine/engine_lods.js +146 -146
  113. package/lib/engine/engine_mainloop_utils.d.ts +32 -32
  114. package/lib/engine/engine_mainloop_utils.js +466 -466
  115. package/lib/engine/engine_math.d.ts +114 -114
  116. package/lib/engine/engine_math.js +247 -247
  117. package/lib/engine/engine_modules.d.ts +36 -36
  118. package/lib/engine/engine_modules.js +85 -85
  119. package/lib/engine/engine_networking.d.ts +260 -260
  120. package/lib/engine/engine_networking.js +764 -764
  121. package/lib/engine/engine_networking_auto.d.ts +24 -24
  122. package/lib/engine/engine_networking_auto.js +310 -310
  123. package/lib/engine/engine_networking_blob.d.ts +48 -48
  124. package/lib/engine/engine_networking_blob.js +228 -228
  125. package/lib/engine/engine_networking_files.d.ts +35 -35
  126. package/lib/engine/engine_networking_files.js +172 -172
  127. package/lib/engine/engine_networking_files_default_components.d.ts +6 -6
  128. package/lib/engine/engine_networking_files_default_components.js +42 -42
  129. package/lib/engine/engine_networking_instantiate.d.ts +100 -100
  130. package/lib/engine/engine_networking_instantiate.js +345 -345
  131. package/lib/engine/engine_networking_peer.d.ts +15 -15
  132. package/lib/engine/engine_networking_peer.js +132 -132
  133. package/lib/engine/engine_networking_streams.d.ts +123 -123
  134. package/lib/engine/engine_networking_streams.js +645 -645
  135. package/lib/engine/engine_networking_types.d.ts +22 -22
  136. package/lib/engine/engine_networking_types.js +7 -7
  137. package/lib/engine/engine_networking_utils.d.ts +2 -2
  138. package/lib/engine/engine_networking_utils.js +20 -20
  139. package/lib/engine/engine_networking_websocket.d.ts +1 -1
  140. package/lib/engine/engine_networking_websocket.js +2 -2
  141. package/lib/engine/engine_patcher.d.ts +10 -10
  142. package/lib/engine/engine_patcher.js +142 -142
  143. package/lib/engine/engine_physics.d.ts +152 -152
  144. package/lib/engine/engine_physics.js +645 -645
  145. package/lib/engine/engine_physics.types.d.ts +40 -40
  146. package/lib/engine/engine_physics.types.js +33 -33
  147. package/lib/engine/engine_physics_rapier.d.ts +147 -147
  148. package/lib/engine/engine_physics_rapier.js +1433 -1433
  149. package/lib/engine/engine_playerview.d.ts +26 -26
  150. package/lib/engine/engine_playerview.js +64 -64
  151. package/lib/engine/engine_scenelighting.d.ts +71 -71
  152. package/lib/engine/engine_scenelighting.js +226 -226
  153. package/lib/engine/engine_serialization.d.ts +3 -3
  154. package/lib/engine/engine_serialization.js +3 -3
  155. package/lib/engine/engine_serialization_builtin_serializer.d.ts +72 -72
  156. package/lib/engine/engine_serialization_builtin_serializer.js +403 -403
  157. package/lib/engine/engine_serialization_core.d.ts +94 -94
  158. package/lib/engine/engine_serialization_core.js +607 -607
  159. package/lib/engine/engine_serialization_decorator.d.ts +23 -23
  160. package/lib/engine/engine_serialization_decorator.js +66 -66
  161. package/lib/engine/engine_setup.d.ts +1 -1
  162. package/lib/engine/engine_setup.js +2 -2
  163. package/lib/engine/engine_shaders.d.ts +53 -53
  164. package/lib/engine/engine_shaders.js +252 -252
  165. package/lib/engine/engine_shims.d.ts +4 -4
  166. package/lib/engine/engine_shims.js +24 -24
  167. package/lib/engine/engine_test_utils.d.ts +39 -39
  168. package/lib/engine/engine_test_utils.js +83 -83
  169. package/lib/engine/engine_texture.d.ts +28 -28
  170. package/lib/engine/engine_texture.js +64 -64
  171. package/lib/engine/engine_three_utils.d.ts +201 -201
  172. package/lib/engine/engine_three_utils.js +731 -731
  173. package/lib/engine/engine_time.d.ts +51 -51
  174. package/lib/engine/engine_time.js +82 -82
  175. package/lib/engine/engine_time_utils.d.ts +88 -88
  176. package/lib/engine/engine_time_utils.js +215 -215
  177. package/lib/engine/engine_tonemapping.d.ts +2 -2
  178. package/lib/engine/engine_tonemapping.js +194 -194
  179. package/lib/engine/engine_types.d.ts +578 -578
  180. package/lib/engine/engine_types.js +95 -95
  181. package/lib/engine/engine_typestore.d.ts +28 -28
  182. package/lib/engine/engine_typestore.js +55 -55
  183. package/lib/engine/engine_util_decorator.d.ts +13 -13
  184. package/lib/engine/engine_util_decorator.js +116 -116
  185. package/lib/engine/engine_utils.d.ts +248 -248
  186. package/lib/engine/engine_utils.js +993 -993
  187. package/lib/engine/engine_utils_format.d.ts +24 -24
  188. package/lib/engine/engine_utils_format.js +239 -239
  189. package/lib/engine/engine_utils_screenshot.d.ts +159 -159
  190. package/lib/engine/engine_utils_screenshot.js +513 -513
  191. package/lib/engine/engine_utils_screenshot.xr.d.ts +5 -5
  192. package/lib/engine/engine_utils_screenshot.xr.js +90 -90
  193. package/lib/engine/engine_xr.d.ts +1 -1
  194. package/lib/engine/engine_xr.js +1 -1
  195. package/lib/engine/export/gltf/Writers.d.ts +19 -19
  196. package/lib/engine/export/gltf/Writers.js +24 -24
  197. package/lib/engine/export/gltf/index.d.ts +11 -11
  198. package/lib/engine/export/gltf/index.js +123 -123
  199. package/lib/engine/export/index.d.ts +2 -2
  200. package/lib/engine/export/index.js +2 -2
  201. package/lib/engine/export/state.d.ts +7 -7
  202. package/lib/engine/export/state.js +17 -17
  203. package/lib/engine/export/utils.d.ts +2 -2
  204. package/lib/engine/export/utils.js +7 -7
  205. package/lib/engine/extensions/EXT_texture_exr.d.ts +8 -8
  206. package/lib/engine/extensions/EXT_texture_exr.js +32 -32
  207. package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +122 -122
  208. package/lib/engine/extensions/NEEDLE_animator_controller_model.js +95 -95
  209. package/lib/engine/extensions/NEEDLE_components.d.ts +35 -35
  210. package/lib/engine/extensions/NEEDLE_components.js +220 -220
  211. package/lib/engine/extensions/NEEDLE_gameobject_data.d.ts +10 -10
  212. package/lib/engine/extensions/NEEDLE_gameobject_data.js +57 -57
  213. package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +37 -37
  214. package/lib/engine/extensions/NEEDLE_lighting_settings.js +157 -157
  215. package/lib/engine/extensions/NEEDLE_lightmaps.d.ts +18 -18
  216. package/lib/engine/extensions/NEEDLE_lightmaps.js +99 -99
  217. package/lib/engine/extensions/NEEDLE_persistent_assets.d.ts +11 -11
  218. package/lib/engine/extensions/NEEDLE_persistent_assets.js +63 -63
  219. package/lib/engine/extensions/NEEDLE_progressive.d.ts +1 -1
  220. package/lib/engine/extensions/NEEDLE_progressive.js +1 -1
  221. package/lib/engine/extensions/NEEDLE_render_objects.d.ts +13 -13
  222. package/lib/engine/extensions/NEEDLE_render_objects.js +159 -159
  223. package/lib/engine/extensions/NEEDLE_techniques_webgl.d.ts +38 -38
  224. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +564 -564
  225. package/lib/engine/extensions/extension_resolver.d.ts +4 -4
  226. package/lib/engine/extensions/extension_resolver.js +1 -1
  227. package/lib/engine/extensions/extension_utils.d.ts +12 -12
  228. package/lib/engine/extensions/extension_utils.js +152 -152
  229. package/lib/engine/extensions/extensions.d.ts +32 -32
  230. package/lib/engine/extensions/extensions.js +107 -107
  231. package/lib/engine/extensions/index.d.ts +6 -6
  232. package/lib/engine/extensions/index.js +6 -6
  233. package/lib/engine/extensions/usage_tracker.d.ts +13 -13
  234. package/lib/engine/extensions/usage_tracker.js +65 -65
  235. package/lib/engine/js-extensions/Camera.d.ts +1 -1
  236. package/lib/engine/js-extensions/Camera.js +39 -39
  237. package/lib/engine/js-extensions/ExtensionUtils.d.ts +9 -9
  238. package/lib/engine/js-extensions/ExtensionUtils.js +67 -67
  239. package/lib/engine/js-extensions/Layers.d.ts +6 -6
  240. package/lib/engine/js-extensions/Layers.js +22 -22
  241. package/lib/engine/js-extensions/Object3D.d.ts +120 -120
  242. package/lib/engine/js-extensions/Object3D.js +136 -136
  243. package/lib/engine/js-extensions/RGBAColor.d.ts +23 -23
  244. package/lib/engine/js-extensions/RGBAColor.js +111 -111
  245. package/lib/engine/js-extensions/Vector.d.ts +3 -3
  246. package/lib/engine/js-extensions/Vector.js +13 -13
  247. package/lib/engine/js-extensions/index.d.ts +5 -5
  248. package/lib/engine/js-extensions/index.js +5 -5
  249. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.d.ts +4 -4
  250. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +79 -79
  251. package/lib/engine/shaders/shaderData.d.ts +55 -55
  252. package/lib/engine/shaders/shaderData.js +58 -58
  253. package/lib/engine/tests/test_utils.d.ts +2 -2
  254. package/lib/engine/tests/test_utils.js +53 -53
  255. package/lib/engine/webcomponents/WebXRButtons.d.ts +56 -56
  256. package/lib/engine/webcomponents/WebXRButtons.js +230 -230
  257. package/lib/engine/webcomponents/api.d.ts +5 -5
  258. package/lib/engine/webcomponents/api.js +4 -4
  259. package/lib/engine/webcomponents/buttons.d.ts +51 -51
  260. package/lib/engine/webcomponents/buttons.js +264 -264
  261. package/lib/engine/webcomponents/fonts.d.ts +9 -9
  262. package/lib/engine/webcomponents/fonts.js +32 -32
  263. package/lib/engine/webcomponents/icons.d.ts +9 -9
  264. package/lib/engine/webcomponents/icons.js +52 -52
  265. package/lib/engine/webcomponents/index.d.ts +1 -1
  266. package/lib/engine/webcomponents/index.js +1 -1
  267. package/lib/engine/webcomponents/logo-element.d.ts +10 -10
  268. package/lib/engine/webcomponents/logo-element.js +67 -67
  269. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.d.ts +37 -37
  270. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +513 -513
  271. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +155 -155
  272. package/lib/engine/webcomponents/needle menu/needle-menu.js +1029 -1029
  273. package/lib/engine/webcomponents/needle-button.d.ts +34 -34
  274. package/lib/engine/webcomponents/needle-button.js +161 -161
  275. package/lib/engine/webcomponents/needle-engine.ar-overlay.d.ts +21 -21
  276. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +166 -166
  277. package/lib/engine/webcomponents/needle-engine.attributes.d.ts +69 -69
  278. package/lib/engine/webcomponents/needle-engine.attributes.js +1 -1
  279. package/lib/engine/webcomponents/needle-engine.d.ts +113 -113
  280. package/lib/engine/webcomponents/needle-engine.extras.d.ts +6 -6
  281. package/lib/engine/webcomponents/needle-engine.extras.js +13 -13
  282. package/lib/engine/webcomponents/needle-engine.js +831 -831
  283. package/lib/engine/webcomponents/needle-engine.loading.d.ts +44 -44
  284. package/lib/engine/webcomponents/needle-engine.loading.js +341 -341
  285. package/lib/engine/xr/NeedleXRController.d.ts +313 -313
  286. package/lib/engine/xr/NeedleXRController.js +1007 -1007
  287. package/lib/engine/xr/NeedleXRSession.d.ts +340 -340
  288. package/lib/engine/xr/NeedleXRSession.js +1463 -1463
  289. package/lib/engine/xr/NeedleXRSync.d.ts +22 -22
  290. package/lib/engine/xr/NeedleXRSync.js +188 -188
  291. package/lib/engine/xr/SceneTransition.d.ts +18 -18
  292. package/lib/engine/xr/SceneTransition.js +69 -69
  293. package/lib/engine/xr/TempXRContext.d.ts +34 -34
  294. package/lib/engine/xr/TempXRContext.js +187 -187
  295. package/lib/engine/xr/XRRig.d.ts +7 -7
  296. package/lib/engine/xr/XRRig.js +1 -1
  297. package/lib/engine/xr/api.d.ts +6 -6
  298. package/lib/engine/xr/api.js +6 -6
  299. package/lib/engine/xr/events.d.ts +66 -66
  300. package/lib/engine/xr/events.js +93 -93
  301. package/lib/engine/xr/internal.d.ts +12 -12
  302. package/lib/engine/xr/internal.js +25 -25
  303. package/lib/engine/xr/usdz.d.ts +12 -12
  304. package/lib/engine/xr/usdz.js +29 -29
  305. package/lib/engine/xr/utils.d.ts +11 -11
  306. package/lib/engine/xr/utils.js +34 -34
  307. package/lib/engine-components/AlignmentConstraint.d.ts +10 -10
  308. package/lib/engine-components/AlignmentConstraint.js +39 -39
  309. package/lib/engine-components/Animation.d.ts +156 -156
  310. package/lib/engine-components/Animation.js +508 -508
  311. package/lib/engine-components/AnimationCurve.d.ts +40 -40
  312. package/lib/engine-components/AnimationCurve.js +159 -159
  313. package/lib/engine-components/AnimationUtils.d.ts +8 -8
  314. package/lib/engine-components/AnimationUtils.js +27 -27
  315. package/lib/engine-components/AnimationUtilsAutoplay.d.ts +1 -1
  316. package/lib/engine-components/AnimationUtilsAutoplay.js +39 -39
  317. package/lib/engine-components/Animator.d.ts +217 -217
  318. package/lib/engine-components/Animator.js +354 -354
  319. package/lib/engine-components/AnimatorController.d.ts +227 -227
  320. package/lib/engine-components/AnimatorController.js +1152 -1152
  321. package/lib/engine-components/AudioListener.d.ts +33 -33
  322. package/lib/engine-components/AudioListener.js +86 -86
  323. package/lib/engine-components/AudioSource.d.ts +217 -217
  324. package/lib/engine-components/AudioSource.js +634 -634
  325. package/lib/engine-components/AvatarLoader.d.ts +80 -80
  326. package/lib/engine-components/AvatarLoader.js +231 -231
  327. package/lib/engine-components/AxesHelper.d.ts +32 -32
  328. package/lib/engine-components/AxesHelper.js +67 -67
  329. package/lib/engine-components/BasicIKConstraint.d.ts +9 -9
  330. package/lib/engine-components/BasicIKConstraint.js +43 -43
  331. package/lib/engine-components/BoxCollider.d.ts +2 -2
  332. package/lib/engine-components/BoxCollider.js +2 -2
  333. package/lib/engine-components/BoxHelperComponent.d.ts +47 -47
  334. package/lib/engine-components/BoxHelperComponent.js +102 -102
  335. package/lib/engine-components/Camera.d.ts +231 -231
  336. package/lib/engine-components/Camera.js +700 -700
  337. package/lib/engine-components/CameraUtils.d.ts +1 -1
  338. package/lib/engine-components/CameraUtils.js +121 -121
  339. package/lib/engine-components/CharacterController.d.ts +55 -55
  340. package/lib/engine-components/CharacterController.js +236 -236
  341. package/lib/engine-components/Collider.d.ts +188 -188
  342. package/lib/engine-components/Collider.js +369 -369
  343. package/lib/engine-components/Component.d.ts +792 -792
  344. package/lib/engine-components/Component.js +920 -920
  345. package/lib/engine-components/ContactShadows.d.ts +94 -94
  346. package/lib/engine-components/ContactShadows.js +453 -453
  347. package/lib/engine-components/DeleteBox.d.ts +19 -19
  348. package/lib/engine-components/DeleteBox.js +58 -58
  349. package/lib/engine-components/DeviceFlag.d.ts +16 -16
  350. package/lib/engine-components/DeviceFlag.js +47 -47
  351. package/lib/engine-components/DragControls.d.ts +170 -170
  352. package/lib/engine-components/DragControls.js +1421 -1421
  353. package/lib/engine-components/DropListener.d.ts +215 -215
  354. package/lib/engine-components/DropListener.js +642 -642
  355. package/lib/engine-components/Duplicatable.d.ts +35 -35
  356. package/lib/engine-components/Duplicatable.js +202 -202
  357. package/lib/engine-components/EventList.d.ts +54 -54
  358. package/lib/engine-components/EventList.js +232 -232
  359. package/lib/engine-components/EventTrigger.d.ts +33 -33
  360. package/lib/engine-components/EventTrigger.js +75 -75
  361. package/lib/engine-components/EventType.d.ts +22 -22
  362. package/lib/engine-components/EventType.js +23 -23
  363. package/lib/engine-components/Fog.d.ts +22 -22
  364. package/lib/engine-components/Fog.js +61 -61
  365. package/lib/engine-components/Gizmos.d.ts +17 -17
  366. package/lib/engine-components/Gizmos.js +64 -64
  367. package/lib/engine-components/GridHelper.d.ts +20 -20
  368. package/lib/engine-components/GridHelper.js +54 -54
  369. package/lib/engine-components/GroundProjection.d.ts +67 -67
  370. package/lib/engine-components/GroundProjection.js +343 -343
  371. package/lib/engine-components/Interactable.d.ts +12 -12
  372. package/lib/engine-components/Interactable.js +12 -12
  373. package/lib/engine-components/Joints.d.ts +19 -19
  374. package/lib/engine-components/Joints.js +51 -51
  375. package/lib/engine-components/LODGroup.d.ts +35 -35
  376. package/lib/engine-components/LODGroup.js +152 -152
  377. package/lib/engine-components/Light.d.ts +180 -180
  378. package/lib/engine-components/Light.js +535 -535
  379. package/lib/engine-components/LookAtConstraint.d.ts +19 -19
  380. package/lib/engine-components/LookAtConstraint.js +35 -35
  381. package/lib/engine-components/NeedleMenu.d.ts +50 -50
  382. package/lib/engine-components/NeedleMenu.js +92 -92
  383. package/lib/engine-components/NestedGltf.d.ts +25 -25
  384. package/lib/engine-components/NestedGltf.js +88 -88
  385. package/lib/engine-components/Networking.d.ts +54 -54
  386. package/lib/engine-components/Networking.js +112 -112
  387. package/lib/engine-components/OffsetConstraint.d.ts +14 -14
  388. package/lib/engine-components/OffsetConstraint.js +65 -65
  389. package/lib/engine-components/OrbitControls.d.ts +268 -268
  390. package/lib/engine-components/OrbitControls.js +1015 -1015
  391. package/lib/engine-components/PlayerColor.d.ts +19 -19
  392. package/lib/engine-components/PlayerColor.js +94 -94
  393. package/lib/engine-components/ReflectionProbe.d.ts +27 -27
  394. package/lib/engine-components/ReflectionProbe.js +201 -201
  395. package/lib/engine-components/Renderer.d.ts +153 -153
  396. package/lib/engine-components/Renderer.js +830 -830
  397. package/lib/engine-components/RendererInstancing.d.ts +140 -140
  398. package/lib/engine-components/RendererInstancing.js +744 -744
  399. package/lib/engine-components/RendererLightmap.d.ts +24 -24
  400. package/lib/engine-components/RendererLightmap.js +182 -182
  401. package/lib/engine-components/RigidBody.d.ts +155 -155
  402. package/lib/engine-components/RigidBody.js +517 -517
  403. package/lib/engine-components/SceneSwitcher.d.ts +263 -263
  404. package/lib/engine-components/SceneSwitcher.js +971 -971
  405. package/lib/engine-components/ScreenCapture.d.ts +144 -144
  406. package/lib/engine-components/ScreenCapture.js +547 -547
  407. package/lib/engine-components/ShadowCatcher.d.ts +33 -33
  408. package/lib/engine-components/ShadowCatcher.js +166 -166
  409. package/lib/engine-components/Skybox.d.ts +82 -82
  410. package/lib/engine-components/Skybox.js +448 -448
  411. package/lib/engine-components/SmoothFollow.d.ts +34 -34
  412. package/lib/engine-components/SmoothFollow.js +82 -82
  413. package/lib/engine-components/SpatialTrigger.d.ts +102 -102
  414. package/lib/engine-components/SpatialTrigger.js +225 -225
  415. package/lib/engine-components/SpectatorCamera.d.ts +111 -111
  416. package/lib/engine-components/SpectatorCamera.js +715 -715
  417. package/lib/engine-components/SphereCollider.d.ts +2 -2
  418. package/lib/engine-components/SphereCollider.js +2 -2
  419. package/lib/engine-components/SpriteRenderer.d.ts +132 -132
  420. package/lib/engine-components/SpriteRenderer.js +472 -472
  421. package/lib/engine-components/SyncedCamera.d.ts +41 -41
  422. package/lib/engine-components/SyncedCamera.js +199 -199
  423. package/lib/engine-components/SyncedRoom.d.ts +106 -106
  424. package/lib/engine-components/SyncedRoom.js +371 -371
  425. package/lib/engine-components/SyncedTransform.d.ts +94 -94
  426. package/lib/engine-components/SyncedTransform.js +331 -331
  427. package/lib/engine-components/TestRunner.d.ts +16 -16
  428. package/lib/engine-components/TestRunner.js +102 -102
  429. package/lib/engine-components/TransformGizmo.d.ts +75 -75
  430. package/lib/engine-components/TransformGizmo.js +209 -209
  431. package/lib/engine-components/VideoPlayer.d.ts +184 -184
  432. package/lib/engine-components/VideoPlayer.js +978 -978
  433. package/lib/engine-components/Voip.d.ts +67 -67
  434. package/lib/engine-components/Voip.js +360 -360
  435. package/lib/engine-components/api.d.ts +51 -51
  436. package/lib/engine-components/api.js +50 -50
  437. package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +11 -11
  438. package/lib/engine-components/avatar/AvatarBlink_Simple.js +76 -76
  439. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +14 -14
  440. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +68 -68
  441. package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +29 -29
  442. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +121 -121
  443. package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +15 -15
  444. package/lib/engine-components/avatar/Avatar_MouthShapes.js +79 -79
  445. package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +9 -9
  446. package/lib/engine-components/avatar/Avatar_MustacheShake.js +29 -29
  447. package/lib/engine-components/codegen/components.d.ts +216 -216
  448. package/lib/engine-components/codegen/components.js +218 -218
  449. package/lib/engine-components/debug/LogStats.d.ts +5 -5
  450. package/lib/engine-components/debug/LogStats.js +18 -18
  451. package/lib/engine-components/export/gltf/GltfExport.d.ts +30 -30
  452. package/lib/engine-components/export/gltf/GltfExport.js +246 -246
  453. package/lib/engine-components/export/gltf/index.d.ts +1 -1
  454. package/lib/engine-components/export/gltf/index.js +1 -1
  455. package/lib/engine-components/export/index.d.ts +1 -1
  456. package/lib/engine-components/export/index.js +1 -1
  457. package/lib/engine-components/export/usdz/Extension.d.ts +22 -22
  458. package/lib/engine-components/export/usdz/Extension.js +1 -1
  459. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +160 -160
  460. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +1782 -1782
  461. package/lib/engine-components/export/usdz/USDZExporter.d.ts +130 -130
  462. package/lib/engine-components/export/usdz/USDZExporter.js +663 -663
  463. package/lib/engine-components/export/usdz/extensions/Animation.d.ts +106 -106
  464. package/lib/engine-components/export/usdz/extensions/Animation.js +1071 -1071
  465. package/lib/engine-components/export/usdz/extensions/DocumentExtension.d.ts +5 -5
  466. package/lib/engine-components/export/usdz/extensions/DocumentExtension.js +6 -6
  467. package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +54 -54
  468. package/lib/engine-components/export/usdz/extensions/USDZText.js +203 -203
  469. package/lib/engine-components/export/usdz/extensions/USDZUI.d.ts +8 -8
  470. package/lib/engine-components/export/usdz/extensions/USDZUI.js +158 -158
  471. package/lib/engine-components/export/usdz/extensions/behavior/Actions.d.ts +30 -30
  472. package/lib/engine-components/export/usdz/extensions/behavior/Actions.js +88 -88
  473. package/lib/engine-components/export/usdz/extensions/behavior/AudioExtension.d.ts +10 -10
  474. package/lib/engine-components/export/usdz/extensions/behavior/AudioExtension.js +86 -86
  475. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +28 -28
  476. package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +290 -290
  477. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +190 -190
  478. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +1060 -1060
  479. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +135 -135
  480. package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +548 -548
  481. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.d.ts +7 -7
  482. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js +115 -115
  483. package/lib/engine-components/export/usdz/index.d.ts +3 -3
  484. package/lib/engine-components/export/usdz/index.js +2 -2
  485. package/lib/engine-components/export/usdz/utils/animationutils.d.ts +7 -7
  486. package/lib/engine-components/export/usdz/utils/animationutils.js +163 -163
  487. package/lib/engine-components/export/usdz/utils/quicklook.d.ts +2 -2
  488. package/lib/engine-components/export/usdz/utils/quicklook.js +43 -43
  489. package/lib/engine-components/particlesystem/ParticleSystem.d.ts +177 -177
  490. package/lib/engine-components/particlesystem/ParticleSystem.js +1176 -1176
  491. package/lib/engine-components/particlesystem/ParticleSystemModules.d.ts +526 -526
  492. package/lib/engine-components/particlesystem/ParticleSystemModules.js +1930 -1930
  493. package/lib/engine-components/particlesystem/ParticleSystemSubEmitter.d.ts +25 -25
  494. package/lib/engine-components/particlesystem/ParticleSystemSubEmitter.js +87 -87
  495. package/lib/engine-components/particlesystem/api.d.ts +2 -2
  496. package/lib/engine-components/particlesystem/api.js +2 -2
  497. package/lib/engine-components/postprocessing/Effects/Antialiasing.d.ts +17 -17
  498. package/lib/engine-components/postprocessing/Effects/Antialiasing.js +50 -50
  499. package/lib/engine-components/postprocessing/Effects/BloomEffect.d.ts +46 -46
  500. package/lib/engine-components/postprocessing/Effects/BloomEffect.js +113 -113
  501. package/lib/engine-components/postprocessing/Effects/ChromaticAberration.d.ts +11 -11
  502. package/lib/engine-components/postprocessing/Effects/ChromaticAberration.js +39 -39
  503. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.d.ts +15 -15
  504. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js +92 -92
  505. package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +25 -25
  506. package/lib/engine-components/postprocessing/Effects/DepthOfField.js +104 -104
  507. package/lib/engine-components/postprocessing/Effects/EffectWrapper.d.ts +12 -12
  508. package/lib/engine-components/postprocessing/Effects/EffectWrapper.js +18 -18
  509. package/lib/engine-components/postprocessing/Effects/Pixelation.d.ts +11 -11
  510. package/lib/engine-components/postprocessing/Effects/Pixelation.js +32 -32
  511. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.d.ts +18 -18
  512. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +91 -91
  513. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.d.ts +70 -70
  514. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js +175 -175
  515. package/lib/engine-components/postprocessing/Effects/Sharpening.d.ts +17 -17
  516. package/lib/engine-components/postprocessing/Effects/Sharpening.js +123 -123
  517. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +17 -17
  518. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +70 -70
  519. package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +26 -26
  520. package/lib/engine-components/postprocessing/Effects/Tonemapping.js +138 -138
  521. package/lib/engine-components/postprocessing/Effects/Vignette.d.ts +15 -15
  522. package/lib/engine-components/postprocessing/Effects/Vignette.js +60 -60
  523. package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +72 -72
  524. package/lib/engine-components/postprocessing/PostProcessingEffect.js +149 -149
  525. package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +25 -25
  526. package/lib/engine-components/postprocessing/PostProcessingHandler.js +350 -350
  527. package/lib/engine-components/postprocessing/Volume.d.ts +89 -89
  528. package/lib/engine-components/postprocessing/Volume.js +367 -367
  529. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +26 -26
  530. package/lib/engine-components/postprocessing/VolumeParameter.js +136 -136
  531. package/lib/engine-components/postprocessing/VolumeProfile.d.ts +15 -15
  532. package/lib/engine-components/postprocessing/VolumeProfile.js +60 -60
  533. package/lib/engine-components/postprocessing/index.d.ts +5 -5
  534. package/lib/engine-components/postprocessing/index.js +5 -5
  535. package/lib/engine-components/postprocessing/utils.d.ts +11 -11
  536. package/lib/engine-components/postprocessing/utils.js +37 -37
  537. package/lib/engine-components/timeline/PlayableDirector.d.ts +163 -163
  538. package/lib/engine-components/timeline/PlayableDirector.js +686 -686
  539. package/lib/engine-components/timeline/SignalAsset.d.ts +24 -24
  540. package/lib/engine-components/timeline/SignalAsset.js +130 -130
  541. package/lib/engine-components/timeline/TimelineModels.d.ts +89 -89
  542. package/lib/engine-components/timeline/TimelineModels.js +22 -22
  543. package/lib/engine-components/timeline/TimelineTracks.d.ts +110 -110
  544. package/lib/engine-components/timeline/TimelineTracks.js +879 -879
  545. package/lib/engine-components/timeline/index.d.ts +4 -4
  546. package/lib/engine-components/timeline/index.js +3 -3
  547. package/lib/engine-components/ui/BaseUIComponent.d.ts +48 -48
  548. package/lib/engine-components/ui/BaseUIComponent.js +170 -170
  549. package/lib/engine-components/ui/Button.d.ts +64 -64
  550. package/lib/engine-components/ui/Button.js +315 -315
  551. package/lib/engine-components/ui/Canvas.d.ts +74 -74
  552. package/lib/engine-components/ui/Canvas.js +407 -407
  553. package/lib/engine-components/ui/CanvasGroup.d.ts +19 -19
  554. package/lib/engine-components/ui/CanvasGroup.js +58 -58
  555. package/lib/engine-components/ui/EventSystem.d.ts +125 -125
  556. package/lib/engine-components/ui/EventSystem.js +765 -765
  557. package/lib/engine-components/ui/Graphic.d.ts +55 -55
  558. package/lib/engine-components/ui/Graphic.js +255 -255
  559. package/lib/engine-components/ui/Image.d.ts +35 -35
  560. package/lib/engine-components/ui/Image.js +116 -116
  561. package/lib/engine-components/ui/InputField.d.ts +42 -42
  562. package/lib/engine-components/ui/InputField.js +268 -268
  563. package/lib/engine-components/ui/Interfaces.d.ts +38 -38
  564. package/lib/engine-components/ui/Interfaces.js +12 -12
  565. package/lib/engine-components/ui/Layout.d.ts +84 -84
  566. package/lib/engine-components/ui/Layout.js +330 -330
  567. package/lib/engine-components/ui/Outline.d.ts +7 -7
  568. package/lib/engine-components/ui/Outline.js +20 -20
  569. package/lib/engine-components/ui/PointerEvents.d.ts +115 -115
  570. package/lib/engine-components/ui/PointerEvents.js +145 -145
  571. package/lib/engine-components/ui/RaycastUtils.d.ts +11 -11
  572. package/lib/engine-components/ui/RaycastUtils.js +67 -67
  573. package/lib/engine-components/ui/Raycaster.d.ts +30 -30
  574. package/lib/engine-components/ui/Raycaster.js +95 -95
  575. package/lib/engine-components/ui/RectTransform.d.ts +61 -61
  576. package/lib/engine-components/ui/RectTransform.js +356 -356
  577. package/lib/engine-components/ui/SpatialHtml.d.ts +8 -8
  578. package/lib/engine-components/ui/SpatialHtml.js +79 -79
  579. package/lib/engine-components/ui/Symbols.d.ts +1 -1
  580. package/lib/engine-components/ui/Symbols.js +1 -1
  581. package/lib/engine-components/ui/Text.d.ts +78 -78
  582. package/lib/engine-components/ui/Text.js +539 -539
  583. package/lib/engine-components/ui/Utils.d.ts +24 -24
  584. package/lib/engine-components/ui/Utils.js +90 -90
  585. package/lib/engine-components/ui/index.d.ts +1 -1
  586. package/lib/engine-components/ui/index.js +1 -1
  587. package/lib/engine-components/utils/EnvironmentScene.d.ts +5 -5
  588. package/lib/engine-components/utils/EnvironmentScene.js +205 -205
  589. package/lib/engine-components/utils/LookAt.d.ts +31 -31
  590. package/lib/engine-components/utils/LookAt.js +82 -82
  591. package/lib/engine-components/utils/OpenURL.d.ts +42 -42
  592. package/lib/engine-components/utils/OpenURL.js +119 -119
  593. package/lib/engine-components/webxr/Avatar.d.ts +25 -25
  594. package/lib/engine-components/webxr/Avatar.js +255 -255
  595. package/lib/engine-components/webxr/TeleportTarget.d.ts +7 -7
  596. package/lib/engine-components/webxr/TeleportTarget.js +7 -7
  597. package/lib/engine-components/webxr/WebARCameraBackground.d.ts +30 -30
  598. package/lib/engine-components/webxr/WebARCameraBackground.js +155 -155
  599. package/lib/engine-components/webxr/WebARSessionRoot.d.ts +98 -98
  600. package/lib/engine-components/webxr/WebARSessionRoot.js +770 -770
  601. package/lib/engine-components/webxr/WebXR.d.ts +232 -232
  602. package/lib/engine-components/webxr/WebXR.js +561 -561
  603. package/lib/engine-components/webxr/WebXRAvatar.d.ts +27 -27
  604. package/lib/engine-components/webxr/WebXRAvatar.js +44 -44
  605. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +86 -86
  606. package/lib/engine-components/webxr/WebXRImageTracking.js +471 -471
  607. package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +92 -92
  608. package/lib/engine-components/webxr/WebXRPlaneTracking.js +500 -500
  609. package/lib/engine-components/webxr/WebXRRig.d.ts +32 -32
  610. package/lib/engine-components/webxr/WebXRRig.js +72 -72
  611. package/lib/engine-components/webxr/XRFlag.d.ts +38 -38
  612. package/lib/engine-components/webxr/XRFlag.js +139 -139
  613. package/lib/engine-components/webxr/controllers/XRControllerFollow.d.ts +47 -47
  614. package/lib/engine-components/webxr/controllers/XRControllerFollow.js +120 -120
  615. package/lib/engine-components/webxr/controllers/XRControllerModel.d.ts +43 -43
  616. package/lib/engine-components/webxr/controllers/XRControllerModel.js +352 -352
  617. package/lib/engine-components/webxr/controllers/XRControllerMovement.d.ts +78 -78
  618. package/lib/engine-components/webxr/controllers/XRControllerMovement.js +506 -506
  619. package/lib/engine-components/webxr/index.d.ts +3 -3
  620. package/lib/engine-components/webxr/index.js +3 -3
  621. package/lib/engine-components/webxr/types.d.ts +3 -3
  622. package/lib/engine-components/webxr/types.js +1 -1
  623. package/lib/engine-components-experimental/Presentation.d.ts +6 -6
  624. package/lib/engine-components-experimental/Presentation.js +9 -9
  625. package/lib/engine-components-experimental/api.d.ts +4 -4
  626. package/lib/engine-components-experimental/api.js +4 -4
  627. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +156 -156
  628. package/lib/engine-components-experimental/networking/PlayerSync.js +377 -377
  629. package/lib/engine-schemes/api.d.ts +12 -12
  630. package/lib/engine-schemes/api.js +12 -12
  631. package/lib/engine-schemes/schemes.d.ts +7 -7
  632. package/lib/engine-schemes/schemes.js +19 -19
  633. package/lib/engine-schemes/synced-camera-model.d.ts +25 -25
  634. package/lib/engine-schemes/synced-camera-model.js +67 -67
  635. package/lib/engine-schemes/synced-transform-model.d.ts +31 -31
  636. package/lib/engine-schemes/synced-transform-model.js +66 -66
  637. package/lib/engine-schemes/transform.d.ts +12 -12
  638. package/lib/engine-schemes/transform.js +39 -39
  639. package/lib/engine-schemes/vec2.d.ts +10 -10
  640. package/lib/engine-schemes/vec2.js +25 -25
  641. package/lib/engine-schemes/vec3.d.ts +11 -11
  642. package/lib/engine-schemes/vec3.js +29 -29
  643. package/lib/engine-schemes/vec4.d.ts +12 -12
  644. package/lib/engine-schemes/vec4.js +33 -33
  645. package/lib/engine-schemes/vr-user-state-buffer.d.ts +37 -37
  646. package/lib/engine-schemes/vr-user-state-buffer.js +110 -110
  647. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.d.ts +6 -6
  648. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js +45 -45
  649. package/lib/needle-engine.d.ts +7 -7
  650. package/lib/needle-engine.js +64 -64
  651. package/package.json +2 -2
  652. package/plugins/common/buildinfo.js +64 -64
  653. package/plugins/common/cloud.js +1 -1
  654. package/plugins/common/config.cjs +31 -31
  655. package/plugins/common/config.js +35 -35
  656. package/plugins/common/files.js +31 -31
  657. package/plugins/common/generator.js +10 -10
  658. package/plugins/common/license.js +452 -442
  659. package/plugins/common/npm.js +15 -15
  660. package/plugins/common/timers.js +7 -7
  661. package/plugins/common/version.js +37 -37
  662. package/plugins/gltf-packer.mjs +1 -1
  663. package/plugins/next/alias.cjs +39 -39
  664. package/plugins/next/license.cjs +24 -24
  665. package/plugins/next/meshbvhworker.cjs +18 -18
  666. package/plugins/next/next.js +141 -141
  667. package/plugins/types/index.d.ts +2 -2
  668. package/plugins/types/license.d.ts +24 -24
  669. package/plugins/types/needleConfig.d.ts +27 -27
  670. package/plugins/types/next.d.ts +2 -2
  671. package/plugins/types/userconfig.d.ts +120 -120
  672. package/plugins/types/vite.d.ts +13 -13
  673. package/plugins/types/webmanifest.d.ts +32 -32
  674. package/plugins/vite/alias.js +174 -174
  675. package/plugins/vite/asap.js +245 -245
  676. package/plugins/vite/build-pipeline.js +371 -371
  677. package/plugins/vite/build.js +19 -19
  678. package/plugins/vite/buildinfo.js +41 -41
  679. package/plugins/vite/config.js +106 -106
  680. package/plugins/vite/copyfiles.js +138 -138
  681. package/plugins/vite/defines.js +70 -70
  682. package/plugins/vite/dependencies.js +232 -232
  683. package/plugins/vite/dependency-watcher.js +231 -231
  684. package/plugins/vite/drop-client.js +76 -76
  685. package/plugins/vite/drop.js +87 -87
  686. package/plugins/vite/editor-connection.js +124 -124
  687. package/plugins/vite/facebook-instant-games.js +102 -102
  688. package/plugins/vite/gzip.js +5 -5
  689. package/plugins/vite/imports-logger.js +143 -143
  690. package/plugins/vite/index.js +143 -143
  691. package/plugins/vite/license.js +56 -56
  692. package/plugins/vite/local-files.js +231 -231
  693. package/plugins/vite/meta.js +163 -163
  694. package/plugins/vite/npm.js +7 -7
  695. package/plugins/vite/peer.js +29 -29
  696. package/plugins/vite/poster-client.js +73 -73
  697. package/plugins/vite/poster.js +79 -79
  698. package/plugins/vite/pwa.js +604 -604
  699. package/plugins/vite/reload-client.js +15 -15
  700. package/plugins/vite/reload.js +351 -351
  701. package/plugins/vite/server.js +66 -66
  702. package/plugins/vite/transform-codegen.js +55 -55
  703. package/plugins/vite/transform.js +31 -31
  704. package/plugins/vite/vite-4.4-hack.js +31 -31
  705. package/src/asap/needle-asap.ts +111 -111
  706. package/src/asap/sessiongranted.ts +75 -75
  707. package/src/asap/utils.ts +4 -4
  708. package/src/engine/analytics/index.ts +10 -10
  709. package/src/engine/analytics/lcp.ts +35 -35
  710. package/src/engine/api.ts +82 -82
  711. package/src/engine/assets/index.ts +59 -59
  712. package/src/engine/assets/static.js +5 -5
  713. package/src/engine/codegen/register_types.ts +300 -300
  714. package/src/engine/debug/debug.ts +51 -51
  715. package/src/engine/debug/debug_console.ts +333 -333
  716. package/src/engine/debug/debug_overlay.ts +332 -332
  717. package/src/engine/debug/debug_spatial_console.ts +429 -429
  718. package/src/engine/debug/index.ts +1 -1
  719. package/src/engine/engine_addressables.ts +680 -680
  720. package/src/engine/engine_animation.ts +145 -145
  721. package/src/engine/engine_application.ts +113 -113
  722. package/src/engine/engine_assetdatabase.ts +387 -387
  723. package/src/engine/engine_audio.ts +24 -24
  724. package/src/engine/engine_camera.ts +39 -39
  725. package/src/engine/engine_components.ts +366 -366
  726. package/src/engine/engine_components_internal.ts +40 -40
  727. package/src/engine/engine_constants.ts +52 -52
  728. package/src/engine/engine_context.ts +1811 -1811
  729. package/src/engine/engine_context_registry.ts +129 -129
  730. package/src/engine/engine_coroutine.ts +54 -54
  731. package/src/engine/engine_create_objects.ts +411 -411
  732. package/src/engine/engine_default_parameters.ts +3 -3
  733. package/src/engine/engine_editor-sync.ts +28 -28
  734. package/src/engine/engine_fileloader.js +9 -9
  735. package/src/engine/engine_gameobject.ts +709 -709
  736. package/src/engine/engine_generic_utils.js +13 -13
  737. package/src/engine/engine_gizmos.ts +577 -577
  738. package/src/engine/engine_gltf.ts +29 -29
  739. package/src/engine/engine_gltf_builtin_components.ts +403 -403
  740. package/src/engine/engine_hot_reload.ts +210 -210
  741. package/src/engine/engine_input.ts +1500 -1500
  742. package/src/engine/engine_input_utils.ts +23 -23
  743. package/src/engine/engine_instancing.ts +45 -45
  744. package/src/engine/engine_license.ts +386 -386
  745. package/src/engine/engine_lifecycle_api.ts +113 -113
  746. package/src/engine/engine_lifecycle_functions_internal.ts +193 -193
  747. package/src/engine/engine_lightdata.ts +117 -117
  748. package/src/engine/engine_loaders.callbacks.ts +136 -136
  749. package/src/engine/engine_loaders.gltf.ts +82 -82
  750. package/src/engine/engine_loaders.ts +378 -378
  751. package/src/engine/engine_lods.ts +168 -168
  752. package/src/engine/engine_mainloop_utils.ts +472 -472
  753. package/src/engine/engine_math.ts +282 -282
  754. package/src/engine/engine_modules.ts +83 -83
  755. package/src/engine/engine_networking.ts +862 -862
  756. package/src/engine/engine_networking_auto.ts +352 -352
  757. package/src/engine/engine_networking_blob.ts +275 -275
  758. package/src/engine/engine_networking_files.ts +217 -217
  759. package/src/engine/engine_networking_files_default_components.ts +58 -58
  760. package/src/engine/engine_networking_instantiate.ts +419 -419
  761. package/src/engine/engine_networking_peer.ts +159 -159
  762. package/src/engine/engine_networking_streams.ts +713 -713
  763. package/src/engine/engine_networking_types.ts +24 -24
  764. package/src/engine/engine_networking_utils.ts +23 -23
  765. package/src/engine/engine_networking_websocket.ts +2 -2
  766. package/src/engine/engine_patcher.ts +199 -199
  767. package/src/engine/engine_physics.ts +783 -783
  768. package/src/engine/engine_physics.types.ts +46 -46
  769. package/src/engine/engine_physics_rapier.ts +1577 -1577
  770. package/src/engine/engine_playerview.ts +80 -80
  771. package/src/engine/engine_scenelighting.ts +294 -294
  772. package/src/engine/engine_serialization.ts +2 -2
  773. package/src/engine/engine_serialization_builtin_serializer.ts +473 -473
  774. package/src/engine/engine_serialization_core.ts +720 -720
  775. package/src/engine/engine_serialization_decorator.ts +80 -80
  776. package/src/engine/engine_setup.ts +1 -1
  777. package/src/engine/engine_shaders.ts +267 -267
  778. package/src/engine/engine_shims.ts +32 -32
  779. package/src/engine/engine_test_utils.ts +109 -109
  780. package/src/engine/engine_texture.ts +82 -82
  781. package/src/engine/engine_three_utils.ts +849 -849
  782. package/src/engine/engine_time.ts +94 -94
  783. package/src/engine/engine_time_utils.ts +237 -237
  784. package/src/engine/engine_tonemapping.ts +210 -210
  785. package/src/engine/engine_types.ts +730 -730
  786. package/src/engine/engine_typestore.ts +63 -63
  787. package/src/engine/engine_util_decorator.ts +136 -136
  788. package/src/engine/engine_utils.ts +1093 -1093
  789. package/src/engine/engine_utils_format.ts +273 -273
  790. package/src/engine/engine_utils_screenshot.ts +698 -698
  791. package/src/engine/engine_utils_screenshot.xr.ts +103 -103
  792. package/src/engine/export/gltf/Writers.ts +34 -34
  793. package/src/engine/export/gltf/index.ts +158 -158
  794. package/src/engine/export/index.ts +2 -2
  795. package/src/engine/export/state.ts +19 -19
  796. package/src/engine/export/utils.ts +9 -9
  797. package/src/engine/extensions/EXT_texture_exr.ts +50 -50
  798. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +195 -195
  799. package/src/engine/extensions/NEEDLE_components.ts +268 -268
  800. package/src/engine/extensions/NEEDLE_gameobject_data.ts +81 -81
  801. package/src/engine/extensions/NEEDLE_lighting_settings.ts +185 -185
  802. package/src/engine/extensions/NEEDLE_lightmaps.ts +119 -119
  803. package/src/engine/extensions/NEEDLE_persistent_assets.ts +76 -76
  804. package/src/engine/extensions/NEEDLE_render_objects.ts +209 -209
  805. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +640 -640
  806. package/src/engine/extensions/extension_resolver.ts +4 -4
  807. package/src/engine/extensions/extension_utils.ts +166 -166
  808. package/src/engine/extensions/extensions.ts +140 -140
  809. package/src/engine/extensions/index.ts +5 -5
  810. package/src/engine/extensions/usage_tracker.ts +100 -100
  811. package/src/engine/js-extensions/Camera.ts +37 -37
  812. package/src/engine/js-extensions/ExtensionUtils.ts +85 -85
  813. package/src/engine/js-extensions/Layers.ts +23 -23
  814. package/src/engine/js-extensions/Object3D.ts +296 -296
  815. package/src/engine/js-extensions/RGBAColor.ts +126 -126
  816. package/src/engine/js-extensions/Vector.ts +18 -18
  817. package/src/engine/js-extensions/index.ts +4 -4
  818. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +125 -125
  819. package/src/engine/shaders/shaderData.ts +67 -67
  820. package/src/engine/tests/test_utils.ts +63 -63
  821. package/src/engine/webcomponents/WebXRButtons.ts +260 -260
  822. package/src/engine/webcomponents/api.ts +6 -6
  823. package/src/engine/webcomponents/buttons.ts +292 -292
  824. package/src/engine/webcomponents/fonts.ts +41 -41
  825. package/src/engine/webcomponents/icons.ts +57 -57
  826. package/src/engine/webcomponents/index.ts +1 -1
  827. package/src/engine/webcomponents/logo-element.ts +78 -78
  828. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +573 -573
  829. package/src/engine/webcomponents/needle menu/needle-menu.ts +1118 -1118
  830. package/src/engine/webcomponents/needle-button.ts +181 -181
  831. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +186 -186
  832. package/src/engine/webcomponents/needle-engine.attributes.ts +82 -82
  833. package/src/engine/webcomponents/needle-engine.extras.ts +16 -16
  834. package/src/engine/webcomponents/needle-engine.loading.ts +373 -373
  835. package/src/engine/webcomponents/needle-engine.ts +871 -871
  836. package/src/engine/xr/NeedleXRController.ts +1125 -1125
  837. package/src/engine/xr/NeedleXRSession.ts +1624 -1624
  838. package/src/engine/xr/NeedleXRSync.ts +220 -220
  839. package/src/engine/xr/SceneTransition.ts +78 -78
  840. package/src/engine/xr/TempXRContext.ts +216 -216
  841. package/src/engine/xr/XRRig.ts +9 -9
  842. package/src/engine/xr/api.ts +5 -5
  843. package/src/engine/xr/events.ts +102 -102
  844. package/src/engine/xr/internal.ts +34 -34
  845. package/src/engine/xr/usdz.ts +30 -30
  846. package/src/engine/xr/utils.ts +39 -39
  847. package/src/engine-components/AlignmentConstraint.ts +36 -36
  848. package/src/engine-components/Animation.ts +557 -557
  849. package/src/engine-components/AnimationCurve.ts +150 -150
  850. package/src/engine-components/AnimationUtils.ts +28 -28
  851. package/src/engine-components/AnimationUtilsAutoplay.ts +43 -43
  852. package/src/engine-components/Animator.ts +397 -397
  853. package/src/engine-components/AnimatorController.ts +1293 -1293
  854. package/src/engine-components/AudioListener.ts +92 -92
  855. package/src/engine-components/AudioSource.ts +644 -644
  856. package/src/engine-components/AvatarLoader.ts +263 -263
  857. package/src/engine-components/AxesHelper.ts +59 -59
  858. package/src/engine-components/BasicIKConstraint.ts +54 -54
  859. package/src/engine-components/BoxCollider.ts +1 -1
  860. package/src/engine-components/BoxHelperComponent.ts +114 -114
  861. package/src/engine-components/Camera.ts +719 -719
  862. package/src/engine-components/CameraUtils.ts +136 -136
  863. package/src/engine-components/CharacterController.ts +253 -253
  864. package/src/engine-components/Collider.ts +374 -374
  865. package/src/engine-components/Component.ts +1297 -1297
  866. package/src/engine-components/ContactShadows.ts +506 -506
  867. package/src/engine-components/DeleteBox.ts +62 -62
  868. package/src/engine-components/DeviceFlag.ts +46 -46
  869. package/src/engine-components/DragControls.ts +1623 -1623
  870. package/src/engine-components/DropListener.ts +713 -713
  871. package/src/engine-components/Duplicatable.ts +198 -198
  872. package/src/engine-components/EventList.ts +266 -266
  873. package/src/engine-components/EventTrigger.ts +74 -74
  874. package/src/engine-components/EventType.ts +22 -22
  875. package/src/engine-components/Fog.ts +60 -60
  876. package/src/engine-components/Gizmos.ts +56 -56
  877. package/src/engine-components/GridHelper.ts +48 -48
  878. package/src/engine-components/GroundProjection.ts +356 -356
  879. package/src/engine-components/Interactable.ts +14 -14
  880. package/src/engine-components/Joints.ts +52 -52
  881. package/src/engine-components/LODGroup.ts +153 -153
  882. package/src/engine-components/Light.ts +558 -558
  883. package/src/engine-components/LookAtConstraint.ts +25 -25
  884. package/src/engine-components/NeedleMenu.ts +84 -84
  885. package/src/engine-components/NestedGltf.ts +86 -86
  886. package/src/engine-components/Networking.ts +114 -114
  887. package/src/engine-components/OffsetConstraint.ts +60 -60
  888. package/src/engine-components/OrbitControls.ts +1074 -1074
  889. package/src/engine-components/PlayerColor.ts +103 -103
  890. package/src/engine-components/ReflectionProbe.ts +216 -216
  891. package/src/engine-components/Renderer.ts +900 -900
  892. package/src/engine-components/RendererInstancing.ts +855 -855
  893. package/src/engine-components/RendererLightmap.ts +198 -198
  894. package/src/engine-components/RigidBody.ts +526 -526
  895. package/src/engine-components/SceneSwitcher.ts +1030 -1030
  896. package/src/engine-components/ScreenCapture.ts +592 -592
  897. package/src/engine-components/ShadowCatcher.ts +172 -172
  898. package/src/engine-components/Skybox.ts +455 -455
  899. package/src/engine-components/SmoothFollow.ts +76 -76
  900. package/src/engine-components/SpatialTrigger.ts +229 -229
  901. package/src/engine-components/SpectatorCamera.ts +787 -787
  902. package/src/engine-components/SphereCollider.ts +1 -1
  903. package/src/engine-components/SpriteRenderer.ts +468 -468
  904. package/src/engine-components/SyncedCamera.ts +220 -220
  905. package/src/engine-components/SyncedRoom.ts +380 -380
  906. package/src/engine-components/SyncedTransform.ts +383 -383
  907. package/src/engine-components/TestRunner.ts +118 -118
  908. package/src/engine-components/TransformGizmo.ts +219 -219
  909. package/src/engine-components/VideoPlayer.ts +1025 -1025
  910. package/src/engine-components/Voip.ts +363 -363
  911. package/src/engine-components/api.ts +60 -60
  912. package/src/engine-components/avatar/AvatarBlink_Simple.ts +69 -69
  913. package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +63 -63
  914. package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +139 -139
  915. package/src/engine-components/avatar/Avatar_MouthShapes.ts +83 -83
  916. package/src/engine-components/avatar/Avatar_MustacheShake.ts +31 -31
  917. package/src/engine-components/codegen/components.ts +217 -217
  918. package/src/engine-components/debug/LogStats.ts +21 -21
  919. package/src/engine-components/export/gltf/GltfExport.ts +265 -265
  920. package/src/engine-components/export/usdz/Extension.ts +24 -24
  921. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2413 -2413
  922. package/src/engine-components/export/usdz/USDZExporter.ts +705 -705
  923. package/src/engine-components/export/usdz/extensions/Animation.ts +1204 -1204
  924. package/src/engine-components/export/usdz/extensions/DocumentExtension.ts +9 -9
  925. package/src/engine-components/export/usdz/extensions/USDZText.ts +240 -240
  926. package/src/engine-components/export/usdz/extensions/USDZUI.ts +189 -189
  927. package/src/engine-components/export/usdz/extensions/behavior/Actions.ts +99 -99
  928. package/src/engine-components/export/usdz/extensions/behavior/AudioExtension.ts +102 -102
  929. package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +320 -320
  930. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +1225 -1225
  931. package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +646 -646
  932. package/src/engine-components/export/usdz/extensions/behavior/PhysicsExtension.ts +132 -132
  933. package/src/engine-components/export/usdz/index.ts +2 -2
  934. package/src/engine-components/export/usdz/utils/animationutils.ts +191 -191
  935. package/src/engine-components/export/usdz/utils/quicklook.ts +50 -50
  936. package/src/engine-components/particlesystem/ParticleSystem.ts +1287 -1287
  937. package/src/engine-components/particlesystem/ParticleSystemModules.ts +1765 -1765
  938. package/src/engine-components/particlesystem/ParticleSystemSubEmitter.ts +111 -111
  939. package/src/engine-components/particlesystem/api.ts +1 -1
  940. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +55 -55
  941. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +116 -116
  942. package/src/engine-components/postprocessing/Effects/ChromaticAberration.ts +37 -37
  943. package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +95 -95
  944. package/src/engine-components/postprocessing/Effects/DepthOfField.ts +103 -103
  945. package/src/engine-components/postprocessing/Effects/EffectWrapper.ts +25 -25
  946. package/src/engine-components/postprocessing/Effects/Pixelation.ts +32 -32
  947. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +90 -90
  948. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +191 -191
  949. package/src/engine-components/postprocessing/Effects/Sharpening.ts +138 -138
  950. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +61 -61
  951. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +155 -155
  952. package/src/engine-components/postprocessing/Effects/Vignette.ts +59 -59
  953. package/src/engine-components/postprocessing/PostProcessingEffect.ts +172 -172
  954. package/src/engine-components/postprocessing/PostProcessingHandler.ts +398 -398
  955. package/src/engine-components/postprocessing/Volume.ts +410 -410
  956. package/src/engine-components/postprocessing/VolumeParameter.ts +158 -158
  957. package/src/engine-components/postprocessing/VolumeProfile.ts +61 -61
  958. package/src/engine-components/postprocessing/index.ts +5 -5
  959. package/src/engine-components/postprocessing/utils.ts +52 -52
  960. package/src/engine-components/timeline/PlayableDirector.ts +722 -722
  961. package/src/engine-components/timeline/SignalAsset.ts +144 -144
  962. package/src/engine-components/timeline/TimelineModels.ts +92 -92
  963. package/src/engine-components/timeline/TimelineTracks.ts +967 -967
  964. package/src/engine-components/timeline/index.ts +3 -3
  965. package/src/engine-components/ui/BaseUIComponent.ts +203 -203
  966. package/src/engine-components/ui/Button.ts +307 -307
  967. package/src/engine-components/ui/Canvas.ts +419 -419
  968. package/src/engine-components/ui/CanvasGroup.ts +54 -54
  969. package/src/engine-components/ui/EventSystem.ts +854 -854
  970. package/src/engine-components/ui/Graphic.ts +275 -275
  971. package/src/engine-components/ui/Image.ts +112 -112
  972. package/src/engine-components/ui/InputField.ts +321 -321
  973. package/src/engine-components/ui/Interfaces.ts +57 -57
  974. package/src/engine-components/ui/Layout.ts +334 -334
  975. package/src/engine-components/ui/Outline.ts +13 -13
  976. package/src/engine-components/ui/PointerEvents.ts +206 -206
  977. package/src/engine-components/ui/RaycastUtils.ts +69 -69
  978. package/src/engine-components/ui/Raycaster.ts +102 -102
  979. package/src/engine-components/ui/RectTransform.ts +375 -375
  980. package/src/engine-components/ui/SpatialHtml.ts +79 -79
  981. package/src/engine-components/ui/Symbols.ts +1 -1
  982. package/src/engine-components/ui/Text.ts +578 -578
  983. package/src/engine-components/ui/Utils.ts +113 -113
  984. package/src/engine-components/utils/EnvironmentScene.ts +245 -245
  985. package/src/engine-components/utils/LookAt.ts +88 -88
  986. package/src/engine-components/utils/OpenURL.ts +114 -114
  987. package/src/engine-components/webxr/Avatar.ts +265 -265
  988. package/src/engine-components/webxr/TeleportTarget.ts +9 -9
  989. package/src/engine-components/webxr/WebARCameraBackground.ts +175 -175
  990. package/src/engine-components/webxr/WebARSessionRoot.ts +880 -880
  991. package/src/engine-components/webxr/WebXR.ts +585 -585
  992. package/src/engine-components/webxr/WebXRAvatar.ts +66 -66
  993. package/src/engine-components/webxr/WebXRImageTracking.ts +519 -519
  994. package/src/engine-components/webxr/WebXRPlaneTracking.ts +570 -570
  995. package/src/engine-components/webxr/WebXRRig.ts +77 -77
  996. package/src/engine-components/webxr/XRFlag.ts +147 -147
  997. package/src/engine-components/webxr/controllers/XRControllerFollow.ts +118 -118
  998. package/src/engine-components/webxr/controllers/XRControllerModel.ts +373 -373
  999. package/src/engine-components/webxr/controllers/XRControllerMovement.ts +550 -550
  1000. package/src/engine-components/webxr/index.ts +2 -2
  1001. package/src/engine-components/webxr/types.ts +3 -3
  1002. package/src/engine-components-experimental/Presentation.ts +12 -12
  1003. package/src/engine-components-experimental/api.ts +4 -4
  1004. package/src/engine-components-experimental/networking/PlayerSync.ts +401 -401
  1005. package/src/engine-schemes/COMPILE_SCHEMES.bat +3 -3
  1006. package/src/engine-schemes/COMPILE_TS.bat +11 -11
  1007. package/src/engine-schemes/README.md +1 -1
  1008. package/src/engine-schemes/api.ts +12 -12
  1009. package/src/engine-schemes/dist/api.js +17 -0
  1010. package/src/engine-schemes/dist/api.js.meta +7 -0
  1011. package/src/engine-schemes/dist/schemes.js +25 -0
  1012. package/src/engine-schemes/dist/schemes.js.meta +7 -0
  1013. package/src/engine-schemes/dist/synced-camera-model.js +74 -0
  1014. package/src/engine-schemes/dist/synced-camera-model.js.meta +7 -0
  1015. package/src/engine-schemes/dist/synced-transform-model.js +73 -0
  1016. package/src/engine-schemes/dist/synced-transform-model.js.meta +7 -0
  1017. package/src/engine-schemes/dist/transform.js +46 -0
  1018. package/src/engine-schemes/dist/transform.js.meta +7 -0
  1019. package/src/engine-schemes/dist/vec2.js +32 -0
  1020. package/src/engine-schemes/dist/vec2.js.meta +7 -0
  1021. package/src/engine-schemes/dist/vec3.js +36 -0
  1022. package/src/engine-schemes/dist/vec3.js.meta +7 -0
  1023. package/src/engine-schemes/dist/vec4.js +40 -0
  1024. package/src/engine-schemes/dist/vec4.js.meta +7 -0
  1025. package/src/engine-schemes/dist/vr-user-state-buffer.js +110 -0
  1026. package/src/engine-schemes/dist/vr-user-state-buffer.js.meta +7 -0
  1027. package/src/engine-schemes/schemes.ts +28 -28
  1028. package/src/engine-schemes/synced-camera-model.ts +92 -92
  1029. package/src/engine-schemes/synced-transform-model.ts +90 -90
  1030. package/src/engine-schemes/syncedCamera.fbs +10 -10
  1031. package/src/engine-schemes/transform.ts +50 -50
  1032. package/src/engine-schemes/transforms.fbs +25 -25
  1033. package/src/engine-schemes/vec.fbs +19 -19
  1034. package/src/engine-schemes/vec2.ts +33 -33
  1035. package/src/engine-schemes/vec3.ts +38 -38
  1036. package/src/engine-schemes/vec4.ts +43 -43
  1037. package/src/engine-schemes/vr-user-state-buffer.ts +145 -145
  1038. package/src/engine-schemes/vrUserStateBuffer.fbs +17 -17
  1039. package/src/include/draco/draco_decoder.js +34 -34
  1040. package/src/include/ktx2/basis_transcoder.js +21 -21
  1041. package/src/include/needle/arial-msdf.json +1471 -1471
  1042. package/src/include/three/DragControls.js +231 -231
  1043. package/src/include/three/EXT_mesh_gpu_instancing_exporter.js +66 -66
  1044. package/src/needle-engine.ts +70 -70
@@ -1,1577 +1,1577 @@
1
- import type { Ball, Collider, ColliderDesc, Cuboid, EventQueue, QueryFilterFlags, Ray, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat';
2
- import { BufferAttribute, BufferGeometry, InterleavedBufferAttribute, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from 'three'
3
- import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
4
-
5
- import { CollisionDetectionMode, PhysicsMaterialCombine } from '../engine/engine_physics.types.js';
6
- import { MeshCollider } from '../engine-components/Collider.js';
7
- import { isDevEnvironment } from './debug/debug.js';
8
- import { ContextEvent, ContextRegistry } from './engine_context_registry.js';
9
- import { foreachComponent } from './engine_gameobject.js';
10
- import { Gizmos } from './engine_gizmos.js';
11
- import { Mathf } from './engine_math.js';
12
- import { MODULES } from './engine_modules.js';
13
- import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils.js"
14
- import type {
15
- IBoxCollider,
16
- ICollider,
17
- IComponent,
18
- IContext,
19
- IGameObject,
20
- IPhysicsEngine,
21
- IRigidbody,
22
- ISphereCollider,
23
- Vec2,
24
- Vec3,
25
- } from './engine_types.js';
26
- import { Collision, ContactPoint } from './engine_types.js';
27
- import { SphereOverlapResult } from './engine_types.js';
28
- import { CircularBuffer, getParam } from "./engine_utils.js"
29
-
30
- const debugPhysics = getParam("debugphysics");
31
- const debugColliderPlacement = getParam("debugcolliderplacement");
32
- const debugCollisions = getParam("debugcollisions");
33
- const showColliders = getParam("showcolliders");
34
- const showPhysicsRaycasts = getParam("debugraycasts");
35
-
36
-
37
- /** on physics body and references the needle component */
38
- const $componentKey = Symbol("needle component");
39
- /** on needle component and references physics body */
40
- const $bodyKey = Symbol("physics body");
41
- const $colliderRigidbody = Symbol("rigidbody");
42
-
43
-
44
- declare const NEEDLE_USE_RAPIER: boolean;
45
- globalThis["NEEDLE_USE_RAPIER"] = globalThis["NEEDLE_USE_RAPIER"] !== undefined ? globalThis["NEEDLE_USE_RAPIER"] : true;
46
- if (debugPhysics)
47
- console.log("Use Rapier", NEEDLE_USE_RAPIER, globalThis["NEEDLE_USE_RAPIER"])
48
-
49
- if (NEEDLE_USE_RAPIER) {
50
- ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, evt => {
51
- if (debugPhysics)
52
- console.log("Register rapier physics backend")
53
- evt.context.physics.engine = new RapierPhysics(evt.context);
54
- // We do not initialize physics immediately to avoid loading the physics engine if it is not needed
55
- });
56
- }
57
-
58
-
59
- declare type PhysicsBody = {
60
- translation(): { x: number, y: number, z: number }
61
- rotation(): { x: number, y: number, z: number, w: number }
62
- }
63
-
64
- export class RapierPhysics implements IPhysicsEngine {
65
-
66
- debugRenderColliders: boolean = false;
67
- debugRenderRaycasts: boolean = false;
68
-
69
- removeBody(obj: IComponent) {
70
- if (!obj) return;
71
- this.validate();
72
- const body = obj[$bodyKey];
73
- obj[$bodyKey] = null;
74
- if (body && this.world) {
75
- const index = this.objects.findIndex(o => o === obj);
76
- if (index >= 0) {
77
- const rapierBody = this.bodies[index];
78
- // Remove references
79
- this.bodies.splice(index, 1);
80
- this.objects.splice(index, 1);
81
-
82
-
83
- // Remove the collider from the physics world
84
- if (rapierBody instanceof MODULES.RAPIER_PHYSICS.MODULE.Collider) {
85
- const rapierCollider = rapierBody as Collider;
86
- this.world?.removeCollider(rapierCollider, true);
87
-
88
- // also remove the rigidbody if it doesnt have colliders anymore
89
- const rapierRigidbody: RigidBody | null = rapierCollider.parent();
90
- if (rapierRigidbody && rapierRigidbody.numColliders() <= 0) {
91
- const rigidbody = rapierRigidbody[$componentKey] as IRigidbody;
92
- if (rigidbody) {
93
- // If the collider was attached to a rigidbody and this rigidbody now has no colliders anymore we should ignore it - because the Rigidbody component will delete itself
94
- }
95
- else {
96
- // But if there is no explicit rigidbody needle component then the colliders did create it implictly and thus we need to remove it here:
97
- this.world?.removeRigidBody(rapierRigidbody);
98
- }
99
- }
100
- }
101
- // Remove the rigidbody from the physics world
102
- else if (rapierBody instanceof MODULES.RAPIER_PHYSICS.MODULE.RigidBody) {
103
- if (rapierBody.numColliders() <= 0) {
104
- this.world?.removeRigidBody(rapierBody);
105
- }
106
- else {
107
- if (isDevEnvironment()) {
108
- if (!rapierBody["did_log_removing"]) {
109
- setTimeout(() => {
110
- if (rapierBody.numColliders() > 0) {
111
- rapierBody["did_log_removing"] = true;
112
- console.warn("RapierPhysics: removing rigidbody with colliders from the physics world is not possible right now, please remove the colliders first");
113
- }
114
- }, 1);
115
-
116
- }
117
- }
118
- }
119
- }
120
- }
121
- }
122
- }
123
-
124
- updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean) {
125
- this.validate();
126
- if (!this.enabled) return;
127
- if (comp.destroyed || !comp.gameObject) return;
128
- if (!translation && !rotation) return;
129
-
130
- if ((comp as ICollider).isCollider === true) {
131
- // const collider = comp as ICollider;
132
- console.warn("TODO: implement updating collider position");
133
- }
134
- else {
135
- const rigidbody = comp as IRigidbody;
136
- const body = rigidbody[$bodyKey];
137
- if (body) {
138
- this.syncPhysicsBody(rigidbody.gameObject, body, translation, rotation);
139
- }
140
- }
141
- }
142
-
143
- updateProperties(obj: IRigidbody | ICollider) {
144
- this.validate();
145
-
146
- if ((obj as ICollider).isCollider) {
147
- const col = obj as ICollider;
148
- const body = col[$bodyKey];
149
- if (body) {
150
- this.internalUpdateColliderProperties(col, body);
151
- if (col.sharedMaterial)
152
- this.updatePhysicsMaterial(col);
153
- }
154
- }
155
- else {
156
- const rb = obj as IRigidbody;
157
- const physicsBody = this.internal_getRigidbody(rb);
158
- if (physicsBody) {
159
- this.internalUpdateRigidbodyProperties(rb, physicsBody);
160
- }
161
- }
162
- }
163
- addForce(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
164
- this.validate();
165
- const body = this.internal_getRigidbody(rigidbody);
166
- if (body) body.addForce(force, wakeup)
167
- else console.warn("Rigidbody doesn't exist: can not apply force (does your object with the Rigidbody have a collider?)");
168
- }
169
- addImpulse(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
170
- this.validate();
171
- const body = this.internal_getRigidbody(rigidbody);
172
- if (body) body.applyImpulse(force, wakeup);
173
- else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
174
- }
175
- getLinearVelocity(comp: IRigidbody | ICollider): Vec3 | null {
176
- this.validate();
177
- const body = this.internal_getRigidbody(comp);
178
- if (body) {
179
- const vel = body.linvel();
180
- return vel;
181
- }
182
- // else console.warn("Rigidbody doesn't exist: can not get linear velocity (does your object with the Rigidbody have a collider?)");
183
- return null;
184
- }
185
- getAngularVelocity(rb: IRigidbody): Vec3 | null {
186
- this.validate();
187
- const body = this.internal_getRigidbody(rb);
188
- if (body) {
189
- const vel = body.angvel();
190
- return vel;
191
- }
192
- // else console.warn("Rigidbody doesn't exist: can not get angular velocity (does your object with the Rigidbody have a collider?)");
193
- return null;
194
- }
195
- resetForces(rb: IRigidbody, wakeup: boolean) {
196
- this.validate();
197
- const body = this.internal_getRigidbody(rb);
198
- body?.resetForces(wakeup);
199
- }
200
- resetTorques(rb: IRigidbody, wakeup: boolean) {
201
- this.validate();
202
- const body = this.internal_getRigidbody(rb);
203
- body?.resetTorques(wakeup);
204
- }
205
- applyImpulse(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
206
- this.validate();
207
- const body = this.internal_getRigidbody(rb);
208
- if (body) body.applyImpulse(vec, wakeup);
209
- else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
210
- }
211
-
212
- wakeup(rb: IRigidbody) {
213
- this.validate();
214
- const body = this.internal_getRigidbody(rb);
215
- if (body) body.wakeUp();
216
- else console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
217
- }
218
- isSleeping(rb: IRigidbody) {
219
- this.validate();
220
- const body = this.internal_getRigidbody(rb);
221
- return body?.isSleeping();
222
- }
223
- setAngularVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
224
- this.validate();
225
- const body = this.internal_getRigidbody(rb);
226
- if (body) body.setAngvel(vec, wakeup);
227
- else console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
228
- }
229
- setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
230
- this.validate();
231
- const body = this.internal_getRigidbody(rb);
232
- if (body) body.setLinvel(vec, wakeup);
233
- else console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
234
- }
235
-
236
- private readonly context?: IContext;
237
- private _initializePromise?: Promise<boolean>;
238
- private _isInitialized: boolean = false;
239
-
240
- constructor(ctx: IContext) {
241
- this.context = ctx;
242
- }
243
-
244
- get isInitialized() { return this._isInitialized; }
245
-
246
- async initialize() {
247
- if (!this._initializePromise)
248
- this._initializePromise = this.internalInitialization();
249
- return this._initializePromise;
250
- }
251
-
252
- private async internalInitialization() {
253
- if (getParam("__nophysics")) {
254
- console.warn("Physics are disabled");
255
- return false;
256
- }
257
- if (debugPhysics) console.log("Initialize rapier physics engine");
258
- // NEEDLE_PHYSICS_INIT_START
259
- // use .env file with VITE_NEEDLE_USE_RAPIER=false to treeshake rapier
260
- // @ts-ignore
261
- if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_RAPIER === "false") {
262
- if (debugPhysics) console.log("Rapier disabled");
263
- return false;
264
- }
265
- // Can be transformed during build time to disable rapier
266
- if (!NEEDLE_USE_RAPIER) return false;
267
- if (this._hasCreatedWorld) {
268
- console.error("Invalid call to create physics world: world is already created");
269
- return true;
270
- }
271
- this._hasCreatedWorld = true;
272
- if (MODULES.RAPIER_PHYSICS.MAYBEMODULE == undefined) {
273
- if (debugPhysics) console.trace("Loading rapier physics engine");
274
- const module = await MODULES.RAPIER_PHYSICS.load();
275
- await module.init();
276
- }
277
- if (debugPhysics) console.log("Physics engine initialized, creating world...");
278
- this._world = new MODULES.RAPIER_PHYSICS.MODULE.World(this._gravity);
279
- this.rapierRay = new MODULES.RAPIER_PHYSICS.MODULE.Ray({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 });
280
- this.enabled = true;
281
- this._isInitialized = true;
282
- if (debugPhysics) console.log("Physics world created");
283
- return true;
284
- // NEEDLE_PHYSICS_INIT_END
285
- }
286
-
287
- /** Check is the physics engine has been initialized and the call can be made */
288
- private validate() {
289
- if (!this._isInitialized) {
290
- if (debugPhysics) {
291
- this["_lastWarnTime"] = this["_lastWarnTime"] ?? 0;
292
- if (Date.now() - this["_lastWarnTime"] > 1000) {
293
- this["_lastWarnTime"] = Date.now();
294
- console.warn("Physics engine is not initialized");
295
- }
296
- }
297
- }
298
- }
299
-
300
-
301
- private rapierRay!: Ray;
302
- private raycastVectorsBuffer = new CircularBuffer(() => new Vector3(), 10);
303
-
304
- public raycast(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
305
- maxDistance?: number,
306
- /** True if you want to also hit objects when the raycast starts from inside a collider */
307
- solid?: boolean,
308
- queryFilterFlags?: QueryFilterFlags,
309
- filterGroups?: number,
310
- /** Return false to ignore this collider */
311
- filterPredicate?: (c: ICollider) => boolean,
312
- /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
313
- * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
314
- * @default undefined
315
- */
316
- useIgnoreRaycastLayer?: boolean
317
- })
318
- : null | { point: Vector3, collider: ICollider } {
319
-
320
- if (!this._isInitialized) {
321
- console.log("Physics engine is not initialized");
322
- return null;
323
- }
324
-
325
- let maxDistance = options?.maxDistance;
326
- let solid = options?.solid;
327
-
328
- if (maxDistance === undefined) maxDistance = Infinity;
329
- if (solid === undefined) solid = true;
330
-
331
- const ray = this.getPhysicsRay(this.rapierRay, origin, direction);
332
- if (!ray) return null;
333
-
334
- if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawRay(ray.origin, ray.dir, 0x0000ff, 1);
335
-
336
- const hit = this.world?.castRay(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
337
- const component = c[$componentKey];
338
- if (options?.filterPredicate) return options.filterPredicate(component);
339
- if (options?.useIgnoreRaycastLayer !== false) {
340
- // ignore objects in the IgnoreRaycast=2 layer
341
- return !component?.gameObject.layers.isEnabled(2);
342
- }
343
- return true;
344
- });
345
- if (hit) {
346
- const point = ray.pointAt(hit.timeOfImpact);
347
- const vec = this.raycastVectorsBuffer.get();
348
- vec.set(point.x, point.y, point.z);
349
- return { point: vec, collider: hit.collider[$componentKey] };
350
- }
351
-
352
- return null;
353
- }
354
-
355
- public raycastAndGetNormal(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
356
- maxDistance?: number,
357
- /** True if you want to also hit objects when the raycast starts from inside a collider */
358
- solid?: boolean,
359
- queryFilterFlags?: QueryFilterFlags,
360
- filterGroups?: number,
361
- /** Return false to ignore this collider */
362
- filterPredicate?: (c: ICollider) => boolean,
363
- /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
364
- * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
365
- * @default undefined
366
- */
367
- useIgnoreRaycastLayer?: boolean
368
- })
369
- : null | { point: Vector3, normal: Vector3, collider: ICollider } {
370
-
371
- if (!this._isInitialized) {
372
- return null;
373
- }
374
-
375
- let maxDistance = options?.maxDistance;
376
- let solid = options?.solid;
377
-
378
- if (maxDistance === undefined) maxDistance = Infinity;
379
- if (solid === undefined) solid = true;
380
-
381
- const ray = this.getPhysicsRay(this.rapierRay, origin, direction);
382
- if (!ray) return null;
383
-
384
- if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawRay(ray.origin, ray.dir, 0x0000ff, 1);
385
-
386
- const hit = this.world?.castRayAndGetNormal(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
387
- const component = c[$componentKey];
388
- if (options?.filterPredicate) return options.filterPredicate(component);
389
- if (options?.useIgnoreRaycastLayer !== false) {
390
- // ignore objects in the IgnoreRaycast=2 layer
391
- return !component?.gameObject.layers.isEnabled(2);
392
- }
393
- return true;
394
- });
395
- if (hit) {
396
- const point = ray.pointAt(hit.timeOfImpact);
397
- const normal = hit.normal;
398
- const vec = this.raycastVectorsBuffer.get();
399
- const nor = this.raycastVectorsBuffer.get();
400
- vec.set(point.x, point.y, point.z);
401
- nor.set(normal.x, normal.y, normal.z);
402
- return { point: vec, normal: nor, collider: hit.collider[$componentKey] };
403
- }
404
- return null;
405
- }
406
-
407
- private getPhysicsRay(ray: Ray, origin?: Vec2 | Vec3, direction?: Vec3): Ray | null {
408
- const cam = this.context?.mainCamera;
409
- if (origin === undefined) {
410
- const pos = this.context?.input.getPointerPosition(0);
411
- if (pos) origin = pos;
412
- else return null;
413
- }
414
- // if we get origin in 2d space we need to project it to 3d space
415
- if (origin["z"] === undefined) {
416
- if (!cam) {
417
- console.error("Can not perform raycast from 2d point - no main camera found");
418
- return null;
419
- }
420
- const vec3 = this.raycastVectorsBuffer.get();
421
- vec3.x = origin.x;
422
- vec3.y = origin.y;
423
- vec3.z = 0;
424
- // if the origin is in screen space we need to convert it to raycaster space
425
- if (vec3.x > 1 || vec3.y > 1 || vec3.y < -1 || vec3.x < -1) {
426
- if (debugPhysics) console.warn("Converting screenspace to raycast space", vec3)
427
- this.context?.input.convertScreenspaceToRaycastSpace(vec3);
428
- }
429
- vec3.unproject(cam);
430
- origin = vec3;
431
- }
432
-
433
- const o = origin as Vec3;
434
-
435
- ray.origin.x = o.x;
436
- ray.origin.y = o.y;
437
- ray.origin.z = o.z;
438
- const vec = this.raycastVectorsBuffer.get();
439
- if (direction)
440
- vec.set(direction.x, direction.y, direction.z);
441
- else {
442
- if (!cam) {
443
- console.error("Can not perform raycast - no camera found");
444
- return null;
445
- }
446
- vec.set(ray.origin.x, ray.origin.y, ray.origin.z);
447
- const camPosition = getWorldPosition(cam);
448
- vec.sub(camPosition);
449
- }
450
- // we need to normalize the ray because our input is a max travel length and the direction may be not normalized
451
- vec.normalize();
452
- ray.dir.x = vec.x;
453
- ray.dir.y = vec.y;
454
- ray.dir.z = vec.z;
455
- // Gizmos.DrawRay(ray.origin, ray.dir, 0xff0000, Infinity);
456
- return ray;
457
- }
458
-
459
-
460
- private rapierSphere: Ball | null = null;
461
- private readonly rapierColliderArray: Array<SphereOverlapResult> = [];
462
- private readonly rapierIdentityRotation = { x: 0, y: 0, z: 0, w: 1 };
463
- private readonly rapierForwardVector = { x: 0, y: 0, z: 1 };
464
- /** Precice sphere overlap detection using rapier against colliders
465
- * @param point center of the sphere in worldspace
466
- * @param radius radius of the sphere
467
- * @returns array of colliders that overlap with the sphere. Note: they currently only contain the collider and the gameobject
468
- */
469
- public sphereOverlap(point: Vector3, radius: number): Array<SphereOverlapResult> {
470
- this.rapierColliderArray.length = 0;
471
- if (!this._isInitialized) {
472
- return this.rapierColliderArray;
473
- }
474
- if (!this.world) return this.rapierColliderArray;
475
- this.rapierSphere ??= new MODULES.RAPIER_PHYSICS.MODULE.Ball(radius);
476
- this.rapierSphere.radius = radius;
477
-
478
- if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawWireSphere(point, radius, 0x3344ff, 1);
479
- this.world.intersectionsWithShape(point,
480
- this.rapierIdentityRotation,
481
- this.rapierSphere,
482
- col => {
483
- const collider = col[$componentKey] as ICollider
484
- // if (collider.gameObject.layers.isEnabled(2)) return true;
485
- const intersection = new SphereOverlapResult(collider.gameObject, collider);
486
- this.rapierColliderArray.push(intersection);
487
- return true; // Return `false` instead if we want to stop searching for other colliders that contain this point.
488
- },
489
- // TODO: it seems as QueryFilterFlags.EXCLUDE_SENSORS also excludes DYNAMIC Rigidbodies (only if they're set to kinematic)
490
- undefined, // QueryFilterFlags.EXCLUDE_SENSORS,
491
- undefined, undefined, undefined,
492
- col => {
493
- // we don't want to raycast against triggers (see comment about Exclude Sensors above)
494
- if (col.isSensor()) return false;
495
- const collider = col[$componentKey] as ICollider
496
- return collider.gameObject.layers.isEnabled(2) == false
497
- }
498
- );
499
- return this.rapierColliderArray;
500
-
501
-
502
- // TODO: this only returns one hit
503
- // let filterGroups = 0xffffffff;
504
- // filterGroups &= ~(1 << 2);
505
- // const hit: ShapeColliderTOI | null = this.world.castShape(point,
506
- // this.rapierIdentityRotation,
507
- // this.rapierForwardVector,
508
- // this.rapierSphere,
509
- // 0,
510
- // QueryFilterFlags.EXCLUDE_SENSORS,
511
- // // filterGroups,
512
- // );
513
- // // console.log(hit);
514
- // if (hit) {
515
- // const collider = hit.collider[$componentKey] as ICollider
516
- // const intersection = new SphereOverlapResult(collider.gameObject);
517
- // this.rapierColliderArray.push(intersection);
518
- // // const localpt = hit.witness2;
519
- // // // const normal = hit.normal2;
520
- // // const hitPoint = new Vector3(localpt.x, localpt.y, localpt.z);
521
- // // // collider.gameObject.localToWorld(hitPoint);
522
- // // // const normalPt = new Vector3(normal.x, normal.y, normal.z);
523
- // // // const mat = new Matrix4().setPosition(point).scale(new Vector3(radius, radius, radius));
524
- // // // hitPoint.applyMatrix4(mat);
525
- // // console.log(hit.witness2)
526
- // // // hitPoint.add(point);
527
- // // const dist = hitPoint.distanceTo(point);
528
- // }
529
-
530
- // return this.rapierColliderArray;
531
- }
532
-
533
-
534
-
535
-
536
- // physics simulation
537
-
538
- enabled: boolean = false;
539
- /** Get access to the rapier world */
540
- public get world(): World | undefined { return this._world };
541
-
542
- private _tempPosition: Vector3 = new Vector3();
543
- private _tempQuaternion: Quaternion = new Quaternion();
544
- private _tempScale: Vector3 = new Vector3();
545
- private _tempMatrix: Matrix4 = new Matrix4();
546
-
547
- private static _didLoadPhysicsEngine: boolean = false;
548
-
549
- private _isUpdatingPhysicsWorld: boolean = false;
550
- get isUpdating(): boolean { return this._isUpdatingPhysicsWorld; }
551
-
552
-
553
- private _world?: World;
554
- private _hasCreatedWorld: boolean = false;
555
- private eventQueue?: EventQueue;
556
- private collisionHandler?: PhysicsCollisionHandler;
557
-
558
-
559
- private objects: IComponent[] = [];
560
- private bodies: PhysicsBody[] = [];
561
-
562
- private _meshCache: Map<string, Float32Array> = new Map<string, Float32Array>();
563
-
564
- private _gravity = { x: 0.0, y: -9.81, z: 0.0 };
565
-
566
- get gravity() {
567
- return this.world?.gravity ?? this._gravity;
568
- }
569
-
570
- set gravity(value: Vec3) {
571
- if (this.world) {
572
- this.world.gravity = value;
573
- }
574
- else {
575
- this._gravity = value;
576
- }
577
- }
578
-
579
- clearCaches() {
580
- this._meshCache.clear();
581
- if (this.eventQueue?.raw)
582
- this.eventQueue?.free();
583
- if (this.world?.bodies)
584
- this.world?.free();
585
- }
586
-
587
- async addBoxCollider(collider: ICollider, size: Vector3) {
588
- if (!this._isInitialized)
589
- await this.initialize();
590
- if (!collider.activeAndEnabled) return;
591
-
592
- if (!this.enabled) {
593
- if (debugPhysics) console.warn("Physics are disabled");
594
- return;
595
- }
596
- const obj = collider.gameObject;
597
- const scale = getWorldScale(obj, this._tempPosition).multiply(size);
598
- scale.multiplyScalar(0.5);
599
-
600
- // prevent negative scale
601
- if (scale.x < 0) scale.x = Math.abs(scale.x);
602
- if (scale.y < 0) scale.y = Math.abs(scale.y);
603
- if (scale.z < 0) scale.z = Math.abs(scale.z);
604
-
605
- // prevent zero scale - seems normals are flipped otherwise
606
- const minSize = 0.0000001;
607
- if (scale.x < minSize) scale.x = minSize;
608
- if (scale.y < minSize) scale.y = minSize;
609
- if (scale.z < minSize) scale.z = minSize;
610
-
611
- const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.cuboid(scale.x, scale.y, scale.z);
612
- // const objectLayerMask = collider.gameObject.layers.mask;
613
- // const mask = objectLayerMask & ~2;
614
- // TODO: https://rapier.rs/docs/user_guides/javascript/colliders/#collision-groups-and-solver-groups
615
- // desc.setCollisionGroups(objectLayerMask);
616
- this.createCollider(collider, desc);
617
- }
618
-
619
- async addSphereCollider(collider: ICollider) {
620
- if (!this._isInitialized)
621
- await this.initialize();
622
- if (!collider.activeAndEnabled) return;
623
- if (!this.enabled) {
624
- if (debugPhysics) console.warn("Physics are disabled");
625
- return;
626
- }
627
- const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.ball(.5);
628
- this.createCollider(collider, desc);
629
- this.updateProperties(collider);
630
- }
631
-
632
- async addCapsuleCollider(collider: ICollider, height: number, radius: number) {
633
- if (!this._isInitialized)
634
- await this.initialize();
635
- if (!collider.activeAndEnabled) return;
636
- if (!this.enabled) {
637
- if (debugPhysics) console.warn("Physics are disabled");
638
- return;
639
- }
640
- const obj = collider.gameObject;
641
- const scale = getWorldScale(obj, this._tempPosition);
642
- // Prevent negative scales
643
- scale.x = Math.abs(scale.x);
644
- scale.y = Math.abs(scale.y);
645
- const finalRadius = radius * scale.x;
646
- // half height = distance between capsule origin and top sphere origin (not the top end of the capsule)
647
- height = Math.max(height, finalRadius * 2);
648
- const hh = Mathf.clamp((height * .5 * scale.y) - (radius * scale.x), 0, Number.MAX_SAFE_INTEGER);
649
- const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.capsule(hh, finalRadius);
650
- this.createCollider(collider, desc);
651
- }
652
-
653
- async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, extraScale?: Vector3) {
654
-
655
- // capture the geometry before waiting for phyiscs engine
656
- let geo = mesh.geometry;
657
- if (!geo) {
658
- if (debugPhysics) console.warn("Missing mesh geometry", mesh.name);
659
- return;
660
- }
661
-
662
- // check if mesh is indexed, if not generate indices
663
- if (!geo.index?.array?.length) {
664
- console.warn(`Your MeshCollider is missing vertices or indices in the assined mesh \"${mesh.name}\". Consider providing an indexed geometry.`);
665
- geo = BufferGeometryUtils.mergeVertices(geo);
666
- }
667
-
668
- let positions: Float32Array | null = null;
669
-
670
- const positionAttribute = geo.getAttribute("position") as BufferAttribute | InterleavedBufferAttribute;
671
- if (positionAttribute instanceof InterleavedBufferAttribute) {
672
- const count = positionAttribute.count;
673
- positions = new Float32Array(count * 3);
674
- for (let i = 0; i < count; i++) {
675
- const x = positionAttribute.getX(i);
676
- const y = positionAttribute.getY(i);
677
- const z = positionAttribute.getZ(i);
678
- positions[i * 3] = x;
679
- positions[i * 3 + 1] = y;
680
- positions[i * 3 + 2] = z;
681
- }
682
- }
683
- else {
684
- positions = positionAttribute.array as Float32Array;
685
- }
686
-
687
- await this.initialize();
688
-
689
- if (!this.enabled) {
690
- if (debugPhysics) console.warn("Physics are disabled");
691
- return;
692
- }
693
-
694
- if (!collider.activeAndEnabled) return;
695
-
696
-
697
- // let positions = geo.getAttribute("position").array as Float32Array;
698
- const indices = geo.index?.array as Uint32Array;
699
-
700
- const scale = collider.gameObject.worldScale.clone();
701
- if(extraScale) scale.multiply(extraScale);
702
-
703
- // scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
704
- if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
705
- const key = `${geo.uuid}_${scale.x}_${scale.y}_${scale.z}_${convex}`;
706
- if (this._meshCache.has(key)) {
707
- if (debugPhysics) console.warn("Use cached mesh collider")
708
- positions = this._meshCache.get(key)!;
709
- }
710
- else {
711
- if (debugPhysics || isDevEnvironment()) console.debug(`[Performance] Your MeshCollider \"${collider.name}\" is scaled: consider applying the scale to the collider mesh instead (${scale.x}, ${scale.y}, ${scale.z})`);
712
- const scaledPositions = new Float32Array(positions.length);
713
- for (let i = 0; i < positions.length; i += 3) {
714
- scaledPositions[i] = positions[i] * scale.x;
715
- scaledPositions[i + 1] = positions[i + 1] * scale.y;
716
- scaledPositions[i + 2] = positions[i + 2] * scale.z;
717
- }
718
- positions = scaledPositions;
719
- this._meshCache.set(key, scaledPositions);
720
- }
721
- }
722
- const desc = convex
723
- ? MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.convexHull(positions)
724
- : MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.trimesh(positions, indices);
725
- if (desc) {
726
- this.createCollider(collider, desc);
727
- // col.setMassProperties(1, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 });
728
- // rb?.setTranslation({ x: 0, y: 2, z: 0 });
729
- // col.setTranslationWrtParent(new Vector3(0,2,0));
730
-
731
- }
732
- }
733
-
734
- updatePhysicsMaterial(col: ICollider) {
735
- if (!col) return;
736
- const physicsMaterial = col.sharedMaterial;
737
- const rapier_collider = col[$bodyKey] as Collider;
738
- if (!rapier_collider) return;
739
-
740
- if (physicsMaterial) {
741
- if (physicsMaterial.bounciness !== undefined)
742
- rapier_collider.setRestitution(physicsMaterial.bounciness);
743
-
744
- if (physicsMaterial.bounceCombine !== undefined) {
745
- switch (physicsMaterial.bounceCombine) {
746
- case PhysicsMaterialCombine.Average:
747
- rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
748
- break;
749
- case PhysicsMaterialCombine.Maximum:
750
- rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
751
- break;
752
- case PhysicsMaterialCombine.Minimum:
753
- rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
754
- break;
755
- case PhysicsMaterialCombine.Multiply:
756
- rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
757
- break;
758
- }
759
- }
760
-
761
- if (physicsMaterial.dynamicFriction !== undefined)
762
- rapier_collider.setFriction(physicsMaterial.dynamicFriction);
763
-
764
- if (physicsMaterial.frictionCombine !== undefined) {
765
- switch (physicsMaterial.frictionCombine) {
766
- case PhysicsMaterialCombine.Average:
767
- rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
768
- break;
769
- case PhysicsMaterialCombine.Maximum:
770
- rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
771
- break;
772
- case PhysicsMaterialCombine.Minimum:
773
- rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
774
- break;
775
- case PhysicsMaterialCombine.Multiply:
776
- rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
777
- break;
778
- }
779
- }
780
- }
781
- }
782
-
783
- /** Get the rapier body for a Needle component */
784
- getBody(obj: ICollider | IRigidbody): null | any {
785
- if (!obj) return null;
786
- const body = obj[$bodyKey];
787
- return body;
788
- }
789
-
790
- /** Get the Needle Engine component for a rapier object */
791
- getComponent(rapierObject: object): IComponent | null {
792
- if (!rapierObject) return null;
793
- const component = rapierObject[$componentKey];
794
- return component;
795
- }
796
-
797
- private createCollider(collider: ICollider, desc: ColliderDesc) {
798
- if (!this.world) throw new Error("Physics world not initialized");
799
- const matrix = this._tempMatrix;
800
- let rigidBody: RigidBody | undefined = undefined;
801
- if (!collider.attachedRigidbody) {
802
- if (debugPhysics) console.log("Create collider without rigidbody", collider.name);
803
- matrix.makeRotationFromQuaternion(getWorldQuaternion(collider.gameObject));
804
- matrix.setPosition(getWorldPosition(collider.gameObject));
805
- }
806
- else {
807
- rigidBody = this.getRigidbody(collider, this._tempMatrix);
808
- }
809
-
810
- matrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
811
- this.tryApplyCenter(collider, this._tempPosition);
812
- desc.setTranslation(this._tempPosition.x, this._tempPosition.y, this._tempPosition.z);
813
- desc.setRotation(this._tempQuaternion);
814
- desc.setSensor(collider.isTrigger);
815
-
816
- // TODO: we might want to update this if the material changes
817
- const physicsMaterial = collider.sharedMaterial;
818
- if (physicsMaterial) {
819
-
820
- if (physicsMaterial.bounciness !== undefined)
821
- desc.setRestitution(physicsMaterial.bounciness);
822
-
823
- if (physicsMaterial.bounceCombine !== undefined) {
824
- switch (physicsMaterial.bounceCombine) {
825
- case PhysicsMaterialCombine.Average:
826
- desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
827
- break;
828
- case PhysicsMaterialCombine.Maximum:
829
- desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
830
- break;
831
- case PhysicsMaterialCombine.Minimum:
832
- desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
833
- break;
834
- case PhysicsMaterialCombine.Multiply:
835
- desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
836
- break;
837
- }
838
- }
839
-
840
- if (physicsMaterial.dynamicFriction !== undefined)
841
- desc.setFriction(physicsMaterial.dynamicFriction);
842
-
843
- if (physicsMaterial.frictionCombine !== undefined) {
844
- switch (physicsMaterial.frictionCombine) {
845
- case PhysicsMaterialCombine.Average:
846
- desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
847
- break;
848
- case PhysicsMaterialCombine.Maximum:
849
- desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
850
- break;
851
- case PhysicsMaterialCombine.Minimum:
852
- desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
853
- break;
854
- case PhysicsMaterialCombine.Multiply:
855
- desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
856
- break;
857
- }
858
- }
859
- }
860
-
861
- // if we want to use explicit mass properties, we need to set the collider density to 0
862
- // otherwise rapier will compute the mass properties based on the collider shape and density
863
- // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
864
- if (collider.attachedRigidbody?.autoMass === false) {
865
- desc.setDensity(.000001);
866
- desc.setMass(.000001);
867
- }
868
-
869
- try {
870
- const col = this.world.createCollider(desc, rigidBody);
871
- col[$componentKey] = collider;
872
- collider[$bodyKey] = col;
873
- col.setActiveEvents(MODULES.RAPIER_PHYSICS.MODULE.ActiveEvents.COLLISION_EVENTS);
874
- // We want to receive collisitons between two triggers too
875
- col.setActiveCollisionTypes(MODULES.RAPIER_PHYSICS.MODULE.ActiveCollisionTypes.ALL);
876
- this.objects.push(collider);
877
- this.bodies.push(col);
878
-
879
- // set the collider layers
880
- this.updateColliderCollisionGroups(collider);
881
-
882
- return col;
883
- }
884
- catch (e) {
885
- console.error("Error creating collider \"" + collider.name + "\"\nError:", e);
886
- return null;
887
- }
888
- }
889
-
890
- /**
891
- * Updates the collision groups of a collider.
892
- *
893
- * @param collider - The collider to update.
894
- */
895
- private updateColliderCollisionGroups(collider: ICollider) {
896
- const body = collider[$bodyKey] as Collider;
897
- const members = collider.membership;
898
- let memberMask = 0;
899
- if (members == undefined) {
900
- memberMask = 0xffff;
901
- }
902
- else {
903
- for (let i = 0; i < members.length; i++) {
904
- const member = members[i];
905
- if (member > 31) console.error(`Rapier only supports 32 layers, layer ${member} is not supported`);
906
- else memberMask |= 1 << Math.floor(member);
907
- }
908
- }
909
-
910
- const mask = collider.filter;
911
- let filterMask = 0;
912
- if (mask == undefined) {
913
- filterMask = 0xffff;
914
- }
915
- else {
916
- for (let i = 0; i < mask.length; i++) {
917
- const member = mask[i];
918
- if (member > 31) console.error(`Rapier only supports 32 layers, layer ${member} is not supported`);
919
- else filterMask |= 1 << Math.floor(member);
920
- }
921
- }
922
- body.setCollisionGroups((memberMask << 16) | filterMask);
923
- }
924
-
925
- private getRigidbody(collider: ICollider, _matrix: Matrix4): RigidBody {
926
-
927
- if (!this.world) throw new Error("Physics world not initialized");
928
- let rigidBody: RigidBody | null = null;
929
-
930
- if (collider.attachedRigidbody) {
931
- const rb = collider.attachedRigidbody;
932
- rigidBody = rb[$bodyKey];
933
- if (!rigidBody) {
934
- const kinematic = rb.isKinematic && !debugColliderPlacement;
935
- if (debugPhysics)
936
- console.log("Create rigidbody", kinematic);
937
- const rigidBodyDesc = (kinematic ? MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.kinematicPositionBased() : MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.dynamic()) as RigidBodyDesc;
938
- const pos = getWorldPosition(collider.attachedRigidbody.gameObject);
939
- rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
940
- rigidBodyDesc.setRotation(getWorldQuaternion(collider.attachedRigidbody.gameObject));
941
- rigidBodyDesc.centerOfMass = new MODULES.RAPIER_PHYSICS.MODULE.Vector3(rb.centerOfMass.x, rb.centerOfMass.y, rb.centerOfMass.z);
942
- rigidBody = this.world.createRigidBody(rigidBodyDesc);
943
- this.bodies.push(rigidBody);
944
- this.objects.push(rb);
945
- }
946
- rigidBody[$componentKey] = rb;
947
- rb[$bodyKey] = rigidBody;
948
- this.internalUpdateRigidbodyProperties(rb, rigidBody);
949
- this.getRigidbodyRelativeMatrix(collider.gameObject, rb.gameObject, _matrix);
950
- collider[$colliderRigidbody] = rigidBody;
951
- }
952
- else {
953
- const rigidBodyDesc = MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.kinematicPositionBased();
954
- const pos = getWorldPosition(collider.gameObject);
955
- rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
956
- rigidBodyDesc.setRotation(getWorldQuaternion(collider.gameObject));
957
- rigidBody = this.world.createRigidBody(rigidBodyDesc);
958
- _matrix.identity();
959
- rigidBody[$componentKey] = null;
960
- }
961
-
962
-
963
- return rigidBody;
964
- }
965
-
966
- private internal_getRigidbody(rb: IRigidbody | ICollider): RigidBody | null {
967
- if ((rb as ICollider).isCollider === true) return rb[$colliderRigidbody] as RigidBody;
968
- return rb[$bodyKey] as RigidBody;
969
- }
970
-
971
- private internalUpdateColliderProperties(col: ICollider, collider: Collider) {
972
- const shape = collider.shape;
973
- let sizeHasChanged = false;
974
- switch (shape.type) {
975
- // Sphere Collider
976
- case MODULES.RAPIER_PHYSICS.MODULE.ShapeType.Ball:
977
- {
978
- const ball = shape as Ball;
979
- const sc = col as ISphereCollider;
980
- const obj = col.gameObject;
981
- const scale = getWorldScale(obj, this._tempPosition);
982
- const radius = Math.abs(sc.radius * scale.x);
983
- sizeHasChanged = ball.radius !== radius;
984
- ball.radius = radius;
985
- if (sizeHasChanged) {
986
- collider.setShape(ball);
987
- }
988
- break;
989
- }
990
- case MODULES.RAPIER_PHYSICS.MODULE.ShapeType.Cuboid:
991
- const cuboid = shape as Cuboid;
992
- const sc = col as IBoxCollider;
993
- const obj = col.gameObject;
994
- const scale = getWorldScale(obj, this._tempPosition);
995
- const newX = Math.abs(sc.size.x * 0.5 * scale.x);
996
- const newY = Math.abs(sc.size.y * 0.5 * scale.y);
997
- const newZ = Math.abs(sc.size.z * 0.5 * scale.z);
998
- sizeHasChanged = cuboid.halfExtents.x !== newX || cuboid.halfExtents.y !== newY || cuboid.halfExtents.z !== newZ;
999
- cuboid.halfExtents.x = newX;
1000
- cuboid.halfExtents.y = newY;
1001
- cuboid.halfExtents.z = newZ;
1002
- if (sizeHasChanged) {
1003
- collider.setShape(cuboid);
1004
- }
1005
- break;
1006
- }
1007
-
1008
- if (sizeHasChanged) {
1009
- const rb = col.attachedRigidbody;
1010
- if (rb?.autoMass) {
1011
- const ph = this.getBody(rb) as RigidBody
1012
- ph?.recomputeMassPropertiesFromColliders();
1013
- }
1014
- }
1015
-
1016
- this.updateColliderCollisionGroups(col);
1017
-
1018
- if (col.isTrigger !== collider.isSensor())
1019
- collider.setSensor(col.isTrigger);
1020
- }
1021
-
1022
- private internalUpdateRigidbodyProperties(rb: IRigidbody, rigidbody: RigidBody) {
1023
- // continuous collision detection
1024
- // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
1025
- rigidbody.enableCcd(rb.collisionDetectionMode !== CollisionDetectionMode.Discrete);
1026
- rigidbody.setLinearDamping(rb.drag);
1027
- rigidbody.setAngularDamping(rb.angularDrag);
1028
- rigidbody.setGravityScale(rb.useGravity ? rb.gravityScale : 0, true);
1029
-
1030
- // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#dominance
1031
- if (rb.dominanceGroup <= 127 && rb.dominanceGroup >= -127)
1032
- rigidbody.setDominanceGroup(Math.floor(rb.dominanceGroup))
1033
- else rigidbody.setDominanceGroup(0);
1034
-
1035
- if (rb.autoMass) {
1036
- rigidbody.setAdditionalMass(0, false);
1037
- for (let i = 0; i < rigidbody.numColliders(); i++) {
1038
- const col = rigidbody.collider(i);
1039
- col.setDensity(1);
1040
- }
1041
- rigidbody.recomputeMassPropertiesFromColliders();
1042
- }
1043
- else {
1044
- rigidbody.setAdditionalMass(rb.mass, false);
1045
- for (let i = 0; i < rigidbody.numColliders(); i++) {
1046
- const col = rigidbody.collider(i);
1047
- col.setDensity(0.0000001);
1048
- }
1049
- rigidbody.recomputeMassPropertiesFromColliders();
1050
- }
1051
-
1052
- // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
1053
- // rigidbody.setAdditionalMass(rb.mass, true);
1054
- // for (let i = 0; i < rigidbody.numColliders(); i++) {
1055
- // const collider = rigidbody.collider(i);
1056
- // if (collider) {
1057
- // collider.setMass(rb.mass);
1058
- // // const density = rb.mass / collider.shape.computeMassProperties().mass;
1059
- // }
1060
- // }
1061
-
1062
- // lock rotations
1063
- rigidbody.setEnabledRotations(!rb.lockRotationX, !rb.lockRotationY, !rb.lockRotationZ, false);
1064
- rigidbody.setEnabledTranslations(!rb.lockPositionX, !rb.lockPositionY, !rb.lockPositionZ, false);
1065
-
1066
- if (rb.isKinematic) {
1067
- rigidbody.setBodyType(MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicPositionBased, false);
1068
- }
1069
- else {
1070
- rigidbody.setBodyType(MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.Dynamic, false);
1071
- }
1072
- }
1073
-
1074
- // private _lastStepTime: number | undefined = 0;
1075
- private lines?: LineSegments;
1076
-
1077
- public step(dt?: number) {
1078
- if (!this.world) return;
1079
- if (!this.enabled) return;
1080
- this._isUpdatingPhysicsWorld = true;
1081
- if (!this.eventQueue) {
1082
- this.eventQueue = new MODULES.RAPIER_PHYSICS.MODULE.EventQueue(false);
1083
- }
1084
- if (dt === undefined || dt <= 0) {
1085
- this._isUpdatingPhysicsWorld = false;
1086
- return;
1087
- }
1088
- else if (dt !== undefined) {
1089
- // if we make to sudden changes to the timestep the physics can get unstable
1090
- // https://rapier.rs/docs/user_guides/javascript/integration_parameters/#dt
1091
- this.world.timestep = Mathf.lerp(this.world.timestep, dt, 0.8);
1092
- }
1093
- try {
1094
- this.world.step(this.eventQueue);
1095
- }
1096
- catch (e) {
1097
- console.warn("Error running physics step", e);
1098
- }
1099
- this._isUpdatingPhysicsWorld = false;
1100
- }
1101
-
1102
- public postStep() {
1103
- if (!this.world) return;
1104
- if (!this.enabled) return;
1105
- this._isUpdatingPhysicsWorld = true;
1106
- this.syncObjects();
1107
- this._isUpdatingPhysicsWorld = false;
1108
-
1109
- if (this.eventQueue && !this.collisionHandler) {
1110
- this.collisionHandler = new PhysicsCollisionHandler(this.world, this.eventQueue);
1111
- }
1112
- if (this.collisionHandler) {
1113
- this.collisionHandler.handleCollisionEvents();
1114
- this.collisionHandler.update();
1115
- }
1116
- this.updateDebugRendering(this.world);
1117
- }
1118
-
1119
- private updateDebugRendering(world: World) {
1120
- if (debugPhysics || debugColliderPlacement || showColliders || this.debugRenderColliders === true) {
1121
- if (!this.lines) {
1122
- const material = new LineBasicMaterial({
1123
- color: 0x77dd77,
1124
- fog: false,
1125
- // vertexColors: VertexColors
1126
- });
1127
- const geometry = new BufferGeometry();
1128
- this.lines = new LineSegments(geometry, material);
1129
- this.lines.layers.disableAll();
1130
- this.lines.layers.enable(2);
1131
- }
1132
- if (this.lines.parent !== this.context?.scene)
1133
- this.context?.scene.add(this.lines);
1134
- const buffers = world.debugRender();
1135
- this.lines.geometry.setAttribute('position', new BufferAttribute(buffers.vertices, 3));
1136
- this.lines.geometry.setAttribute('color', new BufferAttribute(buffers.colors, 4));
1137
- // If a scene has no colliders at all at the start of the scene
1138
- // the bounding sphere radius will be 0 and the lines will not be rendered
1139
- // so we need to update the bounding sphere (perhaps it's enough to do this once...)
1140
- if (this.context!.time.frame % 30 === 0 || this.lines.geometry.boundingSphere?.radius === 0) {
1141
- this.lines.geometry.computeBoundingSphere();
1142
- }
1143
- }
1144
- else {
1145
- if (this.lines) {
1146
- this.context?.scene.remove(this.lines);
1147
- }
1148
- }
1149
- }
1150
-
1151
- /** sync rendered objects with physics world (except for colliders without rigidbody) */
1152
- private syncObjects() {
1153
- if (debugColliderPlacement) return;
1154
- for (let i = 0; i < this.bodies.length; i++) {
1155
- const obj = this.objects[i];
1156
- const body = this.bodies[i] as Collider;
1157
-
1158
- // if the collider is not attached to a rigidbody
1159
- // it means that its kinematic so we need to update its position
1160
- const col = (obj as ICollider);
1161
- if (col?.isCollider === true && !col.attachedRigidbody) {
1162
- const rigidbody = body.parent();
1163
- if (rigidbody)
1164
- this.syncPhysicsBody(obj.gameObject, rigidbody, true, true);
1165
- else
1166
- this.syncPhysicsBody(obj.gameObject, body, true, true);
1167
- continue;
1168
- }
1169
-
1170
-
1171
- // sync
1172
- const pos = body.translation();
1173
- const rot = body.rotation();
1174
- if (Number.isNaN(pos.x) || Number.isNaN(rot.x)) {
1175
- if (!col["__COLLIDER_NAN"] && isDevEnvironment()) {
1176
- console.warn("Collider has NaN values", col.name, col.gameObject, body);
1177
- col["__COLLIDER_NAN"] = true;
1178
- }
1179
- continue;
1180
- }
1181
-
1182
- // make sure to keep the collider offset
1183
- const center = obj["center"] as Vector3;
1184
- if (center && center.isVector3) {
1185
- this._tempQuaternion.set(rot.x, rot.y, rot.z, rot.w);
1186
- const offset = this._tempPosition.copy(center).applyQuaternion(this._tempQuaternion);
1187
- const scale = getWorldScale(obj.gameObject);
1188
- offset.multiply(scale);
1189
- pos.x -= offset.x;
1190
- pos.y -= offset.y;
1191
- pos.z -= offset.z;
1192
- }
1193
- setWorldPositionXYZ(obj.gameObject, pos.x, pos.y, pos.z);
1194
- setWorldQuaternionXYZW(obj.gameObject, rot.x, rot.y, rot.z, rot.w);
1195
- }
1196
- }
1197
-
1198
- private syncPhysicsBody(obj: Object3D, body: RigidBody | Collider, translation: boolean, rotation: boolean) {
1199
-
1200
- // const bodyType = body.bodyType();
1201
- // const previous = physicsBody.translation();
1202
- // const vel = physicsBody.linvel();
1203
-
1204
- if (body instanceof MODULES.RAPIER_PHYSICS.MODULE.RigidBody) {
1205
- const worldPosition = getWorldPosition(obj, this._tempPosition);
1206
- const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
1207
- const type = body.bodyType();
1208
- switch (type) {
1209
- case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.Fixed:
1210
- case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicPositionBased:
1211
- case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicVelocityBased:
1212
- if (translation)
1213
- body.setNextKinematicTranslation(worldPosition);
1214
- if (rotation)
1215
- body.setNextKinematicRotation(worldQuaternion);
1216
- break;
1217
- default:
1218
- if (translation)
1219
- body.setTranslation(worldPosition, false);
1220
- if (rotation)
1221
- body.setRotation(worldQuaternion, false);
1222
- break;
1223
-
1224
- }
1225
- }
1226
- else if (body instanceof MODULES.RAPIER_PHYSICS.MODULE.Collider) {
1227
- if (obj.matrixWorldNeedsUpdate) {
1228
- obj.updateWorldMatrix(true, false);
1229
- }
1230
- obj.matrixWorld.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1231
- const wp = this._tempPosition;
1232
- const wq = this._tempQuaternion;
1233
- // const wp = getWorldPosition(obj, this._tempPosition);
1234
- // const wq = getWorldQuaternion(obj, this._tempQuaternion);
1235
- const collider = body[$componentKey] as ICollider;
1236
- this.tryApplyCenter(collider, wp);
1237
-
1238
- // we need to check if translation or rotation have changed, otherwise the physics engine will wakeup rigidbody that are in contact with this collider
1239
- if (translation) {
1240
- const ct = body.translation();
1241
- if (ct.x !== wp.x || ct.y !== wp.y || ct.z !== wp.z)
1242
- body.setTranslation(wp);
1243
- }
1244
- if (rotation) {
1245
- const cr = body.rotation();
1246
- if (cr.x !== wq.x || cr.y !== wq.y || cr.z !== wq.z || cr.w !== wq.w)
1247
- body.setRotation(wq);
1248
- }
1249
- }
1250
-
1251
- // physicsBody.setBodyType(RAPIER.RigidBodyType.Fixed);
1252
- // physicsBody.setLinvel(vel, false);
1253
-
1254
- // update velocity
1255
- // const pos = physicsBody.translation();
1256
- // pos.x -= previous.x;
1257
- // pos.y -= previous.y;
1258
- // pos.z -= previous.z;
1259
- // // threhold
1260
- // const t = 1;
1261
- // const canUpdateVelocity = Math.abs(pos.x) < t && Math.abs(pos.y) < t && Math.abs(pos.z) < t;
1262
- // if (canUpdateVelocity) {
1263
- // const damping = 1 + this.context.time.deltaTime;
1264
- // vel.x *= damping;
1265
- // vel.y *= damping;
1266
- // vel.z *= damping;
1267
- // vel.x += pos.x;
1268
- // vel.y += pos.y;
1269
- // vel.z += pos.z;
1270
- // console.log(vel);
1271
- // physicsBody.setLinvel(vel, true);
1272
- // }
1273
- // else if(debugPhysics) console.warn("Movement exceeded threshold, not updating velocity", pos);
1274
-
1275
- // body.setBodyType(bodyType);
1276
- }
1277
-
1278
- private readonly _tempCenterPos: Vector3 = new Vector3();
1279
- private readonly _tempCenterVec: Vector3 = new Vector3();
1280
- private readonly _tempCenterQuaternion: Quaternion = new Quaternion();
1281
- private tryApplyCenter(collider: ICollider, targetVector: Vector3) {
1282
- const center = collider.center;
1283
- if (center && collider.gameObject) {
1284
- if (center.x !== 0 || center.y !== 0 || center.z !== 0) {
1285
- // TODO: fix export of center in editor integrations so we dont have to flip here
1286
- this._tempCenterPos.x = center.x;
1287
- this._tempCenterPos.y = center.y;
1288
- this._tempCenterPos.z = center.z;
1289
- getWorldScale(collider.gameObject, this._tempCenterVec);
1290
- this._tempCenterPos.multiply(this._tempCenterVec);
1291
- if (!collider.attachedRigidbody) {
1292
- getWorldQuaternion(collider.gameObject, this._tempCenterQuaternion);
1293
- this._tempCenterPos.applyQuaternion(this._tempCenterQuaternion);
1294
- }
1295
- else {
1296
- this._tempCenterPos.applyQuaternion(collider.gameObject.quaternion);
1297
- }
1298
- targetVector.x += this._tempCenterPos.x;
1299
- targetVector.y += this._tempCenterPos.y;
1300
- targetVector.z += this._tempCenterPos.z;
1301
- }
1302
- }
1303
- }
1304
-
1305
- private static _matricesBuffer: Matrix4[] = [];
1306
- private getRigidbodyRelativeMatrix(comp: Object3D, rigidbody: Object3D, mat: Matrix4, matrices?: Matrix4[]): Matrix4 {
1307
- // collect all matrices to the rigidbody and then build the rigidbody relative matrix
1308
- if (matrices === undefined) {
1309
- matrices = RapierPhysics._matricesBuffer;
1310
- matrices.length = 0;
1311
- }
1312
- if (comp === rigidbody) {
1313
- const scale = getWorldScale(comp, this._tempPosition);
1314
- mat.makeScale(scale.x, scale.y, scale.z);
1315
- for (let i = matrices.length - 1; i >= 0; i--) {
1316
- mat.multiply(matrices[i]);
1317
- }
1318
- return mat;
1319
- }
1320
- matrices.push(comp.matrix);
1321
- if (comp.parent) {
1322
- this.getRigidbodyRelativeMatrix(comp.parent, rigidbody, mat, matrices);
1323
- }
1324
- return mat;
1325
- }
1326
-
1327
- private static centerConnectionPos = { x: 0, y: 0, z: 0 };
1328
- private static centerConnectionRot = { x: 0, y: 0, z: 0, w: 1 };
1329
-
1330
-
1331
-
1332
- addFixedJoint(body1: IRigidbody, body2: IRigidbody) {
1333
- if (!this.world) {
1334
- console.error("Physics world not initialized");
1335
- return;
1336
- }
1337
- const b1 = body1[$bodyKey] as RigidBody;
1338
- const b2 = body2[$bodyKey] as RigidBody;
1339
-
1340
- this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
1341
- this._tempMatrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1342
-
1343
- const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.fixed(
1344
- RapierPhysics.centerConnectionPos, RapierPhysics.centerConnectionRot,
1345
- this._tempPosition, this._tempQuaternion,
1346
- );
1347
- const joint = this.world.createImpulseJoint(params, b1, b2, true);
1348
- if (debugPhysics)
1349
- console.log("ADD FIXED JOINT", joint)
1350
- }
1351
-
1352
-
1353
- /** The joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc. They are characterized by one local anchor as well as one local axis on each rigid-body. */
1354
- addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: { x: number, y: number, z: number }, axis: { x: number, y: number, z: number }) {
1355
- if (!this.world) {
1356
- console.error("Physics world not initialized");
1357
- return;
1358
- }
1359
- const b1 = body1[$bodyKey] as RigidBody;
1360
- const b2 = body2[$bodyKey] as RigidBody;
1361
-
1362
- this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
1363
- this._tempMatrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1364
-
1365
- const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.revolute(anchor, this._tempPosition, axis);
1366
- const joint = this.world.createImpulseJoint(params, b1, b2, true);
1367
- if (debugPhysics)
1368
- console.log("ADD HINGE JOINT", joint)
1369
- }
1370
-
1371
-
1372
- private calculateJointRelativeMatrices(body1: IGameObject, body2: IGameObject, mat: Matrix4) {
1373
- body1.updateWorldMatrix(true, false);
1374
- body2.updateWorldMatrix(true, false);
1375
- const world1 = body1.matrixWorld;
1376
- const world2 = body2.matrixWorld;
1377
- // set scale to 1
1378
- world1.elements[0] = 1;
1379
- world1.elements[5] = 1;
1380
- world1.elements[10] = 1;
1381
- world2.elements[0] = 1;
1382
- world2.elements[5] = 1;
1383
- world2.elements[10] = 1;
1384
- mat.copy(world2).premultiply(world1.invert()).invert();
1385
- }
1386
- }
1387
-
1388
-
1389
-
1390
- /** responsible of processing collision events for the component system */
1391
- class PhysicsCollisionHandler {
1392
-
1393
- readonly world: World;
1394
- readonly eventQueue: EventQueue;
1395
-
1396
- constructor(world: World, eventQueue: EventQueue) {
1397
- this.world = world;
1398
- this.eventQueue = eventQueue;
1399
- }
1400
-
1401
- private activeCollisions: Array<{ collider: ICollider, component: IComponent, collision: Collision }> = [];
1402
- private activeCollisionsStay: Array<{ collider: ICollider, component: IComponent, collision: Collision }> = [];
1403
- private activeTriggers: Array<{ collider: ICollider, component: IComponent, otherCollider: ICollider }> = [];
1404
-
1405
- handleCollisionEvents() {
1406
- if (!this.eventQueue) return;
1407
- if (!this.world) return;
1408
- this.eventQueue.drainCollisionEvents((handle1, handle2, started) => {
1409
- const col1 = this.world!.getCollider(handle1);
1410
- const col2 = this.world!.getCollider(handle2);
1411
- if (!col1 || !col2) return;
1412
- const colliderComponent1 = col1[$componentKey];
1413
- const colliderComponent2 = col2[$componentKey];
1414
- if (debugCollisions)
1415
- console.log("EVT", colliderComponent1.name, colliderComponent2.name, started, col1, col2);
1416
- if (colliderComponent1 && colliderComponent2) {
1417
- if (started) {
1418
- this.onCollisionStarted(colliderComponent1, col1, colliderComponent2, col2);
1419
- this.onCollisionStarted(colliderComponent2, col2, colliderComponent1, col1);
1420
- }
1421
- else {
1422
- this.onCollisionEnded(colliderComponent1, colliderComponent2);
1423
- this.onCollisionEnded(colliderComponent2, colliderComponent1);
1424
- }
1425
- }
1426
- });
1427
- }
1428
-
1429
- update() {
1430
- this.onHandleCollisionStay();
1431
- }
1432
-
1433
- private onCollisionStarted(self: ICollider, selfBody: Collider, other: ICollider, otherBody: Collider) {
1434
- let collision: Collision | null = null;
1435
-
1436
- // if one is a trigger we dont get collisions but want to raise the trigger events
1437
- if (self.isTrigger || other.isTrigger) {
1438
- foreachComponent(self.gameObject, (c: IComponent) => {
1439
- if (c.onTriggerEnter && !c.destroyed) {
1440
- c.onTriggerEnter(other);
1441
- }
1442
- this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
1443
- });
1444
- }
1445
- else {
1446
- const object = self.gameObject;
1447
- // TODO: we dont respect the flip value here!
1448
- this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
1449
- foreachComponent(object, (c: IComponent) => {
1450
- if (c.destroyed) return;
1451
- const hasDeclaredEventMethod = c.onCollisionEnter || c.onCollisionStay || c.onCollisionExit;
1452
- if (hasDeclaredEventMethod || debugCollisions) {
1453
- if (!collision) {
1454
- const contacts: Array<ContactPoint> = [];
1455
- const normal = manifold.normal();
1456
- // invert the normal for convex MeshColliders, NE-2680
1457
- if (other instanceof MeshCollider && other.convex) {
1458
- normal.x = -normal.x;
1459
- normal.y = -normal.y;
1460
- normal.z = -normal.z;
1461
- }
1462
- for (let i = 0; i < manifold.numSolverContacts(); i++) {
1463
- // solver points are in world space
1464
- // https://rapier.rs/docs/user_guides/javascript/advanced_collision_detection_js#the-contact-graph
1465
- const pt = manifold.solverContactPoint(i);
1466
- const impulse = manifold.contactImpulse(i);
1467
- if (pt) {
1468
- const dist = manifold.contactDist(i);
1469
- const friction = manifold.solverContactFriction(i);
1470
- const tangentVelocity = manifold.solverContactTangentVelocity(i);
1471
- const contact = new ContactPoint(pt, dist, normal, impulse, friction, tangentVelocity);
1472
- contacts.push(contact);
1473
- if (debugCollisions) {
1474
- Gizmos.DrawDirection(pt, normal, 0xff0000, 3, true);
1475
- }
1476
- }
1477
- }
1478
- collision = new Collision(object, other, contacts);
1479
- }
1480
-
1481
- // we only need to keep track if any event exists
1482
- if (hasDeclaredEventMethod) {
1483
- const info = { collider: self, component: c, collision };
1484
-
1485
- this.activeCollisions.push(info);
1486
- if (c.onCollisionStay) {
1487
- this.activeCollisionsStay.push(info);
1488
- }
1489
-
1490
- c.onCollisionEnter?.call(c, collision);
1491
- }
1492
-
1493
- }
1494
- });
1495
- });
1496
- }
1497
- }
1498
-
1499
- private onHandleCollisionStay() {
1500
- for (const active of this.activeCollisionsStay) {
1501
- const c = active.component;
1502
- if (c.destroyed) continue;
1503
- if (c.activeAndEnabled && c.onCollisionStay) {
1504
- if (active.collision.collider.destroyed) continue;
1505
- const arg = active.collision;
1506
- c.onCollisionStay(arg);
1507
- }
1508
- }
1509
- for (const active of this.activeTriggers) {
1510
- const c = active.component;
1511
- if (c.destroyed) continue;
1512
- if (c.activeAndEnabled && c.onTriggerStay) {
1513
- const arg = active.otherCollider;
1514
- if (arg.destroyed) continue;
1515
- c.onTriggerStay(arg);
1516
- }
1517
- }
1518
- }
1519
-
1520
- private onCollisionEnded(self: ICollider, other: ICollider) {
1521
- if (self.destroyed || other.destroyed) return;
1522
- for (let i = 0; i < this.activeCollisions.length; i++) {
1523
- const active = this.activeCollisions[i];
1524
- const collider = active.collider;
1525
- if (collider.destroyed || active.collision.collider.destroyed) {
1526
- this.activeCollisions.splice(i, 1);
1527
- i--;
1528
- continue;
1529
- }
1530
- if (collider === self && active.collision.collider === other) {
1531
- const c = active.component;
1532
- this.activeCollisions.splice(i, 1);
1533
- i--;
1534
- if (c.activeAndEnabled && c.onCollisionExit) {
1535
- const collision = active.collision;
1536
- c.onCollisionExit(collision);
1537
- }
1538
- }
1539
- }
1540
- for (let i = 0; i < this.activeCollisionsStay.length; i++) {
1541
- const active = this.activeCollisionsStay[i];
1542
- const collider = active.collider;
1543
- if (collider.destroyed || active.collision.collider.destroyed) {
1544
- this.activeCollisionsStay.splice(i, 1);
1545
- i--;
1546
- continue;
1547
- }
1548
- if (collider === self && active.collision.collider === other) {
1549
- const c = active.component;
1550
- this.activeCollisionsStay.splice(i, 1);
1551
- i--;
1552
- if (c.activeAndEnabled && c.onCollisionExit) {
1553
- const collision = active.collision;
1554
- c.onCollisionExit(collision);
1555
- }
1556
- }
1557
- }
1558
- for (let i = 0; i < this.activeTriggers.length; i++) {
1559
- const active = this.activeTriggers[i];
1560
- const collider = active.collider;
1561
- if (collider.destroyed || active.otherCollider.destroyed) {
1562
- this.activeTriggers.splice(i, 1);
1563
- i--;
1564
- continue;
1565
- }
1566
- if (collider === self && active.otherCollider === other) {
1567
- const c = active.component;
1568
- this.activeTriggers.splice(i, 1);
1569
- i--;
1570
- if (c.activeAndEnabled && c.onTriggerExit) {
1571
- const collision = active.otherCollider;
1572
- c.onTriggerExit(collision);
1573
- }
1574
- }
1575
- }
1576
- }
1577
- }
1
+ import type { Ball, Collider, ColliderDesc, Cuboid, EventQueue, QueryFilterFlags, Ray, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat';
2
+ import { BufferAttribute, BufferGeometry, InterleavedBufferAttribute, LineBasicMaterial, LineSegments, Matrix4, Mesh, Object3D, Quaternion, Vector3 } from 'three'
3
+ import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
4
+
5
+ import { CollisionDetectionMode, PhysicsMaterialCombine } from '../engine/engine_physics.types.js';
6
+ import { MeshCollider } from '../engine-components/Collider.js';
7
+ import { isDevEnvironment } from './debug/debug.js';
8
+ import { ContextEvent, ContextRegistry } from './engine_context_registry.js';
9
+ import { foreachComponent } from './engine_gameobject.js';
10
+ import { Gizmos } from './engine_gizmos.js';
11
+ import { Mathf } from './engine_math.js';
12
+ import { MODULES } from './engine_modules.js';
13
+ import { getWorldPosition, getWorldQuaternion, getWorldScale, setWorldPositionXYZ, setWorldQuaternionXYZW } from "./engine_three_utils.js"
14
+ import type {
15
+ IBoxCollider,
16
+ ICollider,
17
+ IComponent,
18
+ IContext,
19
+ IGameObject,
20
+ IPhysicsEngine,
21
+ IRigidbody,
22
+ ISphereCollider,
23
+ Vec2,
24
+ Vec3,
25
+ } from './engine_types.js';
26
+ import { Collision, ContactPoint } from './engine_types.js';
27
+ import { SphereOverlapResult } from './engine_types.js';
28
+ import { CircularBuffer, getParam } from "./engine_utils.js"
29
+
30
+ const debugPhysics = getParam("debugphysics");
31
+ const debugColliderPlacement = getParam("debugcolliderplacement");
32
+ const debugCollisions = getParam("debugcollisions");
33
+ const showColliders = getParam("showcolliders");
34
+ const showPhysicsRaycasts = getParam("debugraycasts");
35
+
36
+
37
+ /** on physics body and references the needle component */
38
+ const $componentKey = Symbol("needle component");
39
+ /** on needle component and references physics body */
40
+ const $bodyKey = Symbol("physics body");
41
+ const $colliderRigidbody = Symbol("rigidbody");
42
+
43
+
44
+ declare const NEEDLE_USE_RAPIER: boolean;
45
+ globalThis["NEEDLE_USE_RAPIER"] = globalThis["NEEDLE_USE_RAPIER"] !== undefined ? globalThis["NEEDLE_USE_RAPIER"] : true;
46
+ if (debugPhysics)
47
+ console.log("Use Rapier", NEEDLE_USE_RAPIER, globalThis["NEEDLE_USE_RAPIER"])
48
+
49
+ if (NEEDLE_USE_RAPIER) {
50
+ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, evt => {
51
+ if (debugPhysics)
52
+ console.log("Register rapier physics backend")
53
+ evt.context.physics.engine = new RapierPhysics(evt.context);
54
+ // We do not initialize physics immediately to avoid loading the physics engine if it is not needed
55
+ });
56
+ }
57
+
58
+
59
+ declare type PhysicsBody = {
60
+ translation(): { x: number, y: number, z: number }
61
+ rotation(): { x: number, y: number, z: number, w: number }
62
+ }
63
+
64
+ export class RapierPhysics implements IPhysicsEngine {
65
+
66
+ debugRenderColliders: boolean = false;
67
+ debugRenderRaycasts: boolean = false;
68
+
69
+ removeBody(obj: IComponent) {
70
+ if (!obj) return;
71
+ this.validate();
72
+ const body = obj[$bodyKey];
73
+ obj[$bodyKey] = null;
74
+ if (body && this.world) {
75
+ const index = this.objects.findIndex(o => o === obj);
76
+ if (index >= 0) {
77
+ const rapierBody = this.bodies[index];
78
+ // Remove references
79
+ this.bodies.splice(index, 1);
80
+ this.objects.splice(index, 1);
81
+
82
+
83
+ // Remove the collider from the physics world
84
+ if (rapierBody instanceof MODULES.RAPIER_PHYSICS.MODULE.Collider) {
85
+ const rapierCollider = rapierBody as Collider;
86
+ this.world?.removeCollider(rapierCollider, true);
87
+
88
+ // also remove the rigidbody if it doesnt have colliders anymore
89
+ const rapierRigidbody: RigidBody | null = rapierCollider.parent();
90
+ if (rapierRigidbody && rapierRigidbody.numColliders() <= 0) {
91
+ const rigidbody = rapierRigidbody[$componentKey] as IRigidbody;
92
+ if (rigidbody) {
93
+ // If the collider was attached to a rigidbody and this rigidbody now has no colliders anymore we should ignore it - because the Rigidbody component will delete itself
94
+ }
95
+ else {
96
+ // But if there is no explicit rigidbody needle component then the colliders did create it implictly and thus we need to remove it here:
97
+ this.world?.removeRigidBody(rapierRigidbody);
98
+ }
99
+ }
100
+ }
101
+ // Remove the rigidbody from the physics world
102
+ else if (rapierBody instanceof MODULES.RAPIER_PHYSICS.MODULE.RigidBody) {
103
+ if (rapierBody.numColliders() <= 0) {
104
+ this.world?.removeRigidBody(rapierBody);
105
+ }
106
+ else {
107
+ if (isDevEnvironment()) {
108
+ if (!rapierBody["did_log_removing"]) {
109
+ setTimeout(() => {
110
+ if (rapierBody.numColliders() > 0) {
111
+ rapierBody["did_log_removing"] = true;
112
+ console.warn("RapierPhysics: removing rigidbody with colliders from the physics world is not possible right now, please remove the colliders first");
113
+ }
114
+ }, 1);
115
+
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean) {
125
+ this.validate();
126
+ if (!this.enabled) return;
127
+ if (comp.destroyed || !comp.gameObject) return;
128
+ if (!translation && !rotation) return;
129
+
130
+ if ((comp as ICollider).isCollider === true) {
131
+ // const collider = comp as ICollider;
132
+ console.warn("TODO: implement updating collider position");
133
+ }
134
+ else {
135
+ const rigidbody = comp as IRigidbody;
136
+ const body = rigidbody[$bodyKey];
137
+ if (body) {
138
+ this.syncPhysicsBody(rigidbody.gameObject, body, translation, rotation);
139
+ }
140
+ }
141
+ }
142
+
143
+ updateProperties(obj: IRigidbody | ICollider) {
144
+ this.validate();
145
+
146
+ if ((obj as ICollider).isCollider) {
147
+ const col = obj as ICollider;
148
+ const body = col[$bodyKey];
149
+ if (body) {
150
+ this.internalUpdateColliderProperties(col, body);
151
+ if (col.sharedMaterial)
152
+ this.updatePhysicsMaterial(col);
153
+ }
154
+ }
155
+ else {
156
+ const rb = obj as IRigidbody;
157
+ const physicsBody = this.internal_getRigidbody(rb);
158
+ if (physicsBody) {
159
+ this.internalUpdateRigidbodyProperties(rb, physicsBody);
160
+ }
161
+ }
162
+ }
163
+ addForce(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
164
+ this.validate();
165
+ const body = this.internal_getRigidbody(rigidbody);
166
+ if (body) body.addForce(force, wakeup)
167
+ else console.warn("Rigidbody doesn't exist: can not apply force (does your object with the Rigidbody have a collider?)");
168
+ }
169
+ addImpulse(rigidbody: IRigidbody, force: Vec3, wakeup: boolean) {
170
+ this.validate();
171
+ const body = this.internal_getRigidbody(rigidbody);
172
+ if (body) body.applyImpulse(force, wakeup);
173
+ else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
174
+ }
175
+ getLinearVelocity(comp: IRigidbody | ICollider): Vec3 | null {
176
+ this.validate();
177
+ const body = this.internal_getRigidbody(comp);
178
+ if (body) {
179
+ const vel = body.linvel();
180
+ return vel;
181
+ }
182
+ // else console.warn("Rigidbody doesn't exist: can not get linear velocity (does your object with the Rigidbody have a collider?)");
183
+ return null;
184
+ }
185
+ getAngularVelocity(rb: IRigidbody): Vec3 | null {
186
+ this.validate();
187
+ const body = this.internal_getRigidbody(rb);
188
+ if (body) {
189
+ const vel = body.angvel();
190
+ return vel;
191
+ }
192
+ // else console.warn("Rigidbody doesn't exist: can not get angular velocity (does your object with the Rigidbody have a collider?)");
193
+ return null;
194
+ }
195
+ resetForces(rb: IRigidbody, wakeup: boolean) {
196
+ this.validate();
197
+ const body = this.internal_getRigidbody(rb);
198
+ body?.resetForces(wakeup);
199
+ }
200
+ resetTorques(rb: IRigidbody, wakeup: boolean) {
201
+ this.validate();
202
+ const body = this.internal_getRigidbody(rb);
203
+ body?.resetTorques(wakeup);
204
+ }
205
+ applyImpulse(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
206
+ this.validate();
207
+ const body = this.internal_getRigidbody(rb);
208
+ if (body) body.applyImpulse(vec, wakeup);
209
+ else console.warn("Rigidbody doesn't exist: can not apply impulse (does your object with the Rigidbody have a collider?)");
210
+ }
211
+
212
+ wakeup(rb: IRigidbody) {
213
+ this.validate();
214
+ const body = this.internal_getRigidbody(rb);
215
+ if (body) body.wakeUp();
216
+ else console.warn("Rigidbody doesn't exist: can not wake up (does your object with the Rigidbody have a collider?)");
217
+ }
218
+ isSleeping(rb: IRigidbody) {
219
+ this.validate();
220
+ const body = this.internal_getRigidbody(rb);
221
+ return body?.isSleeping();
222
+ }
223
+ setAngularVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
224
+ this.validate();
225
+ const body = this.internal_getRigidbody(rb);
226
+ if (body) body.setAngvel(vec, wakeup);
227
+ else console.warn("Rigidbody doesn't exist: can not set angular velocity (does your object with the Rigidbody have a collider?)");
228
+ }
229
+ setLinearVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean) {
230
+ this.validate();
231
+ const body = this.internal_getRigidbody(rb);
232
+ if (body) body.setLinvel(vec, wakeup);
233
+ else console.warn("Rigidbody doesn't exist: can not set linear velocity (does your object with the Rigidbody have a collider?)");
234
+ }
235
+
236
+ private readonly context?: IContext;
237
+ private _initializePromise?: Promise<boolean>;
238
+ private _isInitialized: boolean = false;
239
+
240
+ constructor(ctx: IContext) {
241
+ this.context = ctx;
242
+ }
243
+
244
+ get isInitialized() { return this._isInitialized; }
245
+
246
+ async initialize() {
247
+ if (!this._initializePromise)
248
+ this._initializePromise = this.internalInitialization();
249
+ return this._initializePromise;
250
+ }
251
+
252
+ private async internalInitialization() {
253
+ if (getParam("__nophysics")) {
254
+ console.warn("Physics are disabled");
255
+ return false;
256
+ }
257
+ if (debugPhysics) console.log("Initialize rapier physics engine");
258
+ // NEEDLE_PHYSICS_INIT_START
259
+ // use .env file with VITE_NEEDLE_USE_RAPIER=false to treeshake rapier
260
+ // @ts-ignore
261
+ if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_RAPIER === "false") {
262
+ if (debugPhysics) console.log("Rapier disabled");
263
+ return false;
264
+ }
265
+ // Can be transformed during build time to disable rapier
266
+ if (!NEEDLE_USE_RAPIER) return false;
267
+ if (this._hasCreatedWorld) {
268
+ console.error("Invalid call to create physics world: world is already created");
269
+ return true;
270
+ }
271
+ this._hasCreatedWorld = true;
272
+ if (MODULES.RAPIER_PHYSICS.MAYBEMODULE == undefined) {
273
+ if (debugPhysics) console.trace("Loading rapier physics engine");
274
+ const module = await MODULES.RAPIER_PHYSICS.load();
275
+ await module.init();
276
+ }
277
+ if (debugPhysics) console.log("Physics engine initialized, creating world...");
278
+ this._world = new MODULES.RAPIER_PHYSICS.MODULE.World(this._gravity);
279
+ this.rapierRay = new MODULES.RAPIER_PHYSICS.MODULE.Ray({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 });
280
+ this.enabled = true;
281
+ this._isInitialized = true;
282
+ if (debugPhysics) console.log("Physics world created");
283
+ return true;
284
+ // NEEDLE_PHYSICS_INIT_END
285
+ }
286
+
287
+ /** Check is the physics engine has been initialized and the call can be made */
288
+ private validate() {
289
+ if (!this._isInitialized) {
290
+ if (debugPhysics) {
291
+ this["_lastWarnTime"] = this["_lastWarnTime"] ?? 0;
292
+ if (Date.now() - this["_lastWarnTime"] > 1000) {
293
+ this["_lastWarnTime"] = Date.now();
294
+ console.warn("Physics engine is not initialized");
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+
301
+ private rapierRay!: Ray;
302
+ private raycastVectorsBuffer = new CircularBuffer(() => new Vector3(), 10);
303
+
304
+ public raycast(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
305
+ maxDistance?: number,
306
+ /** True if you want to also hit objects when the raycast starts from inside a collider */
307
+ solid?: boolean,
308
+ queryFilterFlags?: QueryFilterFlags,
309
+ filterGroups?: number,
310
+ /** Return false to ignore this collider */
311
+ filterPredicate?: (c: ICollider) => boolean,
312
+ /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
313
+ * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
314
+ * @default undefined
315
+ */
316
+ useIgnoreRaycastLayer?: boolean
317
+ })
318
+ : null | { point: Vector3, collider: ICollider } {
319
+
320
+ if (!this._isInitialized) {
321
+ console.log("Physics engine is not initialized");
322
+ return null;
323
+ }
324
+
325
+ let maxDistance = options?.maxDistance;
326
+ let solid = options?.solid;
327
+
328
+ if (maxDistance === undefined) maxDistance = Infinity;
329
+ if (solid === undefined) solid = true;
330
+
331
+ const ray = this.getPhysicsRay(this.rapierRay, origin, direction);
332
+ if (!ray) return null;
333
+
334
+ if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawRay(ray.origin, ray.dir, 0x0000ff, 1);
335
+
336
+ const hit = this.world?.castRay(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
337
+ const component = c[$componentKey];
338
+ if (options?.filterPredicate) return options.filterPredicate(component);
339
+ if (options?.useIgnoreRaycastLayer !== false) {
340
+ // ignore objects in the IgnoreRaycast=2 layer
341
+ return !component?.gameObject.layers.isEnabled(2);
342
+ }
343
+ return true;
344
+ });
345
+ if (hit) {
346
+ const point = ray.pointAt(hit.timeOfImpact);
347
+ const vec = this.raycastVectorsBuffer.get();
348
+ vec.set(point.x, point.y, point.z);
349
+ return { point: vec, collider: hit.collider[$componentKey] };
350
+ }
351
+
352
+ return null;
353
+ }
354
+
355
+ public raycastAndGetNormal(origin?: Vec2 | Vec3, direction?: Vec3, options?: {
356
+ maxDistance?: number,
357
+ /** True if you want to also hit objects when the raycast starts from inside a collider */
358
+ solid?: boolean,
359
+ queryFilterFlags?: QueryFilterFlags,
360
+ filterGroups?: number,
361
+ /** Return false to ignore this collider */
362
+ filterPredicate?: (c: ICollider) => boolean,
363
+ /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
364
+ * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
365
+ * @default undefined
366
+ */
367
+ useIgnoreRaycastLayer?: boolean
368
+ })
369
+ : null | { point: Vector3, normal: Vector3, collider: ICollider } {
370
+
371
+ if (!this._isInitialized) {
372
+ return null;
373
+ }
374
+
375
+ let maxDistance = options?.maxDistance;
376
+ let solid = options?.solid;
377
+
378
+ if (maxDistance === undefined) maxDistance = Infinity;
379
+ if (solid === undefined) solid = true;
380
+
381
+ const ray = this.getPhysicsRay(this.rapierRay, origin, direction);
382
+ if (!ray) return null;
383
+
384
+ if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawRay(ray.origin, ray.dir, 0x0000ff, 1);
385
+
386
+ const hit = this.world?.castRayAndGetNormal(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
387
+ const component = c[$componentKey];
388
+ if (options?.filterPredicate) return options.filterPredicate(component);
389
+ if (options?.useIgnoreRaycastLayer !== false) {
390
+ // ignore objects in the IgnoreRaycast=2 layer
391
+ return !component?.gameObject.layers.isEnabled(2);
392
+ }
393
+ return true;
394
+ });
395
+ if (hit) {
396
+ const point = ray.pointAt(hit.timeOfImpact);
397
+ const normal = hit.normal;
398
+ const vec = this.raycastVectorsBuffer.get();
399
+ const nor = this.raycastVectorsBuffer.get();
400
+ vec.set(point.x, point.y, point.z);
401
+ nor.set(normal.x, normal.y, normal.z);
402
+ return { point: vec, normal: nor, collider: hit.collider[$componentKey] };
403
+ }
404
+ return null;
405
+ }
406
+
407
+ private getPhysicsRay(ray: Ray, origin?: Vec2 | Vec3, direction?: Vec3): Ray | null {
408
+ const cam = this.context?.mainCamera;
409
+ if (origin === undefined) {
410
+ const pos = this.context?.input.getPointerPosition(0);
411
+ if (pos) origin = pos;
412
+ else return null;
413
+ }
414
+ // if we get origin in 2d space we need to project it to 3d space
415
+ if (origin["z"] === undefined) {
416
+ if (!cam) {
417
+ console.error("Can not perform raycast from 2d point - no main camera found");
418
+ return null;
419
+ }
420
+ const vec3 = this.raycastVectorsBuffer.get();
421
+ vec3.x = origin.x;
422
+ vec3.y = origin.y;
423
+ vec3.z = 0;
424
+ // if the origin is in screen space we need to convert it to raycaster space
425
+ if (vec3.x > 1 || vec3.y > 1 || vec3.y < -1 || vec3.x < -1) {
426
+ if (debugPhysics) console.warn("Converting screenspace to raycast space", vec3)
427
+ this.context?.input.convertScreenspaceToRaycastSpace(vec3);
428
+ }
429
+ vec3.unproject(cam);
430
+ origin = vec3;
431
+ }
432
+
433
+ const o = origin as Vec3;
434
+
435
+ ray.origin.x = o.x;
436
+ ray.origin.y = o.y;
437
+ ray.origin.z = o.z;
438
+ const vec = this.raycastVectorsBuffer.get();
439
+ if (direction)
440
+ vec.set(direction.x, direction.y, direction.z);
441
+ else {
442
+ if (!cam) {
443
+ console.error("Can not perform raycast - no camera found");
444
+ return null;
445
+ }
446
+ vec.set(ray.origin.x, ray.origin.y, ray.origin.z);
447
+ const camPosition = getWorldPosition(cam);
448
+ vec.sub(camPosition);
449
+ }
450
+ // we need to normalize the ray because our input is a max travel length and the direction may be not normalized
451
+ vec.normalize();
452
+ ray.dir.x = vec.x;
453
+ ray.dir.y = vec.y;
454
+ ray.dir.z = vec.z;
455
+ // Gizmos.DrawRay(ray.origin, ray.dir, 0xff0000, Infinity);
456
+ return ray;
457
+ }
458
+
459
+
460
+ private rapierSphere: Ball | null = null;
461
+ private readonly rapierColliderArray: Array<SphereOverlapResult> = [];
462
+ private readonly rapierIdentityRotation = { x: 0, y: 0, z: 0, w: 1 };
463
+ private readonly rapierForwardVector = { x: 0, y: 0, z: 1 };
464
+ /** Precice sphere overlap detection using rapier against colliders
465
+ * @param point center of the sphere in worldspace
466
+ * @param radius radius of the sphere
467
+ * @returns array of colliders that overlap with the sphere. Note: they currently only contain the collider and the gameobject
468
+ */
469
+ public sphereOverlap(point: Vector3, radius: number): Array<SphereOverlapResult> {
470
+ this.rapierColliderArray.length = 0;
471
+ if (!this._isInitialized) {
472
+ return this.rapierColliderArray;
473
+ }
474
+ if (!this.world) return this.rapierColliderArray;
475
+ this.rapierSphere ??= new MODULES.RAPIER_PHYSICS.MODULE.Ball(radius);
476
+ this.rapierSphere.radius = radius;
477
+
478
+ if (this.debugRenderRaycasts || showPhysicsRaycasts) Gizmos.DrawWireSphere(point, radius, 0x3344ff, 1);
479
+ this.world.intersectionsWithShape(point,
480
+ this.rapierIdentityRotation,
481
+ this.rapierSphere,
482
+ col => {
483
+ const collider = col[$componentKey] as ICollider
484
+ // if (collider.gameObject.layers.isEnabled(2)) return true;
485
+ const intersection = new SphereOverlapResult(collider.gameObject, collider);
486
+ this.rapierColliderArray.push(intersection);
487
+ return true; // Return `false` instead if we want to stop searching for other colliders that contain this point.
488
+ },
489
+ // TODO: it seems as QueryFilterFlags.EXCLUDE_SENSORS also excludes DYNAMIC Rigidbodies (only if they're set to kinematic)
490
+ undefined, // QueryFilterFlags.EXCLUDE_SENSORS,
491
+ undefined, undefined, undefined,
492
+ col => {
493
+ // we don't want to raycast against triggers (see comment about Exclude Sensors above)
494
+ if (col.isSensor()) return false;
495
+ const collider = col[$componentKey] as ICollider
496
+ return collider.gameObject.layers.isEnabled(2) == false
497
+ }
498
+ );
499
+ return this.rapierColliderArray;
500
+
501
+
502
+ // TODO: this only returns one hit
503
+ // let filterGroups = 0xffffffff;
504
+ // filterGroups &= ~(1 << 2);
505
+ // const hit: ShapeColliderTOI | null = this.world.castShape(point,
506
+ // this.rapierIdentityRotation,
507
+ // this.rapierForwardVector,
508
+ // this.rapierSphere,
509
+ // 0,
510
+ // QueryFilterFlags.EXCLUDE_SENSORS,
511
+ // // filterGroups,
512
+ // );
513
+ // // console.log(hit);
514
+ // if (hit) {
515
+ // const collider = hit.collider[$componentKey] as ICollider
516
+ // const intersection = new SphereOverlapResult(collider.gameObject);
517
+ // this.rapierColliderArray.push(intersection);
518
+ // // const localpt = hit.witness2;
519
+ // // // const normal = hit.normal2;
520
+ // // const hitPoint = new Vector3(localpt.x, localpt.y, localpt.z);
521
+ // // // collider.gameObject.localToWorld(hitPoint);
522
+ // // // const normalPt = new Vector3(normal.x, normal.y, normal.z);
523
+ // // // const mat = new Matrix4().setPosition(point).scale(new Vector3(radius, radius, radius));
524
+ // // // hitPoint.applyMatrix4(mat);
525
+ // // console.log(hit.witness2)
526
+ // // // hitPoint.add(point);
527
+ // // const dist = hitPoint.distanceTo(point);
528
+ // }
529
+
530
+ // return this.rapierColliderArray;
531
+ }
532
+
533
+
534
+
535
+
536
+ // physics simulation
537
+
538
+ enabled: boolean = false;
539
+ /** Get access to the rapier world */
540
+ public get world(): World | undefined { return this._world };
541
+
542
+ private _tempPosition: Vector3 = new Vector3();
543
+ private _tempQuaternion: Quaternion = new Quaternion();
544
+ private _tempScale: Vector3 = new Vector3();
545
+ private _tempMatrix: Matrix4 = new Matrix4();
546
+
547
+ private static _didLoadPhysicsEngine: boolean = false;
548
+
549
+ private _isUpdatingPhysicsWorld: boolean = false;
550
+ get isUpdating(): boolean { return this._isUpdatingPhysicsWorld; }
551
+
552
+
553
+ private _world?: World;
554
+ private _hasCreatedWorld: boolean = false;
555
+ private eventQueue?: EventQueue;
556
+ private collisionHandler?: PhysicsCollisionHandler;
557
+
558
+
559
+ private objects: IComponent[] = [];
560
+ private bodies: PhysicsBody[] = [];
561
+
562
+ private _meshCache: Map<string, Float32Array> = new Map<string, Float32Array>();
563
+
564
+ private _gravity = { x: 0.0, y: -9.81, z: 0.0 };
565
+
566
+ get gravity() {
567
+ return this.world?.gravity ?? this._gravity;
568
+ }
569
+
570
+ set gravity(value: Vec3) {
571
+ if (this.world) {
572
+ this.world.gravity = value;
573
+ }
574
+ else {
575
+ this._gravity = value;
576
+ }
577
+ }
578
+
579
+ clearCaches() {
580
+ this._meshCache.clear();
581
+ if (this.eventQueue?.raw)
582
+ this.eventQueue?.free();
583
+ if (this.world?.bodies)
584
+ this.world?.free();
585
+ }
586
+
587
+ async addBoxCollider(collider: ICollider, size: Vector3) {
588
+ if (!this._isInitialized)
589
+ await this.initialize();
590
+ if (!collider.activeAndEnabled) return;
591
+
592
+ if (!this.enabled) {
593
+ if (debugPhysics) console.warn("Physics are disabled");
594
+ return;
595
+ }
596
+ const obj = collider.gameObject;
597
+ const scale = getWorldScale(obj, this._tempPosition).multiply(size);
598
+ scale.multiplyScalar(0.5);
599
+
600
+ // prevent negative scale
601
+ if (scale.x < 0) scale.x = Math.abs(scale.x);
602
+ if (scale.y < 0) scale.y = Math.abs(scale.y);
603
+ if (scale.z < 0) scale.z = Math.abs(scale.z);
604
+
605
+ // prevent zero scale - seems normals are flipped otherwise
606
+ const minSize = 0.0000001;
607
+ if (scale.x < minSize) scale.x = minSize;
608
+ if (scale.y < minSize) scale.y = minSize;
609
+ if (scale.z < minSize) scale.z = minSize;
610
+
611
+ const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.cuboid(scale.x, scale.y, scale.z);
612
+ // const objectLayerMask = collider.gameObject.layers.mask;
613
+ // const mask = objectLayerMask & ~2;
614
+ // TODO: https://rapier.rs/docs/user_guides/javascript/colliders/#collision-groups-and-solver-groups
615
+ // desc.setCollisionGroups(objectLayerMask);
616
+ this.createCollider(collider, desc);
617
+ }
618
+
619
+ async addSphereCollider(collider: ICollider) {
620
+ if (!this._isInitialized)
621
+ await this.initialize();
622
+ if (!collider.activeAndEnabled) return;
623
+ if (!this.enabled) {
624
+ if (debugPhysics) console.warn("Physics are disabled");
625
+ return;
626
+ }
627
+ const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.ball(.5);
628
+ this.createCollider(collider, desc);
629
+ this.updateProperties(collider);
630
+ }
631
+
632
+ async addCapsuleCollider(collider: ICollider, height: number, radius: number) {
633
+ if (!this._isInitialized)
634
+ await this.initialize();
635
+ if (!collider.activeAndEnabled) return;
636
+ if (!this.enabled) {
637
+ if (debugPhysics) console.warn("Physics are disabled");
638
+ return;
639
+ }
640
+ const obj = collider.gameObject;
641
+ const scale = getWorldScale(obj, this._tempPosition);
642
+ // Prevent negative scales
643
+ scale.x = Math.abs(scale.x);
644
+ scale.y = Math.abs(scale.y);
645
+ const finalRadius = radius * scale.x;
646
+ // half height = distance between capsule origin and top sphere origin (not the top end of the capsule)
647
+ height = Math.max(height, finalRadius * 2);
648
+ const hh = Mathf.clamp((height * .5 * scale.y) - (radius * scale.x), 0, Number.MAX_SAFE_INTEGER);
649
+ const desc = MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.capsule(hh, finalRadius);
650
+ this.createCollider(collider, desc);
651
+ }
652
+
653
+ async addMeshCollider(collider: ICollider, mesh: Mesh, convex: boolean, extraScale?: Vector3) {
654
+
655
+ // capture the geometry before waiting for phyiscs engine
656
+ let geo = mesh.geometry;
657
+ if (!geo) {
658
+ if (debugPhysics) console.warn("Missing mesh geometry", mesh.name);
659
+ return;
660
+ }
661
+
662
+ // check if mesh is indexed, if not generate indices
663
+ if (!geo.index?.array?.length) {
664
+ console.warn(`Your MeshCollider is missing vertices or indices in the assined mesh \"${mesh.name}\". Consider providing an indexed geometry.`);
665
+ geo = BufferGeometryUtils.mergeVertices(geo);
666
+ }
667
+
668
+ let positions: Float32Array | null = null;
669
+
670
+ const positionAttribute = geo.getAttribute("position") as BufferAttribute | InterleavedBufferAttribute;
671
+ if (positionAttribute instanceof InterleavedBufferAttribute) {
672
+ const count = positionAttribute.count;
673
+ positions = new Float32Array(count * 3);
674
+ for (let i = 0; i < count; i++) {
675
+ const x = positionAttribute.getX(i);
676
+ const y = positionAttribute.getY(i);
677
+ const z = positionAttribute.getZ(i);
678
+ positions[i * 3] = x;
679
+ positions[i * 3 + 1] = y;
680
+ positions[i * 3 + 2] = z;
681
+ }
682
+ }
683
+ else {
684
+ positions = positionAttribute.array as Float32Array;
685
+ }
686
+
687
+ await this.initialize();
688
+
689
+ if (!this.enabled) {
690
+ if (debugPhysics) console.warn("Physics are disabled");
691
+ return;
692
+ }
693
+
694
+ if (!collider.activeAndEnabled) return;
695
+
696
+
697
+ // let positions = geo.getAttribute("position").array as Float32Array;
698
+ const indices = geo.index?.array as Uint32Array;
699
+
700
+ const scale = collider.gameObject.worldScale.clone();
701
+ if(extraScale) scale.multiply(extraScale);
702
+
703
+ // scaling seems not supported yet https://github.com/dimforge/rapier/issues/243
704
+ if (Math.abs(scale.x - 1) > 0.0001 || Math.abs(scale.y - 1) > 0.0001 || Math.abs(scale.z - 1) > 0.0001) {
705
+ const key = `${geo.uuid}_${scale.x}_${scale.y}_${scale.z}_${convex}`;
706
+ if (this._meshCache.has(key)) {
707
+ if (debugPhysics) console.warn("Use cached mesh collider")
708
+ positions = this._meshCache.get(key)!;
709
+ }
710
+ else {
711
+ if (debugPhysics || isDevEnvironment()) console.debug(`[Performance] Your MeshCollider \"${collider.name}\" is scaled: consider applying the scale to the collider mesh instead (${scale.x}, ${scale.y}, ${scale.z})`);
712
+ const scaledPositions = new Float32Array(positions.length);
713
+ for (let i = 0; i < positions.length; i += 3) {
714
+ scaledPositions[i] = positions[i] * scale.x;
715
+ scaledPositions[i + 1] = positions[i + 1] * scale.y;
716
+ scaledPositions[i + 2] = positions[i + 2] * scale.z;
717
+ }
718
+ positions = scaledPositions;
719
+ this._meshCache.set(key, scaledPositions);
720
+ }
721
+ }
722
+ const desc = convex
723
+ ? MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.convexHull(positions)
724
+ : MODULES.RAPIER_PHYSICS.MODULE.ColliderDesc.trimesh(positions, indices);
725
+ if (desc) {
726
+ this.createCollider(collider, desc);
727
+ // col.setMassProperties(1, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0, w: 1 });
728
+ // rb?.setTranslation({ x: 0, y: 2, z: 0 });
729
+ // col.setTranslationWrtParent(new Vector3(0,2,0));
730
+
731
+ }
732
+ }
733
+
734
+ updatePhysicsMaterial(col: ICollider) {
735
+ if (!col) return;
736
+ const physicsMaterial = col.sharedMaterial;
737
+ const rapier_collider = col[$bodyKey] as Collider;
738
+ if (!rapier_collider) return;
739
+
740
+ if (physicsMaterial) {
741
+ if (physicsMaterial.bounciness !== undefined)
742
+ rapier_collider.setRestitution(physicsMaterial.bounciness);
743
+
744
+ if (physicsMaterial.bounceCombine !== undefined) {
745
+ switch (physicsMaterial.bounceCombine) {
746
+ case PhysicsMaterialCombine.Average:
747
+ rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
748
+ break;
749
+ case PhysicsMaterialCombine.Maximum:
750
+ rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
751
+ break;
752
+ case PhysicsMaterialCombine.Minimum:
753
+ rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
754
+ break;
755
+ case PhysicsMaterialCombine.Multiply:
756
+ rapier_collider.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
757
+ break;
758
+ }
759
+ }
760
+
761
+ if (physicsMaterial.dynamicFriction !== undefined)
762
+ rapier_collider.setFriction(physicsMaterial.dynamicFriction);
763
+
764
+ if (physicsMaterial.frictionCombine !== undefined) {
765
+ switch (physicsMaterial.frictionCombine) {
766
+ case PhysicsMaterialCombine.Average:
767
+ rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
768
+ break;
769
+ case PhysicsMaterialCombine.Maximum:
770
+ rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
771
+ break;
772
+ case PhysicsMaterialCombine.Minimum:
773
+ rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
774
+ break;
775
+ case PhysicsMaterialCombine.Multiply:
776
+ rapier_collider.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
777
+ break;
778
+ }
779
+ }
780
+ }
781
+ }
782
+
783
+ /** Get the rapier body for a Needle component */
784
+ getBody(obj: ICollider | IRigidbody): null | any {
785
+ if (!obj) return null;
786
+ const body = obj[$bodyKey];
787
+ return body;
788
+ }
789
+
790
+ /** Get the Needle Engine component for a rapier object */
791
+ getComponent(rapierObject: object): IComponent | null {
792
+ if (!rapierObject) return null;
793
+ const component = rapierObject[$componentKey];
794
+ return component;
795
+ }
796
+
797
+ private createCollider(collider: ICollider, desc: ColliderDesc) {
798
+ if (!this.world) throw new Error("Physics world not initialized");
799
+ const matrix = this._tempMatrix;
800
+ let rigidBody: RigidBody | undefined = undefined;
801
+ if (!collider.attachedRigidbody) {
802
+ if (debugPhysics) console.log("Create collider without rigidbody", collider.name);
803
+ matrix.makeRotationFromQuaternion(getWorldQuaternion(collider.gameObject));
804
+ matrix.setPosition(getWorldPosition(collider.gameObject));
805
+ }
806
+ else {
807
+ rigidBody = this.getRigidbody(collider, this._tempMatrix);
808
+ }
809
+
810
+ matrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
811
+ this.tryApplyCenter(collider, this._tempPosition);
812
+ desc.setTranslation(this._tempPosition.x, this._tempPosition.y, this._tempPosition.z);
813
+ desc.setRotation(this._tempQuaternion);
814
+ desc.setSensor(collider.isTrigger);
815
+
816
+ // TODO: we might want to update this if the material changes
817
+ const physicsMaterial = collider.sharedMaterial;
818
+ if (physicsMaterial) {
819
+
820
+ if (physicsMaterial.bounciness !== undefined)
821
+ desc.setRestitution(physicsMaterial.bounciness);
822
+
823
+ if (physicsMaterial.bounceCombine !== undefined) {
824
+ switch (physicsMaterial.bounceCombine) {
825
+ case PhysicsMaterialCombine.Average:
826
+ desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
827
+ break;
828
+ case PhysicsMaterialCombine.Maximum:
829
+ desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
830
+ break;
831
+ case PhysicsMaterialCombine.Minimum:
832
+ desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
833
+ break;
834
+ case PhysicsMaterialCombine.Multiply:
835
+ desc.setRestitutionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
836
+ break;
837
+ }
838
+ }
839
+
840
+ if (physicsMaterial.dynamicFriction !== undefined)
841
+ desc.setFriction(physicsMaterial.dynamicFriction);
842
+
843
+ if (physicsMaterial.frictionCombine !== undefined) {
844
+ switch (physicsMaterial.frictionCombine) {
845
+ case PhysicsMaterialCombine.Average:
846
+ desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Average);
847
+ break;
848
+ case PhysicsMaterialCombine.Maximum:
849
+ desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Max);
850
+ break;
851
+ case PhysicsMaterialCombine.Minimum:
852
+ desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Min);
853
+ break;
854
+ case PhysicsMaterialCombine.Multiply:
855
+ desc.setFrictionCombineRule(MODULES.RAPIER_PHYSICS.MODULE.CoefficientCombineRule.Multiply);
856
+ break;
857
+ }
858
+ }
859
+ }
860
+
861
+ // if we want to use explicit mass properties, we need to set the collider density to 0
862
+ // otherwise rapier will compute the mass properties based on the collider shape and density
863
+ // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
864
+ if (collider.attachedRigidbody?.autoMass === false) {
865
+ desc.setDensity(.000001);
866
+ desc.setMass(.000001);
867
+ }
868
+
869
+ try {
870
+ const col = this.world.createCollider(desc, rigidBody);
871
+ col[$componentKey] = collider;
872
+ collider[$bodyKey] = col;
873
+ col.setActiveEvents(MODULES.RAPIER_PHYSICS.MODULE.ActiveEvents.COLLISION_EVENTS);
874
+ // We want to receive collisitons between two triggers too
875
+ col.setActiveCollisionTypes(MODULES.RAPIER_PHYSICS.MODULE.ActiveCollisionTypes.ALL);
876
+ this.objects.push(collider);
877
+ this.bodies.push(col);
878
+
879
+ // set the collider layers
880
+ this.updateColliderCollisionGroups(collider);
881
+
882
+ return col;
883
+ }
884
+ catch (e) {
885
+ console.error("Error creating collider \"" + collider.name + "\"\nError:", e);
886
+ return null;
887
+ }
888
+ }
889
+
890
+ /**
891
+ * Updates the collision groups of a collider.
892
+ *
893
+ * @param collider - The collider to update.
894
+ */
895
+ private updateColliderCollisionGroups(collider: ICollider) {
896
+ const body = collider[$bodyKey] as Collider;
897
+ const members = collider.membership;
898
+ let memberMask = 0;
899
+ if (members == undefined) {
900
+ memberMask = 0xffff;
901
+ }
902
+ else {
903
+ for (let i = 0; i < members.length; i++) {
904
+ const member = members[i];
905
+ if (member > 31) console.error(`Rapier only supports 32 layers, layer ${member} is not supported`);
906
+ else memberMask |= 1 << Math.floor(member);
907
+ }
908
+ }
909
+
910
+ const mask = collider.filter;
911
+ let filterMask = 0;
912
+ if (mask == undefined) {
913
+ filterMask = 0xffff;
914
+ }
915
+ else {
916
+ for (let i = 0; i < mask.length; i++) {
917
+ const member = mask[i];
918
+ if (member > 31) console.error(`Rapier only supports 32 layers, layer ${member} is not supported`);
919
+ else filterMask |= 1 << Math.floor(member);
920
+ }
921
+ }
922
+ body.setCollisionGroups((memberMask << 16) | filterMask);
923
+ }
924
+
925
+ private getRigidbody(collider: ICollider, _matrix: Matrix4): RigidBody {
926
+
927
+ if (!this.world) throw new Error("Physics world not initialized");
928
+ let rigidBody: RigidBody | null = null;
929
+
930
+ if (collider.attachedRigidbody) {
931
+ const rb = collider.attachedRigidbody;
932
+ rigidBody = rb[$bodyKey];
933
+ if (!rigidBody) {
934
+ const kinematic = rb.isKinematic && !debugColliderPlacement;
935
+ if (debugPhysics)
936
+ console.log("Create rigidbody", kinematic);
937
+ const rigidBodyDesc = (kinematic ? MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.kinematicPositionBased() : MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.dynamic()) as RigidBodyDesc;
938
+ const pos = getWorldPosition(collider.attachedRigidbody.gameObject);
939
+ rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
940
+ rigidBodyDesc.setRotation(getWorldQuaternion(collider.attachedRigidbody.gameObject));
941
+ rigidBodyDesc.centerOfMass = new MODULES.RAPIER_PHYSICS.MODULE.Vector3(rb.centerOfMass.x, rb.centerOfMass.y, rb.centerOfMass.z);
942
+ rigidBody = this.world.createRigidBody(rigidBodyDesc);
943
+ this.bodies.push(rigidBody);
944
+ this.objects.push(rb);
945
+ }
946
+ rigidBody[$componentKey] = rb;
947
+ rb[$bodyKey] = rigidBody;
948
+ this.internalUpdateRigidbodyProperties(rb, rigidBody);
949
+ this.getRigidbodyRelativeMatrix(collider.gameObject, rb.gameObject, _matrix);
950
+ collider[$colliderRigidbody] = rigidBody;
951
+ }
952
+ else {
953
+ const rigidBodyDesc = MODULES.RAPIER_PHYSICS.MODULE.RigidBodyDesc.kinematicPositionBased();
954
+ const pos = getWorldPosition(collider.gameObject);
955
+ rigidBodyDesc.setTranslation(pos.x, pos.y, pos.z);
956
+ rigidBodyDesc.setRotation(getWorldQuaternion(collider.gameObject));
957
+ rigidBody = this.world.createRigidBody(rigidBodyDesc);
958
+ _matrix.identity();
959
+ rigidBody[$componentKey] = null;
960
+ }
961
+
962
+
963
+ return rigidBody;
964
+ }
965
+
966
+ private internal_getRigidbody(rb: IRigidbody | ICollider): RigidBody | null {
967
+ if ((rb as ICollider).isCollider === true) return rb[$colliderRigidbody] as RigidBody;
968
+ return rb[$bodyKey] as RigidBody;
969
+ }
970
+
971
+ private internalUpdateColliderProperties(col: ICollider, collider: Collider) {
972
+ const shape = collider.shape;
973
+ let sizeHasChanged = false;
974
+ switch (shape.type) {
975
+ // Sphere Collider
976
+ case MODULES.RAPIER_PHYSICS.MODULE.ShapeType.Ball:
977
+ {
978
+ const ball = shape as Ball;
979
+ const sc = col as ISphereCollider;
980
+ const obj = col.gameObject;
981
+ const scale = getWorldScale(obj, this._tempPosition);
982
+ const radius = Math.abs(sc.radius * scale.x);
983
+ sizeHasChanged = ball.radius !== radius;
984
+ ball.radius = radius;
985
+ if (sizeHasChanged) {
986
+ collider.setShape(ball);
987
+ }
988
+ break;
989
+ }
990
+ case MODULES.RAPIER_PHYSICS.MODULE.ShapeType.Cuboid:
991
+ const cuboid = shape as Cuboid;
992
+ const sc = col as IBoxCollider;
993
+ const obj = col.gameObject;
994
+ const scale = getWorldScale(obj, this._tempPosition);
995
+ const newX = Math.abs(sc.size.x * 0.5 * scale.x);
996
+ const newY = Math.abs(sc.size.y * 0.5 * scale.y);
997
+ const newZ = Math.abs(sc.size.z * 0.5 * scale.z);
998
+ sizeHasChanged = cuboid.halfExtents.x !== newX || cuboid.halfExtents.y !== newY || cuboid.halfExtents.z !== newZ;
999
+ cuboid.halfExtents.x = newX;
1000
+ cuboid.halfExtents.y = newY;
1001
+ cuboid.halfExtents.z = newZ;
1002
+ if (sizeHasChanged) {
1003
+ collider.setShape(cuboid);
1004
+ }
1005
+ break;
1006
+ }
1007
+
1008
+ if (sizeHasChanged) {
1009
+ const rb = col.attachedRigidbody;
1010
+ if (rb?.autoMass) {
1011
+ const ph = this.getBody(rb) as RigidBody
1012
+ ph?.recomputeMassPropertiesFromColliders();
1013
+ }
1014
+ }
1015
+
1016
+ this.updateColliderCollisionGroups(col);
1017
+
1018
+ if (col.isTrigger !== collider.isSensor())
1019
+ collider.setSensor(col.isTrigger);
1020
+ }
1021
+
1022
+ private internalUpdateRigidbodyProperties(rb: IRigidbody, rigidbody: RigidBody) {
1023
+ // continuous collision detection
1024
+ // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
1025
+ rigidbody.enableCcd(rb.collisionDetectionMode !== CollisionDetectionMode.Discrete);
1026
+ rigidbody.setLinearDamping(rb.drag);
1027
+ rigidbody.setAngularDamping(rb.angularDrag);
1028
+ rigidbody.setGravityScale(rb.useGravity ? rb.gravityScale : 0, true);
1029
+
1030
+ // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#dominance
1031
+ if (rb.dominanceGroup <= 127 && rb.dominanceGroup >= -127)
1032
+ rigidbody.setDominanceGroup(Math.floor(rb.dominanceGroup))
1033
+ else rigidbody.setDominanceGroup(0);
1034
+
1035
+ if (rb.autoMass) {
1036
+ rigidbody.setAdditionalMass(0, false);
1037
+ for (let i = 0; i < rigidbody.numColliders(); i++) {
1038
+ const col = rigidbody.collider(i);
1039
+ col.setDensity(1);
1040
+ }
1041
+ rigidbody.recomputeMassPropertiesFromColliders();
1042
+ }
1043
+ else {
1044
+ rigidbody.setAdditionalMass(rb.mass, false);
1045
+ for (let i = 0; i < rigidbody.numColliders(); i++) {
1046
+ const col = rigidbody.collider(i);
1047
+ col.setDensity(0.0000001);
1048
+ }
1049
+ rigidbody.recomputeMassPropertiesFromColliders();
1050
+ }
1051
+
1052
+ // https://rapier.rs/docs/user_guides/javascript/rigid_bodies#mass-properties
1053
+ // rigidbody.setAdditionalMass(rb.mass, true);
1054
+ // for (let i = 0; i < rigidbody.numColliders(); i++) {
1055
+ // const collider = rigidbody.collider(i);
1056
+ // if (collider) {
1057
+ // collider.setMass(rb.mass);
1058
+ // // const density = rb.mass / collider.shape.computeMassProperties().mass;
1059
+ // }
1060
+ // }
1061
+
1062
+ // lock rotations
1063
+ rigidbody.setEnabledRotations(!rb.lockRotationX, !rb.lockRotationY, !rb.lockRotationZ, false);
1064
+ rigidbody.setEnabledTranslations(!rb.lockPositionX, !rb.lockPositionY, !rb.lockPositionZ, false);
1065
+
1066
+ if (rb.isKinematic) {
1067
+ rigidbody.setBodyType(MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicPositionBased, false);
1068
+ }
1069
+ else {
1070
+ rigidbody.setBodyType(MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.Dynamic, false);
1071
+ }
1072
+ }
1073
+
1074
+ // private _lastStepTime: number | undefined = 0;
1075
+ private lines?: LineSegments;
1076
+
1077
+ public step(dt?: number) {
1078
+ if (!this.world) return;
1079
+ if (!this.enabled) return;
1080
+ this._isUpdatingPhysicsWorld = true;
1081
+ if (!this.eventQueue) {
1082
+ this.eventQueue = new MODULES.RAPIER_PHYSICS.MODULE.EventQueue(false);
1083
+ }
1084
+ if (dt === undefined || dt <= 0) {
1085
+ this._isUpdatingPhysicsWorld = false;
1086
+ return;
1087
+ }
1088
+ else if (dt !== undefined) {
1089
+ // if we make to sudden changes to the timestep the physics can get unstable
1090
+ // https://rapier.rs/docs/user_guides/javascript/integration_parameters/#dt
1091
+ this.world.timestep = Mathf.lerp(this.world.timestep, dt, 0.8);
1092
+ }
1093
+ try {
1094
+ this.world.step(this.eventQueue);
1095
+ }
1096
+ catch (e) {
1097
+ console.warn("Error running physics step", e);
1098
+ }
1099
+ this._isUpdatingPhysicsWorld = false;
1100
+ }
1101
+
1102
+ public postStep() {
1103
+ if (!this.world) return;
1104
+ if (!this.enabled) return;
1105
+ this._isUpdatingPhysicsWorld = true;
1106
+ this.syncObjects();
1107
+ this._isUpdatingPhysicsWorld = false;
1108
+
1109
+ if (this.eventQueue && !this.collisionHandler) {
1110
+ this.collisionHandler = new PhysicsCollisionHandler(this.world, this.eventQueue);
1111
+ }
1112
+ if (this.collisionHandler) {
1113
+ this.collisionHandler.handleCollisionEvents();
1114
+ this.collisionHandler.update();
1115
+ }
1116
+ this.updateDebugRendering(this.world);
1117
+ }
1118
+
1119
+ private updateDebugRendering(world: World) {
1120
+ if (debugPhysics || debugColliderPlacement || showColliders || this.debugRenderColliders === true) {
1121
+ if (!this.lines) {
1122
+ const material = new LineBasicMaterial({
1123
+ color: 0x77dd77,
1124
+ fog: false,
1125
+ // vertexColors: VertexColors
1126
+ });
1127
+ const geometry = new BufferGeometry();
1128
+ this.lines = new LineSegments(geometry, material);
1129
+ this.lines.layers.disableAll();
1130
+ this.lines.layers.enable(2);
1131
+ }
1132
+ if (this.lines.parent !== this.context?.scene)
1133
+ this.context?.scene.add(this.lines);
1134
+ const buffers = world.debugRender();
1135
+ this.lines.geometry.setAttribute('position', new BufferAttribute(buffers.vertices, 3));
1136
+ this.lines.geometry.setAttribute('color', new BufferAttribute(buffers.colors, 4));
1137
+ // If a scene has no colliders at all at the start of the scene
1138
+ // the bounding sphere radius will be 0 and the lines will not be rendered
1139
+ // so we need to update the bounding sphere (perhaps it's enough to do this once...)
1140
+ if (this.context!.time.frame % 30 === 0 || this.lines.geometry.boundingSphere?.radius === 0) {
1141
+ this.lines.geometry.computeBoundingSphere();
1142
+ }
1143
+ }
1144
+ else {
1145
+ if (this.lines) {
1146
+ this.context?.scene.remove(this.lines);
1147
+ }
1148
+ }
1149
+ }
1150
+
1151
+ /** sync rendered objects with physics world (except for colliders without rigidbody) */
1152
+ private syncObjects() {
1153
+ if (debugColliderPlacement) return;
1154
+ for (let i = 0; i < this.bodies.length; i++) {
1155
+ const obj = this.objects[i];
1156
+ const body = this.bodies[i] as Collider;
1157
+
1158
+ // if the collider is not attached to a rigidbody
1159
+ // it means that its kinematic so we need to update its position
1160
+ const col = (obj as ICollider);
1161
+ if (col?.isCollider === true && !col.attachedRigidbody) {
1162
+ const rigidbody = body.parent();
1163
+ if (rigidbody)
1164
+ this.syncPhysicsBody(obj.gameObject, rigidbody, true, true);
1165
+ else
1166
+ this.syncPhysicsBody(obj.gameObject, body, true, true);
1167
+ continue;
1168
+ }
1169
+
1170
+
1171
+ // sync
1172
+ const pos = body.translation();
1173
+ const rot = body.rotation();
1174
+ if (Number.isNaN(pos.x) || Number.isNaN(rot.x)) {
1175
+ if (!col["__COLLIDER_NAN"] && isDevEnvironment()) {
1176
+ console.warn("Collider has NaN values", col.name, col.gameObject, body);
1177
+ col["__COLLIDER_NAN"] = true;
1178
+ }
1179
+ continue;
1180
+ }
1181
+
1182
+ // make sure to keep the collider offset
1183
+ const center = obj["center"] as Vector3;
1184
+ if (center && center.isVector3) {
1185
+ this._tempQuaternion.set(rot.x, rot.y, rot.z, rot.w);
1186
+ const offset = this._tempPosition.copy(center).applyQuaternion(this._tempQuaternion);
1187
+ const scale = getWorldScale(obj.gameObject);
1188
+ offset.multiply(scale);
1189
+ pos.x -= offset.x;
1190
+ pos.y -= offset.y;
1191
+ pos.z -= offset.z;
1192
+ }
1193
+ setWorldPositionXYZ(obj.gameObject, pos.x, pos.y, pos.z);
1194
+ setWorldQuaternionXYZW(obj.gameObject, rot.x, rot.y, rot.z, rot.w);
1195
+ }
1196
+ }
1197
+
1198
+ private syncPhysicsBody(obj: Object3D, body: RigidBody | Collider, translation: boolean, rotation: boolean) {
1199
+
1200
+ // const bodyType = body.bodyType();
1201
+ // const previous = physicsBody.translation();
1202
+ // const vel = physicsBody.linvel();
1203
+
1204
+ if (body instanceof MODULES.RAPIER_PHYSICS.MODULE.RigidBody) {
1205
+ const worldPosition = getWorldPosition(obj, this._tempPosition);
1206
+ const worldQuaternion = getWorldQuaternion(obj, this._tempQuaternion);
1207
+ const type = body.bodyType();
1208
+ switch (type) {
1209
+ case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.Fixed:
1210
+ case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicPositionBased:
1211
+ case MODULES.RAPIER_PHYSICS.MODULE.RigidBodyType.KinematicVelocityBased:
1212
+ if (translation)
1213
+ body.setNextKinematicTranslation(worldPosition);
1214
+ if (rotation)
1215
+ body.setNextKinematicRotation(worldQuaternion);
1216
+ break;
1217
+ default:
1218
+ if (translation)
1219
+ body.setTranslation(worldPosition, false);
1220
+ if (rotation)
1221
+ body.setRotation(worldQuaternion, false);
1222
+ break;
1223
+
1224
+ }
1225
+ }
1226
+ else if (body instanceof MODULES.RAPIER_PHYSICS.MODULE.Collider) {
1227
+ if (obj.matrixWorldNeedsUpdate) {
1228
+ obj.updateWorldMatrix(true, false);
1229
+ }
1230
+ obj.matrixWorld.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1231
+ const wp = this._tempPosition;
1232
+ const wq = this._tempQuaternion;
1233
+ // const wp = getWorldPosition(obj, this._tempPosition);
1234
+ // const wq = getWorldQuaternion(obj, this._tempQuaternion);
1235
+ const collider = body[$componentKey] as ICollider;
1236
+ this.tryApplyCenter(collider, wp);
1237
+
1238
+ // we need to check if translation or rotation have changed, otherwise the physics engine will wakeup rigidbody that are in contact with this collider
1239
+ if (translation) {
1240
+ const ct = body.translation();
1241
+ if (ct.x !== wp.x || ct.y !== wp.y || ct.z !== wp.z)
1242
+ body.setTranslation(wp);
1243
+ }
1244
+ if (rotation) {
1245
+ const cr = body.rotation();
1246
+ if (cr.x !== wq.x || cr.y !== wq.y || cr.z !== wq.z || cr.w !== wq.w)
1247
+ body.setRotation(wq);
1248
+ }
1249
+ }
1250
+
1251
+ // physicsBody.setBodyType(RAPIER.RigidBodyType.Fixed);
1252
+ // physicsBody.setLinvel(vel, false);
1253
+
1254
+ // update velocity
1255
+ // const pos = physicsBody.translation();
1256
+ // pos.x -= previous.x;
1257
+ // pos.y -= previous.y;
1258
+ // pos.z -= previous.z;
1259
+ // // threhold
1260
+ // const t = 1;
1261
+ // const canUpdateVelocity = Math.abs(pos.x) < t && Math.abs(pos.y) < t && Math.abs(pos.z) < t;
1262
+ // if (canUpdateVelocity) {
1263
+ // const damping = 1 + this.context.time.deltaTime;
1264
+ // vel.x *= damping;
1265
+ // vel.y *= damping;
1266
+ // vel.z *= damping;
1267
+ // vel.x += pos.x;
1268
+ // vel.y += pos.y;
1269
+ // vel.z += pos.z;
1270
+ // console.log(vel);
1271
+ // physicsBody.setLinvel(vel, true);
1272
+ // }
1273
+ // else if(debugPhysics) console.warn("Movement exceeded threshold, not updating velocity", pos);
1274
+
1275
+ // body.setBodyType(bodyType);
1276
+ }
1277
+
1278
+ private readonly _tempCenterPos: Vector3 = new Vector3();
1279
+ private readonly _tempCenterVec: Vector3 = new Vector3();
1280
+ private readonly _tempCenterQuaternion: Quaternion = new Quaternion();
1281
+ private tryApplyCenter(collider: ICollider, targetVector: Vector3) {
1282
+ const center = collider.center;
1283
+ if (center && collider.gameObject) {
1284
+ if (center.x !== 0 || center.y !== 0 || center.z !== 0) {
1285
+ // TODO: fix export of center in editor integrations so we dont have to flip here
1286
+ this._tempCenterPos.x = center.x;
1287
+ this._tempCenterPos.y = center.y;
1288
+ this._tempCenterPos.z = center.z;
1289
+ getWorldScale(collider.gameObject, this._tempCenterVec);
1290
+ this._tempCenterPos.multiply(this._tempCenterVec);
1291
+ if (!collider.attachedRigidbody) {
1292
+ getWorldQuaternion(collider.gameObject, this._tempCenterQuaternion);
1293
+ this._tempCenterPos.applyQuaternion(this._tempCenterQuaternion);
1294
+ }
1295
+ else {
1296
+ this._tempCenterPos.applyQuaternion(collider.gameObject.quaternion);
1297
+ }
1298
+ targetVector.x += this._tempCenterPos.x;
1299
+ targetVector.y += this._tempCenterPos.y;
1300
+ targetVector.z += this._tempCenterPos.z;
1301
+ }
1302
+ }
1303
+ }
1304
+
1305
+ private static _matricesBuffer: Matrix4[] = [];
1306
+ private getRigidbodyRelativeMatrix(comp: Object3D, rigidbody: Object3D, mat: Matrix4, matrices?: Matrix4[]): Matrix4 {
1307
+ // collect all matrices to the rigidbody and then build the rigidbody relative matrix
1308
+ if (matrices === undefined) {
1309
+ matrices = RapierPhysics._matricesBuffer;
1310
+ matrices.length = 0;
1311
+ }
1312
+ if (comp === rigidbody) {
1313
+ const scale = getWorldScale(comp, this._tempPosition);
1314
+ mat.makeScale(scale.x, scale.y, scale.z);
1315
+ for (let i = matrices.length - 1; i >= 0; i--) {
1316
+ mat.multiply(matrices[i]);
1317
+ }
1318
+ return mat;
1319
+ }
1320
+ matrices.push(comp.matrix);
1321
+ if (comp.parent) {
1322
+ this.getRigidbodyRelativeMatrix(comp.parent, rigidbody, mat, matrices);
1323
+ }
1324
+ return mat;
1325
+ }
1326
+
1327
+ private static centerConnectionPos = { x: 0, y: 0, z: 0 };
1328
+ private static centerConnectionRot = { x: 0, y: 0, z: 0, w: 1 };
1329
+
1330
+
1331
+
1332
+ addFixedJoint(body1: IRigidbody, body2: IRigidbody) {
1333
+ if (!this.world) {
1334
+ console.error("Physics world not initialized");
1335
+ return;
1336
+ }
1337
+ const b1 = body1[$bodyKey] as RigidBody;
1338
+ const b2 = body2[$bodyKey] as RigidBody;
1339
+
1340
+ this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
1341
+ this._tempMatrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1342
+
1343
+ const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.fixed(
1344
+ RapierPhysics.centerConnectionPos, RapierPhysics.centerConnectionRot,
1345
+ this._tempPosition, this._tempQuaternion,
1346
+ );
1347
+ const joint = this.world.createImpulseJoint(params, b1, b2, true);
1348
+ if (debugPhysics)
1349
+ console.log("ADD FIXED JOINT", joint)
1350
+ }
1351
+
1352
+
1353
+ /** The joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc. They are characterized by one local anchor as well as one local axis on each rigid-body. */
1354
+ addHingeJoint(body1: IRigidbody, body2: IRigidbody, anchor: { x: number, y: number, z: number }, axis: { x: number, y: number, z: number }) {
1355
+ if (!this.world) {
1356
+ console.error("Physics world not initialized");
1357
+ return;
1358
+ }
1359
+ const b1 = body1[$bodyKey] as RigidBody;
1360
+ const b2 = body2[$bodyKey] as RigidBody;
1361
+
1362
+ this.calculateJointRelativeMatrices(body1.gameObject, body2.gameObject, this._tempMatrix);
1363
+ this._tempMatrix.decompose(this._tempPosition, this._tempQuaternion, this._tempScale);
1364
+
1365
+ const params = MODULES.RAPIER_PHYSICS.MODULE.JointData.revolute(anchor, this._tempPosition, axis);
1366
+ const joint = this.world.createImpulseJoint(params, b1, b2, true);
1367
+ if (debugPhysics)
1368
+ console.log("ADD HINGE JOINT", joint)
1369
+ }
1370
+
1371
+
1372
+ private calculateJointRelativeMatrices(body1: IGameObject, body2: IGameObject, mat: Matrix4) {
1373
+ body1.updateWorldMatrix(true, false);
1374
+ body2.updateWorldMatrix(true, false);
1375
+ const world1 = body1.matrixWorld;
1376
+ const world2 = body2.matrixWorld;
1377
+ // set scale to 1
1378
+ world1.elements[0] = 1;
1379
+ world1.elements[5] = 1;
1380
+ world1.elements[10] = 1;
1381
+ world2.elements[0] = 1;
1382
+ world2.elements[5] = 1;
1383
+ world2.elements[10] = 1;
1384
+ mat.copy(world2).premultiply(world1.invert()).invert();
1385
+ }
1386
+ }
1387
+
1388
+
1389
+
1390
+ /** responsible of processing collision events for the component system */
1391
+ class PhysicsCollisionHandler {
1392
+
1393
+ readonly world: World;
1394
+ readonly eventQueue: EventQueue;
1395
+
1396
+ constructor(world: World, eventQueue: EventQueue) {
1397
+ this.world = world;
1398
+ this.eventQueue = eventQueue;
1399
+ }
1400
+
1401
+ private activeCollisions: Array<{ collider: ICollider, component: IComponent, collision: Collision }> = [];
1402
+ private activeCollisionsStay: Array<{ collider: ICollider, component: IComponent, collision: Collision }> = [];
1403
+ private activeTriggers: Array<{ collider: ICollider, component: IComponent, otherCollider: ICollider }> = [];
1404
+
1405
+ handleCollisionEvents() {
1406
+ if (!this.eventQueue) return;
1407
+ if (!this.world) return;
1408
+ this.eventQueue.drainCollisionEvents((handle1, handle2, started) => {
1409
+ const col1 = this.world!.getCollider(handle1);
1410
+ const col2 = this.world!.getCollider(handle2);
1411
+ if (!col1 || !col2) return;
1412
+ const colliderComponent1 = col1[$componentKey];
1413
+ const colliderComponent2 = col2[$componentKey];
1414
+ if (debugCollisions)
1415
+ console.log("EVT", colliderComponent1.name, colliderComponent2.name, started, col1, col2);
1416
+ if (colliderComponent1 && colliderComponent2) {
1417
+ if (started) {
1418
+ this.onCollisionStarted(colliderComponent1, col1, colliderComponent2, col2);
1419
+ this.onCollisionStarted(colliderComponent2, col2, colliderComponent1, col1);
1420
+ }
1421
+ else {
1422
+ this.onCollisionEnded(colliderComponent1, colliderComponent2);
1423
+ this.onCollisionEnded(colliderComponent2, colliderComponent1);
1424
+ }
1425
+ }
1426
+ });
1427
+ }
1428
+
1429
+ update() {
1430
+ this.onHandleCollisionStay();
1431
+ }
1432
+
1433
+ private onCollisionStarted(self: ICollider, selfBody: Collider, other: ICollider, otherBody: Collider) {
1434
+ let collision: Collision | null = null;
1435
+
1436
+ // if one is a trigger we dont get collisions but want to raise the trigger events
1437
+ if (self.isTrigger || other.isTrigger) {
1438
+ foreachComponent(self.gameObject, (c: IComponent) => {
1439
+ if (c.onTriggerEnter && !c.destroyed) {
1440
+ c.onTriggerEnter(other);
1441
+ }
1442
+ this.activeTriggers.push({ collider: self, component: c, otherCollider: other });
1443
+ });
1444
+ }
1445
+ else {
1446
+ const object = self.gameObject;
1447
+ // TODO: we dont respect the flip value here!
1448
+ this.world.contactPair(selfBody, otherBody, (manifold, _flipped) => {
1449
+ foreachComponent(object, (c: IComponent) => {
1450
+ if (c.destroyed) return;
1451
+ const hasDeclaredEventMethod = c.onCollisionEnter || c.onCollisionStay || c.onCollisionExit;
1452
+ if (hasDeclaredEventMethod || debugCollisions) {
1453
+ if (!collision) {
1454
+ const contacts: Array<ContactPoint> = [];
1455
+ const normal = manifold.normal();
1456
+ // invert the normal for convex MeshColliders, NE-2680
1457
+ if (other instanceof MeshCollider && other.convex) {
1458
+ normal.x = -normal.x;
1459
+ normal.y = -normal.y;
1460
+ normal.z = -normal.z;
1461
+ }
1462
+ for (let i = 0; i < manifold.numSolverContacts(); i++) {
1463
+ // solver points are in world space
1464
+ // https://rapier.rs/docs/user_guides/javascript/advanced_collision_detection_js#the-contact-graph
1465
+ const pt = manifold.solverContactPoint(i);
1466
+ const impulse = manifold.contactImpulse(i);
1467
+ if (pt) {
1468
+ const dist = manifold.contactDist(i);
1469
+ const friction = manifold.solverContactFriction(i);
1470
+ const tangentVelocity = manifold.solverContactTangentVelocity(i);
1471
+ const contact = new ContactPoint(pt, dist, normal, impulse, friction, tangentVelocity);
1472
+ contacts.push(contact);
1473
+ if (debugCollisions) {
1474
+ Gizmos.DrawDirection(pt, normal, 0xff0000, 3, true);
1475
+ }
1476
+ }
1477
+ }
1478
+ collision = new Collision(object, other, contacts);
1479
+ }
1480
+
1481
+ // we only need to keep track if any event exists
1482
+ if (hasDeclaredEventMethod) {
1483
+ const info = { collider: self, component: c, collision };
1484
+
1485
+ this.activeCollisions.push(info);
1486
+ if (c.onCollisionStay) {
1487
+ this.activeCollisionsStay.push(info);
1488
+ }
1489
+
1490
+ c.onCollisionEnter?.call(c, collision);
1491
+ }
1492
+
1493
+ }
1494
+ });
1495
+ });
1496
+ }
1497
+ }
1498
+
1499
+ private onHandleCollisionStay() {
1500
+ for (const active of this.activeCollisionsStay) {
1501
+ const c = active.component;
1502
+ if (c.destroyed) continue;
1503
+ if (c.activeAndEnabled && c.onCollisionStay) {
1504
+ if (active.collision.collider.destroyed) continue;
1505
+ const arg = active.collision;
1506
+ c.onCollisionStay(arg);
1507
+ }
1508
+ }
1509
+ for (const active of this.activeTriggers) {
1510
+ const c = active.component;
1511
+ if (c.destroyed) continue;
1512
+ if (c.activeAndEnabled && c.onTriggerStay) {
1513
+ const arg = active.otherCollider;
1514
+ if (arg.destroyed) continue;
1515
+ c.onTriggerStay(arg);
1516
+ }
1517
+ }
1518
+ }
1519
+
1520
+ private onCollisionEnded(self: ICollider, other: ICollider) {
1521
+ if (self.destroyed || other.destroyed) return;
1522
+ for (let i = 0; i < this.activeCollisions.length; i++) {
1523
+ const active = this.activeCollisions[i];
1524
+ const collider = active.collider;
1525
+ if (collider.destroyed || active.collision.collider.destroyed) {
1526
+ this.activeCollisions.splice(i, 1);
1527
+ i--;
1528
+ continue;
1529
+ }
1530
+ if (collider === self && active.collision.collider === other) {
1531
+ const c = active.component;
1532
+ this.activeCollisions.splice(i, 1);
1533
+ i--;
1534
+ if (c.activeAndEnabled && c.onCollisionExit) {
1535
+ const collision = active.collision;
1536
+ c.onCollisionExit(collision);
1537
+ }
1538
+ }
1539
+ }
1540
+ for (let i = 0; i < this.activeCollisionsStay.length; i++) {
1541
+ const active = this.activeCollisionsStay[i];
1542
+ const collider = active.collider;
1543
+ if (collider.destroyed || active.collision.collider.destroyed) {
1544
+ this.activeCollisionsStay.splice(i, 1);
1545
+ i--;
1546
+ continue;
1547
+ }
1548
+ if (collider === self && active.collision.collider === other) {
1549
+ const c = active.component;
1550
+ this.activeCollisionsStay.splice(i, 1);
1551
+ i--;
1552
+ if (c.activeAndEnabled && c.onCollisionExit) {
1553
+ const collision = active.collision;
1554
+ c.onCollisionExit(collision);
1555
+ }
1556
+ }
1557
+ }
1558
+ for (let i = 0; i < this.activeTriggers.length; i++) {
1559
+ const active = this.activeTriggers[i];
1560
+ const collider = active.collider;
1561
+ if (collider.destroyed || active.otherCollider.destroyed) {
1562
+ this.activeTriggers.splice(i, 1);
1563
+ i--;
1564
+ continue;
1565
+ }
1566
+ if (collider === self && active.otherCollider === other) {
1567
+ const c = active.component;
1568
+ this.activeTriggers.splice(i, 1);
1569
+ i--;
1570
+ if (c.activeAndEnabled && c.onTriggerExit) {
1571
+ const collision = active.otherCollider;
1572
+ c.onTriggerExit(collision);
1573
+ }
1574
+ }
1575
+ }
1576
+ }
1577
+ }