@needle-tools/engine 4.4.0-beta.3 → 4.4.0-beta.4

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