@babylonjs/core 5.35.0 → 5.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/Audio/sound.d.ts +5 -0
  2. package/Audio/sound.js +7 -0
  3. package/Audio/sound.js.map +1 -1
  4. package/Debug/physicsViewer.d.ts +4 -3
  5. package/Debug/physicsViewer.js +2 -2
  6. package/Debug/physicsViewer.js.map +1 -1
  7. package/Engines/Extensions/engine.renderTarget.js +15 -15
  8. package/Engines/Extensions/engine.renderTarget.js.map +1 -1
  9. package/Engines/Extensions/engine.renderTargetCube.d.ts +1 -1
  10. package/Engines/Extensions/engine.renderTargetCube.js.map +1 -1
  11. package/Engines/Extensions/engine.views.d.ts +4 -0
  12. package/Engines/Extensions/engine.views.js +61 -42
  13. package/Engines/Extensions/engine.views.js.map +1 -1
  14. package/Engines/Native/nativeHardwareTexture.d.ts +14 -0
  15. package/Engines/Native/nativeHardwareTexture.js +24 -0
  16. package/Engines/Native/nativeHardwareTexture.js.map +1 -0
  17. package/Engines/Native/nativeInterfaces.d.ts +22 -15
  18. package/Engines/Native/nativeInterfaces.js.map +1 -1
  19. package/Engines/Native/nativePipelineContext.d.ts +252 -0
  20. package/Engines/Native/nativePipelineContext.js +502 -0
  21. package/Engines/Native/nativePipelineContext.js.map +1 -0
  22. package/Engines/Native/nativeRenderTargetWrapper.d.ts +16 -0
  23. package/Engines/Native/nativeRenderTargetWrapper.js +33 -0
  24. package/Engines/Native/nativeRenderTargetWrapper.js.map +1 -0
  25. package/Engines/WebGPU/Extensions/engine.renderTarget.js +3 -3
  26. package/Engines/WebGPU/Extensions/engine.renderTarget.js.map +1 -1
  27. package/Engines/WebGPU/Extensions/engine.renderTargetCube.js.map +1 -1
  28. package/Engines/engine.d.ts +1 -0
  29. package/Engines/engine.js +24 -18
  30. package/Engines/engine.js.map +1 -1
  31. package/Engines/nativeEngine.d.ts +18 -17
  32. package/Engines/nativeEngine.js +100 -598
  33. package/Engines/nativeEngine.js.map +1 -1
  34. package/Engines/nullEngine.d.ts +1 -1
  35. package/Engines/nullEngine.js.map +1 -1
  36. package/Engines/thinEngine.d.ts +1 -1
  37. package/Engines/thinEngine.js +41 -38
  38. package/Engines/thinEngine.js.map +1 -1
  39. package/Engines/webgpuEngine.js.map +1 -1
  40. package/Gizmos/planeRotationGizmo.js +3 -1
  41. package/Gizmos/planeRotationGizmo.js.map +1 -1
  42. package/Inputs/scene.inputManager.js +4 -4
  43. package/Inputs/scene.inputManager.js.map +1 -1
  44. package/Loading/Plugins/babylonFileLoader.js +3 -3
  45. package/Loading/Plugins/babylonFileLoader.js.map +1 -1
  46. package/Materials/Node/Blocks/Dual/textureBlock.js +1 -1
  47. package/Materials/Node/Blocks/Dual/textureBlock.js.map +1 -1
  48. package/Materials/Node/nodeMaterial.d.ts +19 -1
  49. package/Materials/Node/nodeMaterial.js +30 -0
  50. package/Materials/Node/nodeMaterial.js.map +1 -1
  51. package/Materials/Node/nodeMaterialBuildStateSharedData.d.ts +2 -8
  52. package/Materials/Node/nodeMaterialBuildStateSharedData.js.map +1 -1
  53. package/Materials/Textures/baseTexture.d.ts +2 -1
  54. package/Materials/Textures/baseTexture.js +3 -2
  55. package/Materials/Textures/baseTexture.js.map +1 -1
  56. package/Materials/Textures/internalTexture.d.ts +2 -0
  57. package/Materials/Textures/internalTexture.js +4 -0
  58. package/Materials/Textures/internalTexture.js.map +1 -1
  59. package/Materials/Textures/mirrorTexture.js +0 -2
  60. package/Materials/Textures/mirrorTexture.js.map +1 -1
  61. package/Materials/Textures/renderTargetTexture.d.ts +53 -3
  62. package/Materials/Textures/renderTargetTexture.js +25 -25
  63. package/Materials/Textures/renderTargetTexture.js.map +1 -1
  64. package/Materials/Textures/texture.d.ts +2 -0
  65. package/Materials/Textures/texture.js +35 -7
  66. package/Materials/Textures/texture.js.map +1 -1
  67. package/Materials/Textures/textureCreationOptions.d.ts +4 -1
  68. package/Materials/Textures/textureCreationOptions.js.map +1 -1
  69. package/Materials/material.js +1 -1
  70. package/Materials/material.js.map +1 -1
  71. package/Meshes/abstractMesh.d.ts +4 -4
  72. package/Meshes/abstractMesh.js +4 -4
  73. package/Meshes/abstractMesh.js.map +1 -1
  74. package/Meshes/mesh.d.ts +2 -2
  75. package/Meshes/mesh.js +1 -1
  76. package/Meshes/mesh.js.map +1 -1
  77. package/Misc/copyTextureToTexture.d.ts +9 -2
  78. package/Misc/copyTextureToTexture.js +23 -1
  79. package/Misc/copyTextureToTexture.js.map +1 -1
  80. package/Particles/IParticleSystem.d.ts +15 -1
  81. package/Particles/IParticleSystem.js.map +1 -1
  82. package/Particles/gpuParticleSystem.d.ts +24 -2
  83. package/Particles/gpuParticleSystem.js +98 -43
  84. package/Particles/gpuParticleSystem.js.map +1 -1
  85. package/Particles/particleSystem.d.ts +6 -1
  86. package/Particles/particleSystem.js +7 -2
  87. package/Particles/particleSystem.js.map +1 -1
  88. package/Physics/IPhysicsEngine.d.ts +8 -108
  89. package/Physics/IPhysicsEngine.js.map +1 -1
  90. package/Physics/Plugins/ammoJSPlugin.d.ts +1 -389
  91. package/Physics/Plugins/ammoJSPlugin.js +2 -1414
  92. package/Physics/Plugins/ammoJSPlugin.js.map +1 -1
  93. package/Physics/Plugins/cannonJSPlugin.d.ts +1 -75
  94. package/Physics/Plugins/cannonJSPlugin.js +2 -664
  95. package/Physics/Plugins/cannonJSPlugin.js.map +1 -1
  96. package/Physics/Plugins/oimoJSPlugin.d.ts +1 -59
  97. package/Physics/Plugins/oimoJSPlugin.js +2 -432
  98. package/Physics/Plugins/oimoJSPlugin.js.map +1 -1
  99. package/Physics/index.d.ts +3 -6
  100. package/Physics/index.js +3 -6
  101. package/Physics/index.js.map +1 -1
  102. package/Physics/physicsEngine.d.ts +1 -135
  103. package/Physics/physicsEngine.js +2 -221
  104. package/Physics/physicsEngine.js.map +1 -1
  105. package/Physics/physicsEngineComponent.d.ts +7 -42
  106. package/Physics/physicsEngineComponent.js +11 -71
  107. package/Physics/physicsEngineComponent.js.map +1 -1
  108. package/Physics/physicsHelper.d.ts +1 -411
  109. package/Physics/physicsHelper.js +2 -708
  110. package/Physics/physicsHelper.js.map +1 -1
  111. package/Physics/physicsImpostor.d.ts +1 -640
  112. package/Physics/physicsImpostor.js +2 -1004
  113. package/Physics/physicsImpostor.js.map +1 -1
  114. package/Physics/physicsJoint.d.ts +1 -275
  115. package/Physics/physicsJoint.js +2 -222
  116. package/Physics/physicsJoint.js.map +1 -1
  117. package/Physics/v1/IPhysicsEnginePlugin.d.ts +73 -0
  118. package/Physics/v1/IPhysicsEnginePlugin.js +2 -0
  119. package/Physics/v1/IPhysicsEnginePlugin.js.map +1 -0
  120. package/Physics/v1/Plugins/ammoJSPlugin.d.ts +401 -0
  121. package/Physics/v1/Plugins/ammoJSPlugin.js +1431 -0
  122. package/Physics/v1/Plugins/ammoJSPlugin.js.map +1 -0
  123. package/Physics/v1/Plugins/cannonJSPlugin.d.ts +87 -0
  124. package/Physics/v1/Plugins/cannonJSPlugin.js +683 -0
  125. package/Physics/v1/Plugins/cannonJSPlugin.js.map +1 -0
  126. package/Physics/{Plugins → v1/Plugins}/index.d.ts +0 -0
  127. package/Physics/{Plugins → v1/Plugins}/index.js +0 -0
  128. package/Physics/v1/Plugins/index.js.map +1 -0
  129. package/Physics/v1/Plugins/oimoJSPlugin.d.ts +71 -0
  130. package/Physics/v1/Plugins/oimoJSPlugin.js +450 -0
  131. package/Physics/v1/Plugins/oimoJSPlugin.js.map +1 -0
  132. package/Physics/v1/index.d.ts +7 -0
  133. package/Physics/v1/index.js +9 -0
  134. package/Physics/v1/index.js.map +1 -0
  135. package/Physics/v1/physicsEngine.d.ts +147 -0
  136. package/Physics/v1/physicsEngine.js +237 -0
  137. package/Physics/v1/physicsEngine.js.map +1 -0
  138. package/Physics/v1/physicsEngineComponent.d.ts +45 -0
  139. package/Physics/v1/physicsEngineComponent.js +70 -0
  140. package/Physics/v1/physicsEngineComponent.js.map +1 -0
  141. package/Physics/v1/physicsHelper.d.ts +411 -0
  142. package/Physics/v1/physicsHelper.js +709 -0
  143. package/Physics/v1/physicsHelper.js.map +1 -0
  144. package/Physics/v1/physicsImpostor.d.ts +636 -0
  145. package/Physics/v1/physicsImpostor.js +1001 -0
  146. package/Physics/v1/physicsImpostor.js.map +1 -0
  147. package/Physics/v1/physicsJoint.d.ts +275 -0
  148. package/Physics/v1/physicsJoint.js +223 -0
  149. package/Physics/v1/physicsJoint.js.map +1 -0
  150. package/Physics/v2/IPhysicsEnginePlugin.d.ts +170 -0
  151. package/Physics/v2/IPhysicsEnginePlugin.js +47 -0
  152. package/Physics/v2/IPhysicsEnginePlugin.js.map +1 -0
  153. package/Physics/v2/Plugins/index.d.ts +0 -0
  154. package/Physics/v2/Plugins/index.js +2 -0
  155. package/Physics/v2/Plugins/index.js.map +1 -0
  156. package/Physics/v2/index.d.ts +6 -0
  157. package/Physics/v2/index.js +8 -0
  158. package/Physics/v2/index.js.map +1 -0
  159. package/Physics/v2/physicsAggregate.d.ts +114 -0
  160. package/Physics/v2/physicsAggregate.js +46 -0
  161. package/Physics/v2/physicsAggregate.js.map +1 -0
  162. package/Physics/v2/physicsBody.d.ts +109 -0
  163. package/Physics/v2/physicsBody.js +158 -0
  164. package/Physics/v2/physicsBody.js.map +1 -0
  165. package/Physics/v2/physicsConstraint.d.ts +184 -0
  166. package/Physics/v2/physicsConstraint.js +257 -0
  167. package/Physics/v2/physicsConstraint.js.map +1 -0
  168. package/Physics/v2/physicsEngine.d.ts +103 -0
  169. package/Physics/v2/physicsEngine.js +146 -0
  170. package/Physics/v2/physicsEngine.js.map +1 -0
  171. package/Physics/v2/physicsEngineComponent.d.ts +31 -0
  172. package/Physics/v2/physicsEngineComponent.js +50 -0
  173. package/Physics/v2/physicsEngineComponent.js.map +1 -0
  174. package/Physics/v2/physicsMaterial.d.ts +45 -0
  175. package/Physics/v2/physicsMaterial.js +67 -0
  176. package/Physics/v2/physicsMaterial.js.map +1 -0
  177. package/Physics/v2/physicsShape.d.ts +182 -0
  178. package/Physics/v2/physicsShape.js +229 -0
  179. package/Physics/v2/physicsShape.js.map +1 -0
  180. package/PostProcesses/postProcess.d.ts +3 -1
  181. package/PostProcesses/postProcess.js +4 -1
  182. package/PostProcesses/postProcess.js.map +1 -1
  183. package/Rendering/fluidRenderer/fluidRenderer.d.ts +153 -0
  184. package/Rendering/fluidRenderer/fluidRenderer.js +410 -0
  185. package/Rendering/fluidRenderer/fluidRenderer.js.map +1 -0
  186. package/Rendering/fluidRenderer/fluidRenderingDepthTextureCopy.d.ts +13 -0
  187. package/Rendering/fluidRenderer/fluidRenderingDepthTextureCopy.js +31 -0
  188. package/Rendering/fluidRenderer/fluidRenderingDepthTextureCopy.js.map +1 -0
  189. package/Rendering/fluidRenderer/fluidRenderingObject.d.ts +81 -0
  190. package/Rendering/fluidRenderer/fluidRenderingObject.js +180 -0
  191. package/Rendering/fluidRenderer/fluidRenderingObject.js.map +1 -0
  192. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.d.ts +63 -0
  193. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.js +130 -0
  194. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.js.map +1 -0
  195. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.d.ts +64 -0
  196. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js +104 -0
  197. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js.map +1 -0
  198. package/Rendering/fluidRenderer/fluidRenderingTargetRenderer.d.ts +234 -0
  199. package/Rendering/fluidRenderer/fluidRenderingTargetRenderer.js +690 -0
  200. package/Rendering/fluidRenderer/fluidRenderingTargetRenderer.js.map +1 -0
  201. package/Rendering/fluidRenderer/fluidRenderingTextures.d.ts +56 -0
  202. package/Rendering/fluidRenderer/fluidRenderingTextures.js +261 -0
  203. package/Rendering/fluidRenderer/fluidRenderingTextures.js.map +1 -0
  204. package/Rendering/fluidRenderer/index.d.ts +5 -0
  205. package/Rendering/fluidRenderer/index.js +6 -0
  206. package/Rendering/fluidRenderer/index.js.map +1 -0
  207. package/Rendering/index.d.ts +1 -0
  208. package/Rendering/index.js +2 -0
  209. package/Rendering/index.js.map +1 -1
  210. package/Shaders/copyTextureToTexture.fragment.js +4 -1
  211. package/Shaders/copyTextureToTexture.fragment.js.map +1 -1
  212. package/Shaders/fluidRenderingBilateralBlur.fragment.d.ts +5 -0
  213. package/Shaders/fluidRenderingBilateralBlur.fragment.js +9 -0
  214. package/Shaders/fluidRenderingBilateralBlur.fragment.js.map +1 -0
  215. package/Shaders/fluidRenderingParticleDepth.fragment.d.ts +5 -0
  216. package/Shaders/fluidRenderingParticleDepth.fragment.js +17 -0
  217. package/Shaders/fluidRenderingParticleDepth.fragment.js.map +1 -0
  218. package/Shaders/fluidRenderingParticleDepth.vertex.d.ts +5 -0
  219. package/Shaders/fluidRenderingParticleDepth.vertex.js +13 -0
  220. package/Shaders/fluidRenderingParticleDepth.vertex.js.map +1 -0
  221. package/Shaders/fluidRenderingParticleDiffuse.fragment.d.ts +5 -0
  222. package/Shaders/fluidRenderingParticleDiffuse.fragment.js +9 -0
  223. package/Shaders/fluidRenderingParticleDiffuse.fragment.js.map +1 -0
  224. package/Shaders/fluidRenderingParticleDiffuse.vertex.d.ts +5 -0
  225. package/Shaders/fluidRenderingParticleDiffuse.vertex.js +4 -0
  226. package/Shaders/fluidRenderingParticleDiffuse.vertex.js.map +1 -0
  227. package/Shaders/fluidRenderingParticleThickness.fragment.d.ts +5 -0
  228. package/Shaders/fluidRenderingParticleThickness.fragment.js +9 -0
  229. package/Shaders/fluidRenderingParticleThickness.fragment.js.map +1 -0
  230. package/Shaders/fluidRenderingParticleThickness.vertex.d.ts +5 -0
  231. package/Shaders/fluidRenderingParticleThickness.vertex.js +9 -0
  232. package/Shaders/fluidRenderingParticleThickness.vertex.js.map +1 -0
  233. package/Shaders/fluidRenderingRender.fragment.d.ts +5 -0
  234. package/Shaders/fluidRenderingRender.fragment.js +46 -0
  235. package/Shaders/fluidRenderingRender.fragment.js.map +1 -0
  236. package/Shaders/fluidRenderingStandardBlur.fragment.d.ts +5 -0
  237. package/Shaders/fluidRenderingStandardBlur.fragment.js +9 -0
  238. package/Shaders/fluidRenderingStandardBlur.fragment.js.map +1 -0
  239. package/XR/features/WebXRControllerPhysics.d.ts +1 -1
  240. package/XR/features/WebXRControllerPhysics.js +1 -1
  241. package/XR/features/WebXRControllerPhysics.js.map +1 -1
  242. package/XR/features/WebXRHandTracking.js +1 -1
  243. package/XR/features/WebXRHandTracking.js.map +1 -1
  244. package/package.json +1 -1
  245. package/scene.js +6 -1
  246. package/scene.js.map +1 -1
  247. package/sceneComponent.d.ts +3 -0
  248. package/sceneComponent.js +3 -0
  249. package/sceneComponent.js.map +1 -1
  250. package/Physics/Plugins/index.js.map +0 -1
@@ -0,0 +1,1431 @@
1
+ import { Quaternion, Vector3, Matrix } from "../../../Maths/math.vector.js";
2
+ import { Logger } from "../../../Misc/logger.js";
3
+ import { PhysicsImpostor } from "../physicsImpostor.js";
4
+ import { PhysicsJoint } from "../physicsJoint.js";
5
+ import { VertexBuffer } from "../../../Buffers/buffer.js";
6
+ import { VertexData } from "../../../Meshes/mesh.vertexData.js";
7
+ import { ExtrudeShape } from "../../../Meshes/Builders/shapeBuilder.js";
8
+ import { CreateLines } from "../../../Meshes/Builders/linesBuilder.js";
9
+ import { PhysicsRaycastResult } from "../../physicsRaycastResult.js";
10
+ import { Scalar } from "../../../Maths/math.scalar.js";
11
+ import { Epsilon } from "../../../Maths/math.constants.js";
12
+ /**
13
+ * AmmoJS Physics plugin
14
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/physics/usingPhysicsEngine
15
+ * @see https://github.com/kripken/ammo.js/
16
+ */
17
+ export class AmmoJSPlugin {
18
+ /**
19
+ * Initializes the ammoJS plugin
20
+ * @param _useDeltaForWorldStep if the time between frames should be used when calculating physics steps (Default: true)
21
+ * @param ammoInjection can be used to inject your own ammo reference
22
+ * @param overlappingPairCache can be used to specify your own overlapping pair cache
23
+ */
24
+ constructor(_useDeltaForWorldStep = true, ammoInjection = Ammo, overlappingPairCache = null) {
25
+ this._useDeltaForWorldStep = _useDeltaForWorldStep;
26
+ /**
27
+ * Reference to the Ammo library
28
+ */
29
+ this.bjsAMMO = {};
30
+ /**
31
+ * Name of the plugin
32
+ */
33
+ this.name = "AmmoJSPlugin";
34
+ this._timeStep = 1 / 60;
35
+ this._fixedTimeStep = 1 / 60;
36
+ this._maxSteps = 5;
37
+ this._tmpQuaternion = new Quaternion();
38
+ this._tmpContactCallbackResult = false;
39
+ this._tmpContactPoint = new Vector3();
40
+ this._tmpContactNormal = new Vector3();
41
+ this._tmpVec3 = new Vector3();
42
+ this._tmpMatrix = new Matrix();
43
+ if (typeof ammoInjection === "function") {
44
+ Logger.Error("AmmoJS is not ready. Please make sure you await Ammo() before using the plugin.");
45
+ return;
46
+ }
47
+ else {
48
+ this.bjsAMMO = ammoInjection;
49
+ }
50
+ if (!this.isSupported()) {
51
+ Logger.Error("AmmoJS is not available. Please make sure you included the js file.");
52
+ return;
53
+ }
54
+ // Initialize the physics world
55
+ this._collisionConfiguration = new this.bjsAMMO.btSoftBodyRigidBodyCollisionConfiguration();
56
+ this._dispatcher = new this.bjsAMMO.btCollisionDispatcher(this._collisionConfiguration);
57
+ this._overlappingPairCache = overlappingPairCache || new this.bjsAMMO.btDbvtBroadphase();
58
+ this._solver = new this.bjsAMMO.btSequentialImpulseConstraintSolver();
59
+ this._softBodySolver = new this.bjsAMMO.btDefaultSoftBodySolver();
60
+ this.world = new this.bjsAMMO.btSoftRigidDynamicsWorld(this._dispatcher, this._overlappingPairCache, this._solver, this._collisionConfiguration, this._softBodySolver);
61
+ this._tmpAmmoConcreteContactResultCallback = new this.bjsAMMO.ConcreteContactResultCallback();
62
+ this._tmpAmmoConcreteContactResultCallback.addSingleResult = (contactPoint) => {
63
+ contactPoint = this.bjsAMMO.wrapPointer(contactPoint, this.bjsAMMO.btManifoldPoint);
64
+ const worldPoint = contactPoint.getPositionWorldOnA();
65
+ const worldNormal = contactPoint.m_normalWorldOnB;
66
+ this._tmpContactPoint.x = worldPoint.x();
67
+ this._tmpContactPoint.y = worldPoint.y();
68
+ this._tmpContactPoint.z = worldPoint.z();
69
+ this._tmpContactNormal.x = worldNormal.x();
70
+ this._tmpContactNormal.y = worldNormal.y();
71
+ this._tmpContactNormal.z = worldNormal.z();
72
+ this._tmpContactImpulse = contactPoint.getAppliedImpulse();
73
+ this._tmpContactDistance = contactPoint.getDistance();
74
+ this._tmpContactCallbackResult = true;
75
+ };
76
+ this._raycastResult = new PhysicsRaycastResult();
77
+ // Create temp ammo variables
78
+ this._tmpAmmoTransform = new this.bjsAMMO.btTransform();
79
+ this._tmpAmmoTransform.setIdentity();
80
+ this._tmpAmmoQuaternion = new this.bjsAMMO.btQuaternion(0, 0, 0, 1);
81
+ this._tmpAmmoVectorA = new this.bjsAMMO.btVector3(0, 0, 0);
82
+ this._tmpAmmoVectorB = new this.bjsAMMO.btVector3(0, 0, 0);
83
+ this._tmpAmmoVectorC = new this.bjsAMMO.btVector3(0, 0, 0);
84
+ this._tmpAmmoVectorD = new this.bjsAMMO.btVector3(0, 0, 0);
85
+ }
86
+ /**
87
+ *
88
+ * @returns plugin version
89
+ */
90
+ getPluginVersion() {
91
+ return 1;
92
+ }
93
+ /**
94
+ * Sets the gravity of the physics world (m/(s^2))
95
+ * @param gravity Gravity to set
96
+ */
97
+ setGravity(gravity) {
98
+ this._tmpAmmoVectorA.setValue(gravity.x, gravity.y, gravity.z);
99
+ this.world.setGravity(this._tmpAmmoVectorA);
100
+ this.world.getWorldInfo().set_m_gravity(this._tmpAmmoVectorA);
101
+ }
102
+ /**
103
+ * Amount of time to step forward on each frame (only used if useDeltaForWorldStep is false in the constructor)
104
+ * @param timeStep timestep to use in seconds
105
+ */
106
+ setTimeStep(timeStep) {
107
+ this._timeStep = timeStep;
108
+ }
109
+ /**
110
+ * Increment to step forward in the physics engine (If timeStep is set to 1/60 and fixedTimeStep is set to 1/120 the physics engine should run 2 steps per frame) (Default: 1/60)
111
+ * @param fixedTimeStep fixedTimeStep to use in seconds
112
+ */
113
+ setFixedTimeStep(fixedTimeStep) {
114
+ this._fixedTimeStep = fixedTimeStep;
115
+ }
116
+ /**
117
+ * Sets the maximum number of steps by the physics engine per frame (Default: 5)
118
+ * @param maxSteps the maximum number of steps by the physics engine per frame
119
+ */
120
+ setMaxSteps(maxSteps) {
121
+ this._maxSteps = maxSteps;
122
+ }
123
+ /**
124
+ * Gets the current timestep (only used if useDeltaForWorldStep is false in the constructor)
125
+ * @returns the current timestep in seconds
126
+ */
127
+ getTimeStep() {
128
+ return this._timeStep;
129
+ }
130
+ // Ammo's contactTest and contactPairTest take a callback that runs synchronously, wrap them so that they are easier to consume
131
+ _isImpostorInContact(impostor) {
132
+ this._tmpContactCallbackResult = false;
133
+ this.world.contactTest(impostor.physicsBody, this._tmpAmmoConcreteContactResultCallback);
134
+ return this._tmpContactCallbackResult;
135
+ }
136
+ // Ammo's collision events have some weird quirks
137
+ // contactPairTest fires too many events as it fires events even when objects are close together but contactTest does not
138
+ // so only fire event if both contactTest and contactPairTest have a hit
139
+ _isImpostorPairInContact(impostorA, impostorB) {
140
+ this._tmpContactCallbackResult = false;
141
+ this.world.contactPairTest(impostorA.physicsBody, impostorB.physicsBody, this._tmpAmmoConcreteContactResultCallback);
142
+ return this._tmpContactCallbackResult;
143
+ }
144
+ // Ammo's behavior when maxSteps > 0 does not behave as described in docs
145
+ // @see http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
146
+ //
147
+ // When maxSteps is 0 do the entire simulation in one step
148
+ // When maxSteps is > 0, run up to maxStep times, if on the last step the (remaining step - fixedTimeStep) is < fixedTimeStep, the remainder will be used for the step. (eg. if remainder is 1.001 and fixedTimeStep is 1 the last step will be 1.001, if instead it did 2 steps (1, 0.001) issues occuered when having a tiny step in ammo)
149
+ // Note: To get deterministic physics, timeStep would always need to be divisible by fixedTimeStep
150
+ _stepSimulation(timeStep = 1 / 60, maxSteps = 10, fixedTimeStep = 1 / 60) {
151
+ if (maxSteps == 0) {
152
+ this.world.stepSimulation(timeStep, 0);
153
+ }
154
+ else {
155
+ while (maxSteps > 0 && timeStep > 0) {
156
+ if (timeStep - fixedTimeStep < fixedTimeStep) {
157
+ this.world.stepSimulation(timeStep, 0);
158
+ timeStep = 0;
159
+ }
160
+ else {
161
+ timeStep -= fixedTimeStep;
162
+ this.world.stepSimulation(fixedTimeStep, 0);
163
+ }
164
+ maxSteps--;
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Moves the physics simulation forward delta seconds and updates the given physics imposters
170
+ * Prior to the step the imposters physics location is set to the position of the babylon meshes
171
+ * After the step the babylon meshes are set to the position of the physics imposters
172
+ * @param delta amount of time to step forward
173
+ * @param impostors array of imposters to update before/after the step
174
+ */
175
+ executeStep(delta, impostors) {
176
+ for (const impostor of impostors) {
177
+ // Update physics world objects to match babylon world
178
+ if (!impostor.soft) {
179
+ impostor.beforeStep();
180
+ }
181
+ }
182
+ this._stepSimulation(this._useDeltaForWorldStep ? delta : this._timeStep, this._maxSteps, this._fixedTimeStep);
183
+ for (const mainImpostor of impostors) {
184
+ // After physics update make babylon world objects match physics world objects
185
+ if (mainImpostor.soft) {
186
+ this._afterSoftStep(mainImpostor);
187
+ }
188
+ else {
189
+ mainImpostor.afterStep();
190
+ }
191
+ // Handle collision event
192
+ if (mainImpostor._onPhysicsCollideCallbacks.length > 0) {
193
+ if (this._isImpostorInContact(mainImpostor)) {
194
+ for (const collideCallback of mainImpostor._onPhysicsCollideCallbacks) {
195
+ for (const otherImpostor of collideCallback.otherImpostors) {
196
+ if (mainImpostor.physicsBody.isActive() || otherImpostor.physicsBody.isActive()) {
197
+ if (this._isImpostorPairInContact(mainImpostor, otherImpostor)) {
198
+ mainImpostor.onCollide({
199
+ body: otherImpostor.physicsBody,
200
+ point: this._tmpContactPoint,
201
+ distance: this._tmpContactDistance,
202
+ impulse: this._tmpContactImpulse,
203
+ normal: this._tmpContactNormal,
204
+ });
205
+ otherImpostor.onCollide({
206
+ body: mainImpostor.physicsBody,
207
+ point: this._tmpContactPoint,
208
+ distance: this._tmpContactDistance,
209
+ impulse: this._tmpContactImpulse,
210
+ normal: this._tmpContactNormal,
211
+ });
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ /**
221
+ * Update babylon mesh to match physics world object
222
+ * @param impostor imposter to match
223
+ */
224
+ _afterSoftStep(impostor) {
225
+ if (impostor.type === PhysicsImpostor.RopeImpostor) {
226
+ this._ropeStep(impostor);
227
+ }
228
+ else {
229
+ this._softbodyOrClothStep(impostor);
230
+ }
231
+ }
232
+ /**
233
+ * Update babylon mesh vertices vertices to match physics world softbody or cloth
234
+ * @param impostor imposter to match
235
+ */
236
+ _ropeStep(impostor) {
237
+ const bodyVertices = impostor.physicsBody.get_m_nodes();
238
+ const nbVertices = bodyVertices.size();
239
+ let node;
240
+ let nodePositions;
241
+ let x, y, z;
242
+ const path = new Array();
243
+ for (let n = 0; n < nbVertices; n++) {
244
+ node = bodyVertices.at(n);
245
+ nodePositions = node.get_m_x();
246
+ x = nodePositions.x();
247
+ y = nodePositions.y();
248
+ z = nodePositions.z();
249
+ path.push(new Vector3(x, y, z));
250
+ }
251
+ const object = impostor.object;
252
+ const shape = impostor.getParam("shape");
253
+ if (impostor._isFromLine) {
254
+ impostor.object = CreateLines("lines", { points: path, instance: object });
255
+ }
256
+ else {
257
+ impostor.object = ExtrudeShape("ext", { shape: shape, path: path, instance: object });
258
+ }
259
+ }
260
+ /**
261
+ * Update babylon mesh vertices vertices to match physics world softbody or cloth
262
+ * @param impostor imposter to match
263
+ */
264
+ _softbodyOrClothStep(impostor) {
265
+ const normalDirection = impostor.type === PhysicsImpostor.ClothImpostor ? 1 : -1;
266
+ const object = impostor.object;
267
+ let vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
268
+ if (!vertexPositions) {
269
+ vertexPositions = [];
270
+ }
271
+ let vertexNormals = object.getVerticesData(VertexBuffer.NormalKind);
272
+ if (!vertexNormals) {
273
+ vertexNormals = [];
274
+ }
275
+ const nbVertices = vertexPositions.length / 3;
276
+ const bodyVertices = impostor.physicsBody.get_m_nodes();
277
+ let node;
278
+ let nodePositions;
279
+ let x, y, z;
280
+ let nx, ny, nz;
281
+ for (let n = 0; n < nbVertices; n++) {
282
+ node = bodyVertices.at(n);
283
+ nodePositions = node.get_m_x();
284
+ x = nodePositions.x();
285
+ y = nodePositions.y();
286
+ z = nodePositions.z() * normalDirection;
287
+ const nodeNormals = node.get_m_n();
288
+ nx = nodeNormals.x();
289
+ ny = nodeNormals.y();
290
+ nz = nodeNormals.z() * normalDirection;
291
+ vertexPositions[3 * n] = x;
292
+ vertexPositions[3 * n + 1] = y;
293
+ vertexPositions[3 * n + 2] = z;
294
+ vertexNormals[3 * n] = nx;
295
+ vertexNormals[3 * n + 1] = ny;
296
+ vertexNormals[3 * n + 2] = nz;
297
+ }
298
+ const vertex_data = new VertexData();
299
+ vertex_data.positions = vertexPositions;
300
+ vertex_data.normals = vertexNormals;
301
+ vertex_data.uvs = object.getVerticesData(VertexBuffer.UVKind);
302
+ vertex_data.colors = object.getVerticesData(VertexBuffer.ColorKind);
303
+ if (object && object.getIndices) {
304
+ vertex_data.indices = object.getIndices();
305
+ }
306
+ vertex_data.applyToMesh(object);
307
+ }
308
+ /**
309
+ * Applies an impulse on the imposter
310
+ * @param impostor imposter to apply impulse to
311
+ * @param force amount of force to be applied to the imposter
312
+ * @param contactPoint the location to apply the impulse on the imposter
313
+ */
314
+ applyImpulse(impostor, force, contactPoint) {
315
+ if (!impostor.soft) {
316
+ impostor.physicsBody.activate();
317
+ const worldPoint = this._tmpAmmoVectorA;
318
+ const impulse = this._tmpAmmoVectorB;
319
+ // Convert contactPoint relative to center of mass
320
+ if (impostor.object && impostor.object.getWorldMatrix) {
321
+ contactPoint.subtractInPlace(impostor.object.getWorldMatrix().getTranslation());
322
+ }
323
+ worldPoint.setValue(contactPoint.x, contactPoint.y, contactPoint.z);
324
+ impulse.setValue(force.x, force.y, force.z);
325
+ impostor.physicsBody.applyImpulse(impulse, worldPoint);
326
+ }
327
+ else {
328
+ Logger.Warn("Cannot be applied to a soft body");
329
+ }
330
+ }
331
+ /**
332
+ * Applies a force on the imposter
333
+ * @param impostor imposter to apply force
334
+ * @param force amount of force to be applied to the imposter
335
+ * @param contactPoint the location to apply the force on the imposter
336
+ */
337
+ applyForce(impostor, force, contactPoint) {
338
+ if (!impostor.soft) {
339
+ impostor.physicsBody.activate();
340
+ const worldPoint = this._tmpAmmoVectorA;
341
+ const impulse = this._tmpAmmoVectorB;
342
+ // Convert contactPoint relative to center of mass
343
+ if (impostor.object && impostor.object.getWorldMatrix) {
344
+ const localTranslation = impostor.object.getWorldMatrix().getTranslation();
345
+ worldPoint.setValue(contactPoint.x - localTranslation.x, contactPoint.y - localTranslation.y, contactPoint.z - localTranslation.z);
346
+ }
347
+ else {
348
+ worldPoint.setValue(contactPoint.x, contactPoint.y, contactPoint.z);
349
+ }
350
+ impulse.setValue(force.x, force.y, force.z);
351
+ impostor.physicsBody.applyForce(impulse, worldPoint);
352
+ }
353
+ else {
354
+ Logger.Warn("Cannot be applied to a soft body");
355
+ }
356
+ }
357
+ /**
358
+ * Creates a physics body using the plugin
359
+ * @param impostor the imposter to create the physics body on
360
+ */
361
+ generatePhysicsBody(impostor) {
362
+ // Note: this method will not be called on child imposotrs for compound impostors
363
+ impostor._pluginData.toDispose = [];
364
+ //parent-child relationship
365
+ if (impostor.parent) {
366
+ if (impostor.physicsBody) {
367
+ this.removePhysicsBody(impostor);
368
+ impostor.forceUpdate();
369
+ }
370
+ return;
371
+ }
372
+ if (impostor.isBodyInitRequired()) {
373
+ const colShape = this._createShape(impostor);
374
+ const mass = impostor.getParam("mass");
375
+ impostor._pluginData.mass = mass;
376
+ if (impostor.soft) {
377
+ colShape.get_m_cfg().set_collisions(0x11);
378
+ colShape.get_m_cfg().set_kDP(impostor.getParam("damping"));
379
+ this.bjsAMMO.castObject(colShape, this.bjsAMMO.btCollisionObject).getCollisionShape().setMargin(impostor.getParam("margin"));
380
+ colShape.setActivationState(AmmoJSPlugin._DISABLE_DEACTIVATION_FLAG);
381
+ this.world.addSoftBody(colShape, 1, -1);
382
+ impostor.physicsBody = colShape;
383
+ impostor._pluginData.toDispose.push(colShape);
384
+ this.setBodyPressure(impostor, 0);
385
+ if (impostor.type === PhysicsImpostor.SoftbodyImpostor) {
386
+ this.setBodyPressure(impostor, impostor.getParam("pressure"));
387
+ }
388
+ this.setBodyStiffness(impostor, impostor.getParam("stiffness"));
389
+ this.setBodyVelocityIterations(impostor, impostor.getParam("velocityIterations"));
390
+ this.setBodyPositionIterations(impostor, impostor.getParam("positionIterations"));
391
+ }
392
+ else {
393
+ const localInertia = new this.bjsAMMO.btVector3(0, 0, 0);
394
+ const startTransform = new this.bjsAMMO.btTransform();
395
+ impostor.object.computeWorldMatrix(true);
396
+ startTransform.setIdentity();
397
+ if (mass !== 0) {
398
+ colShape.calculateLocalInertia(mass, localInertia);
399
+ }
400
+ this._tmpAmmoVectorA.setValue(impostor.object.position.x, impostor.object.position.y, impostor.object.position.z);
401
+ this._tmpAmmoQuaternion.setValue(impostor.object.rotationQuaternion.x, impostor.object.rotationQuaternion.y, impostor.object.rotationQuaternion.z, impostor.object.rotationQuaternion.w);
402
+ startTransform.setOrigin(this._tmpAmmoVectorA);
403
+ startTransform.setRotation(this._tmpAmmoQuaternion);
404
+ const myMotionState = new this.bjsAMMO.btDefaultMotionState(startTransform);
405
+ const rbInfo = new this.bjsAMMO.btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
406
+ const body = new this.bjsAMMO.btRigidBody(rbInfo);
407
+ // Make objects kinematic if it's mass is 0
408
+ if (mass === 0) {
409
+ body.setCollisionFlags(body.getCollisionFlags() | AmmoJSPlugin._KINEMATIC_FLAG);
410
+ body.setActivationState(AmmoJSPlugin._DISABLE_DEACTIVATION_FLAG);
411
+ }
412
+ // Disable collision if NoImpostor, but keep collision if shape is btCompoundShape
413
+ if (impostor.type == PhysicsImpostor.NoImpostor && !colShape.getChildShape) {
414
+ body.setCollisionFlags(body.getCollisionFlags() | AmmoJSPlugin._DISABLE_COLLISION_FLAG);
415
+ }
416
+ // compute delta position: compensate the difference between shape center and mesh origin
417
+ if (impostor.type !== PhysicsImpostor.MeshImpostor && impostor.type !== PhysicsImpostor.NoImpostor) {
418
+ const boundingInfo = impostor.object.getBoundingInfo();
419
+ this._tmpVec3.copyFrom(impostor.object.getAbsolutePosition());
420
+ this._tmpVec3.subtractInPlace(boundingInfo.boundingBox.centerWorld);
421
+ this._tmpVec3.x /= impostor.object.scaling.x;
422
+ this._tmpVec3.y /= impostor.object.scaling.y;
423
+ this._tmpVec3.z /= impostor.object.scaling.z;
424
+ impostor.setDeltaPosition(this._tmpVec3);
425
+ }
426
+ const group = impostor.getParam("group");
427
+ const mask = impostor.getParam("mask");
428
+ if (group && mask) {
429
+ this.world.addRigidBody(body, group, mask);
430
+ }
431
+ else {
432
+ this.world.addRigidBody(body);
433
+ }
434
+ impostor.physicsBody = body;
435
+ impostor._pluginData.toDispose = impostor._pluginData.toDispose.concat([body, rbInfo, myMotionState, startTransform, localInertia, colShape]);
436
+ }
437
+ this.setBodyRestitution(impostor, impostor.getParam("restitution"));
438
+ this.setBodyFriction(impostor, impostor.getParam("friction"));
439
+ }
440
+ }
441
+ /**
442
+ * Removes the physics body from the imposter and disposes of the body's memory
443
+ * @param impostor imposter to remove the physics body from
444
+ */
445
+ removePhysicsBody(impostor) {
446
+ if (this.world) {
447
+ if (impostor.soft) {
448
+ this.world.removeSoftBody(impostor.physicsBody);
449
+ }
450
+ else {
451
+ this.world.removeRigidBody(impostor.physicsBody);
452
+ }
453
+ if (impostor._pluginData) {
454
+ impostor._pluginData.toDispose.forEach((d) => {
455
+ this.bjsAMMO.destroy(d);
456
+ });
457
+ impostor._pluginData.toDispose = [];
458
+ }
459
+ }
460
+ }
461
+ /**
462
+ * Generates a joint
463
+ * @param impostorJoint the imposter joint to create the joint with
464
+ */
465
+ generateJoint(impostorJoint) {
466
+ const mainBody = impostorJoint.mainImpostor.physicsBody;
467
+ const connectedBody = impostorJoint.connectedImpostor.physicsBody;
468
+ if (!mainBody || !connectedBody) {
469
+ return;
470
+ }
471
+ const jointData = impostorJoint.joint.jointData;
472
+ if (!jointData.mainPivot) {
473
+ jointData.mainPivot = new Vector3(0, 0, 0);
474
+ }
475
+ if (!jointData.connectedPivot) {
476
+ jointData.connectedPivot = new Vector3(0, 0, 0);
477
+ }
478
+ let joint;
479
+ switch (impostorJoint.joint.type) {
480
+ case PhysicsJoint.DistanceJoint: {
481
+ const distance = jointData.maxDistance;
482
+ if (distance) {
483
+ jointData.mainPivot = new Vector3(0, -distance / 2, 0);
484
+ jointData.connectedPivot = new Vector3(0, distance / 2, 0);
485
+ }
486
+ joint = new this.bjsAMMO.btPoint2PointConstraint(mainBody, connectedBody, new this.bjsAMMO.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new this.bjsAMMO.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
487
+ break;
488
+ }
489
+ case PhysicsJoint.HingeJoint: {
490
+ if (!jointData.mainAxis) {
491
+ jointData.mainAxis = new Vector3(0, 0, 0);
492
+ }
493
+ if (!jointData.connectedAxis) {
494
+ jointData.connectedAxis = new Vector3(0, 0, 0);
495
+ }
496
+ const mainAxis = new this.bjsAMMO.btVector3(jointData.mainAxis.x, jointData.mainAxis.y, jointData.mainAxis.z);
497
+ const connectedAxis = new this.bjsAMMO.btVector3(jointData.connectedAxis.x, jointData.connectedAxis.y, jointData.connectedAxis.z);
498
+ joint = new this.bjsAMMO.btHingeConstraint(mainBody, connectedBody, new this.bjsAMMO.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new this.bjsAMMO.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z), mainAxis, connectedAxis);
499
+ break;
500
+ }
501
+ case PhysicsJoint.BallAndSocketJoint:
502
+ joint = new this.bjsAMMO.btPoint2PointConstraint(mainBody, connectedBody, new this.bjsAMMO.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new this.bjsAMMO.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
503
+ break;
504
+ default:
505
+ Logger.Warn("JointType not currently supported by the Ammo plugin, falling back to PhysicsJoint.BallAndSocketJoint");
506
+ joint = new this.bjsAMMO.btPoint2PointConstraint(mainBody, connectedBody, new this.bjsAMMO.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new this.bjsAMMO.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
507
+ break;
508
+ }
509
+ this.world.addConstraint(joint, !impostorJoint.joint.jointData.collision);
510
+ impostorJoint.joint.physicsJoint = joint;
511
+ }
512
+ /**
513
+ * Removes a joint
514
+ * @param impostorJoint the imposter joint to remove the joint from
515
+ */
516
+ removeJoint(impostorJoint) {
517
+ if (this.world) {
518
+ this.world.removeConstraint(impostorJoint.joint.physicsJoint);
519
+ }
520
+ }
521
+ // adds all verticies (including child verticies) to the triangle mesh
522
+ _addMeshVerts(btTriangleMesh, topLevelObject, object) {
523
+ let triangleCount = 0;
524
+ if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
525
+ let indices = object.getIndices();
526
+ if (!indices) {
527
+ indices = [];
528
+ }
529
+ let vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
530
+ if (!vertexPositions) {
531
+ vertexPositions = [];
532
+ }
533
+ let localMatrix;
534
+ if (topLevelObject && topLevelObject !== object) {
535
+ // top level matrix used for shape transform doesn't take scale into account.
536
+ // Moreover, every children vertex position must be in that space.
537
+ // So, each vertex position here is transform by (mesh world matrix * toplevelMatrix -1)
538
+ let topLevelQuaternion;
539
+ if (topLevelObject.rotationQuaternion) {
540
+ topLevelQuaternion = topLevelObject.rotationQuaternion;
541
+ }
542
+ else if (topLevelObject.rotation) {
543
+ topLevelQuaternion = Quaternion.FromEulerAngles(topLevelObject.rotation.x, topLevelObject.rotation.y, topLevelObject.rotation.z);
544
+ }
545
+ else {
546
+ topLevelQuaternion = Quaternion.Identity();
547
+ }
548
+ const topLevelMatrix = Matrix.Compose(Vector3.One(), topLevelQuaternion, topLevelObject.position);
549
+ topLevelMatrix.invertToRef(this._tmpMatrix);
550
+ const wm = object.computeWorldMatrix(false);
551
+ localMatrix = wm.multiply(this._tmpMatrix);
552
+ }
553
+ else {
554
+ // current top level is same as object level -> only use local scaling
555
+ Matrix.ScalingToRef(object.scaling.x, object.scaling.y, object.scaling.z, this._tmpMatrix);
556
+ localMatrix = this._tmpMatrix;
557
+ }
558
+ const faceCount = indices.length / 3;
559
+ for (let i = 0; i < faceCount; i++) {
560
+ const triPoints = [];
561
+ for (let point = 0; point < 3; point++) {
562
+ let v = new Vector3(vertexPositions[indices[i * 3 + point] * 3 + 0], vertexPositions[indices[i * 3 + point] * 3 + 1], vertexPositions[indices[i * 3 + point] * 3 + 2]);
563
+ v = Vector3.TransformCoordinates(v, localMatrix);
564
+ let vec;
565
+ if (point == 0) {
566
+ vec = this._tmpAmmoVectorA;
567
+ }
568
+ else if (point == 1) {
569
+ vec = this._tmpAmmoVectorB;
570
+ }
571
+ else {
572
+ vec = this._tmpAmmoVectorC;
573
+ }
574
+ vec.setValue(v.x, v.y, v.z);
575
+ triPoints.push(vec);
576
+ }
577
+ btTriangleMesh.addTriangle(triPoints[0], triPoints[1], triPoints[2]);
578
+ triangleCount++;
579
+ }
580
+ object.getChildMeshes().forEach((m) => {
581
+ triangleCount += this._addMeshVerts(btTriangleMesh, topLevelObject, m);
582
+ });
583
+ }
584
+ return triangleCount;
585
+ }
586
+ /**
587
+ * Initialise the soft body vertices to match its object's (mesh) vertices
588
+ * Softbody vertices (nodes) are in world space and to match this
589
+ * The object's position and rotation is set to zero and so its vertices are also then set in world space
590
+ * @param impostor to create the softbody for
591
+ */
592
+ _softVertexData(impostor) {
593
+ const object = impostor.object;
594
+ if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
595
+ let indices = object.getIndices();
596
+ if (!indices) {
597
+ indices = [];
598
+ }
599
+ let vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
600
+ if (!vertexPositions) {
601
+ vertexPositions = [];
602
+ }
603
+ let vertexNormals = object.getVerticesData(VertexBuffer.NormalKind);
604
+ if (!vertexNormals) {
605
+ vertexNormals = [];
606
+ }
607
+ object.computeWorldMatrix(false);
608
+ const newPoints = [];
609
+ const newNorms = [];
610
+ for (let i = 0; i < vertexPositions.length; i += 3) {
611
+ let v = new Vector3(vertexPositions[i], vertexPositions[i + 1], vertexPositions[i + 2]);
612
+ let n = new Vector3(vertexNormals[i], vertexNormals[i + 1], vertexNormals[i + 2]);
613
+ v = Vector3.TransformCoordinates(v, object.getWorldMatrix());
614
+ n = Vector3.TransformNormal(n, object.getWorldMatrix());
615
+ newPoints.push(v.x, v.y, v.z);
616
+ newNorms.push(n.x, n.y, n.z);
617
+ }
618
+ const vertex_data = new VertexData();
619
+ vertex_data.positions = newPoints;
620
+ vertex_data.normals = newNorms;
621
+ vertex_data.uvs = object.getVerticesData(VertexBuffer.UVKind);
622
+ vertex_data.colors = object.getVerticesData(VertexBuffer.ColorKind);
623
+ if (object && object.getIndices) {
624
+ vertex_data.indices = object.getIndices();
625
+ }
626
+ vertex_data.applyToMesh(object);
627
+ object.position = Vector3.Zero();
628
+ object.rotationQuaternion = null;
629
+ object.rotation = Vector3.Zero();
630
+ object.computeWorldMatrix(true);
631
+ return vertex_data;
632
+ }
633
+ return VertexData.ExtractFromMesh(object);
634
+ }
635
+ /**
636
+ * Create an impostor's soft body
637
+ * @param impostor to create the softbody for
638
+ */
639
+ _createSoftbody(impostor) {
640
+ const object = impostor.object;
641
+ if (object && object.getIndices) {
642
+ let indices = object.getIndices();
643
+ if (!indices) {
644
+ indices = [];
645
+ }
646
+ const vertex_data = this._softVertexData(impostor);
647
+ const vertexPositions = vertex_data.positions;
648
+ const vertexNormals = vertex_data.normals;
649
+ if (vertexPositions === null || vertexNormals === null) {
650
+ return new this.bjsAMMO.btCompoundShape();
651
+ }
652
+ else {
653
+ const triPoints = [];
654
+ const triNorms = [];
655
+ for (let i = 0; i < vertexPositions.length; i += 3) {
656
+ const v = new Vector3(vertexPositions[i], vertexPositions[i + 1], vertexPositions[i + 2]);
657
+ const n = new Vector3(vertexNormals[i], vertexNormals[i + 1], vertexNormals[i + 2]);
658
+ triPoints.push(v.x, v.y, -v.z);
659
+ triNorms.push(n.x, n.y, -n.z);
660
+ }
661
+ const softBody = new this.bjsAMMO.btSoftBodyHelpers().CreateFromTriMesh(this.world.getWorldInfo(), triPoints, object.getIndices(), indices.length / 3, true);
662
+ const nbVertices = vertexPositions.length / 3;
663
+ const bodyVertices = softBody.get_m_nodes();
664
+ let node;
665
+ let nodeNormals;
666
+ for (let i = 0; i < nbVertices; i++) {
667
+ node = bodyVertices.at(i);
668
+ nodeNormals = node.get_m_n();
669
+ nodeNormals.setX(triNorms[3 * i]);
670
+ nodeNormals.setY(triNorms[3 * i + 1]);
671
+ nodeNormals.setZ(triNorms[3 * i + 2]);
672
+ }
673
+ return softBody;
674
+ }
675
+ }
676
+ }
677
+ /**
678
+ * Create cloth for an impostor
679
+ * @param impostor to create the softbody for
680
+ */
681
+ _createCloth(impostor) {
682
+ const object = impostor.object;
683
+ if (object && object.getIndices) {
684
+ let indices = object.getIndices();
685
+ if (!indices) {
686
+ indices = [];
687
+ }
688
+ const vertex_data = this._softVertexData(impostor);
689
+ const vertexPositions = vertex_data.positions;
690
+ const vertexNormals = vertex_data.normals;
691
+ if (vertexPositions === null || vertexNormals === null) {
692
+ return new this.bjsAMMO.btCompoundShape();
693
+ }
694
+ else {
695
+ const len = vertexPositions.length;
696
+ const segments = Math.sqrt(len / 3);
697
+ impostor.segments = segments;
698
+ const segs = segments - 1;
699
+ this._tmpAmmoVectorA.setValue(vertexPositions[0], vertexPositions[1], vertexPositions[2]);
700
+ this._tmpAmmoVectorB.setValue(vertexPositions[3 * segs], vertexPositions[3 * segs + 1], vertexPositions[3 * segs + 2]);
701
+ this._tmpAmmoVectorD.setValue(vertexPositions[len - 3], vertexPositions[len - 2], vertexPositions[len - 1]);
702
+ this._tmpAmmoVectorC.setValue(vertexPositions[len - 3 - 3 * segs], vertexPositions[len - 2 - 3 * segs], vertexPositions[len - 1 - 3 * segs]);
703
+ const clothBody = new this.bjsAMMO.btSoftBodyHelpers().CreatePatch(this.world.getWorldInfo(), this._tmpAmmoVectorA, this._tmpAmmoVectorB, this._tmpAmmoVectorC, this._tmpAmmoVectorD, segments, segments, impostor.getParam("fixedPoints"), true);
704
+ return clothBody;
705
+ }
706
+ }
707
+ }
708
+ /**
709
+ * Create rope for an impostor
710
+ * @param impostor to create the softbody for
711
+ */
712
+ _createRope(impostor) {
713
+ let len;
714
+ let segments;
715
+ const vertex_data = this._softVertexData(impostor);
716
+ const vertexPositions = vertex_data.positions;
717
+ const vertexNormals = vertex_data.normals;
718
+ if (vertexPositions === null || vertexNormals === null) {
719
+ return new this.bjsAMMO.btCompoundShape();
720
+ }
721
+ //force the mesh to be updatable
722
+ vertex_data.applyToMesh(impostor.object, true);
723
+ impostor._isFromLine = true;
724
+ // If in lines mesh all normals will be zero
725
+ const vertexSquared = vertexNormals.map((x) => x * x);
726
+ const reducer = (accumulator, currentValue) => accumulator + currentValue;
727
+ const reduced = vertexSquared.reduce(reducer);
728
+ if (reduced === 0) {
729
+ // line mesh
730
+ len = vertexPositions.length;
731
+ segments = len / 3 - 1;
732
+ this._tmpAmmoVectorA.setValue(vertexPositions[0], vertexPositions[1], vertexPositions[2]);
733
+ this._tmpAmmoVectorB.setValue(vertexPositions[len - 3], vertexPositions[len - 2], vertexPositions[len - 1]);
734
+ }
735
+ else {
736
+ //extruded mesh
737
+ impostor._isFromLine = false;
738
+ const pathVectors = impostor.getParam("path");
739
+ const shape = impostor.getParam("shape");
740
+ if (shape === null) {
741
+ Logger.Warn("No shape available for extruded mesh");
742
+ return new this.bjsAMMO.btCompoundShape();
743
+ }
744
+ len = pathVectors.length;
745
+ segments = len - 1;
746
+ this._tmpAmmoVectorA.setValue(pathVectors[0].x, pathVectors[0].y, pathVectors[0].z);
747
+ this._tmpAmmoVectorB.setValue(pathVectors[len - 1].x, pathVectors[len - 1].y, pathVectors[len - 1].z);
748
+ }
749
+ impostor.segments = segments;
750
+ let fixedPoints = impostor.getParam("fixedPoints");
751
+ fixedPoints = fixedPoints > 3 ? 3 : fixedPoints;
752
+ const ropeBody = new this.bjsAMMO.btSoftBodyHelpers().CreateRope(this.world.getWorldInfo(), this._tmpAmmoVectorA, this._tmpAmmoVectorB, segments - 1, fixedPoints);
753
+ ropeBody.get_m_cfg().set_collisions(0x11);
754
+ return ropeBody;
755
+ }
756
+ /**
757
+ * Create a custom physics impostor shape using the plugin's onCreateCustomShape handler
758
+ * @param impostor to create the custom physics shape for
759
+ */
760
+ _createCustom(impostor) {
761
+ let returnValue = null;
762
+ if (this.onCreateCustomShape) {
763
+ returnValue = this.onCreateCustomShape(impostor);
764
+ }
765
+ if (returnValue == null) {
766
+ returnValue = new this.bjsAMMO.btCompoundShape();
767
+ }
768
+ return returnValue;
769
+ }
770
+ // adds all verticies (including child verticies) to the convex hull shape
771
+ _addHullVerts(btConvexHullShape, topLevelObject, object) {
772
+ let triangleCount = 0;
773
+ if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
774
+ let indices = object.getIndices();
775
+ if (!indices) {
776
+ indices = [];
777
+ }
778
+ let vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
779
+ if (!vertexPositions) {
780
+ vertexPositions = [];
781
+ }
782
+ object.computeWorldMatrix(false);
783
+ const faceCount = indices.length / 3;
784
+ for (let i = 0; i < faceCount; i++) {
785
+ const triPoints = [];
786
+ for (let point = 0; point < 3; point++) {
787
+ let v = new Vector3(vertexPositions[indices[i * 3 + point] * 3 + 0], vertexPositions[indices[i * 3 + point] * 3 + 1], vertexPositions[indices[i * 3 + point] * 3 + 2]);
788
+ // Adjust for initial scaling
789
+ Matrix.ScalingToRef(object.scaling.x, object.scaling.y, object.scaling.z, this._tmpMatrix);
790
+ v = Vector3.TransformCoordinates(v, this._tmpMatrix);
791
+ let vec;
792
+ if (point == 0) {
793
+ vec = this._tmpAmmoVectorA;
794
+ }
795
+ else if (point == 1) {
796
+ vec = this._tmpAmmoVectorB;
797
+ }
798
+ else {
799
+ vec = this._tmpAmmoVectorC;
800
+ }
801
+ vec.setValue(v.x, v.y, v.z);
802
+ triPoints.push(vec);
803
+ }
804
+ btConvexHullShape.addPoint(triPoints[0], true);
805
+ btConvexHullShape.addPoint(triPoints[1], true);
806
+ btConvexHullShape.addPoint(triPoints[2], true);
807
+ triangleCount++;
808
+ }
809
+ object.getChildMeshes().forEach((m) => {
810
+ triangleCount += this._addHullVerts(btConvexHullShape, topLevelObject, m);
811
+ });
812
+ }
813
+ return triangleCount;
814
+ }
815
+ _createShape(impostor, ignoreChildren = false) {
816
+ const object = impostor.object;
817
+ let returnValue;
818
+ const impostorExtents = impostor.getObjectExtents();
819
+ if (!ignoreChildren) {
820
+ const meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
821
+ returnValue = new this.bjsAMMO.btCompoundShape();
822
+ // Add shape of all children to the compound shape
823
+ let childrenAdded = 0;
824
+ meshChildren.forEach((childMesh) => {
825
+ const childImpostor = childMesh.getPhysicsImpostor();
826
+ if (childImpostor) {
827
+ if (childImpostor.type == PhysicsImpostor.MeshImpostor) {
828
+ throw "A child MeshImpostor is not supported. Only primitive impostors are supported as children (eg. box or sphere)";
829
+ }
830
+ const shape = this._createShape(childImpostor);
831
+ // Position needs to be scaled based on parent's scaling
832
+ const parentMat = childMesh.parent.getWorldMatrix().clone();
833
+ const s = new Vector3();
834
+ parentMat.decompose(s);
835
+ this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
836
+ this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion.x, childMesh.rotationQuaternion.y, childMesh.rotationQuaternion.z, childMesh.rotationQuaternion.w);
837
+ this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
838
+ returnValue.addChildShape(this._tmpAmmoTransform, shape);
839
+ childImpostor.dispose();
840
+ childrenAdded++;
841
+ }
842
+ });
843
+ if (childrenAdded > 0) {
844
+ // Add parents shape as a child if present
845
+ if (impostor.type != PhysicsImpostor.NoImpostor) {
846
+ const shape = this._createShape(impostor, true);
847
+ if (shape) {
848
+ this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
849
+ this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
850
+ this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
851
+ returnValue.addChildShape(this._tmpAmmoTransform, shape);
852
+ }
853
+ }
854
+ return returnValue;
855
+ }
856
+ else {
857
+ // If no children with impostors create the actual shape below instead
858
+ this.bjsAMMO.destroy(returnValue);
859
+ returnValue = null;
860
+ }
861
+ }
862
+ switch (impostor.type) {
863
+ case PhysicsImpostor.SphereImpostor:
864
+ // Is there a better way to compare floats number? With an epsilon or with a Math function
865
+ if (Scalar.WithinEpsilon(impostorExtents.x, impostorExtents.y, 0.0001) && Scalar.WithinEpsilon(impostorExtents.x, impostorExtents.z, 0.0001)) {
866
+ returnValue = new this.bjsAMMO.btSphereShape(impostorExtents.x / 2);
867
+ }
868
+ else {
869
+ // create a btMultiSphereShape because it's not possible to set a local scaling on a btSphereShape
870
+ const positions = [new this.bjsAMMO.btVector3(0, 0, 0)];
871
+ const radii = [1];
872
+ returnValue = new this.bjsAMMO.btMultiSphereShape(positions, radii, 1);
873
+ returnValue.setLocalScaling(new this.bjsAMMO.btVector3(impostorExtents.x / 2, impostorExtents.y / 2, impostorExtents.z / 2));
874
+ }
875
+ break;
876
+ case PhysicsImpostor.CapsuleImpostor:
877
+ {
878
+ // https://pybullet.org/Bullet/BulletFull/classbtCapsuleShape.html#details
879
+ // Height is just the height between the center of each 'sphere' of the capsule caps
880
+ const capRadius = impostorExtents.x / 2;
881
+ returnValue = new this.bjsAMMO.btCapsuleShape(capRadius, impostorExtents.y - capRadius * 2);
882
+ }
883
+ break;
884
+ case PhysicsImpostor.CylinderImpostor:
885
+ this._tmpAmmoVectorA.setValue(impostorExtents.x / 2, impostorExtents.y / 2, impostorExtents.z / 2);
886
+ returnValue = new this.bjsAMMO.btCylinderShape(this._tmpAmmoVectorA);
887
+ break;
888
+ case PhysicsImpostor.PlaneImpostor:
889
+ case PhysicsImpostor.BoxImpostor:
890
+ this._tmpAmmoVectorA.setValue(impostorExtents.x / 2, impostorExtents.y / 2, impostorExtents.z / 2);
891
+ returnValue = new this.bjsAMMO.btBoxShape(this._tmpAmmoVectorA);
892
+ break;
893
+ case PhysicsImpostor.MeshImpostor: {
894
+ if (impostor.getParam("mass") == 0) {
895
+ // Only create btBvhTriangleMeshShape if the impostor is static
896
+ // See https://pybullet.org/Bullet/phpBB3/viewtopic.php?t=7283
897
+ if (this.onCreateCustomMeshImpostor) {
898
+ returnValue = this.onCreateCustomMeshImpostor(impostor);
899
+ }
900
+ else {
901
+ const triMesh = new this.bjsAMMO.btTriangleMesh();
902
+ impostor._pluginData.toDispose.push(triMesh);
903
+ const triangleCount = this._addMeshVerts(triMesh, object, object);
904
+ if (triangleCount == 0) {
905
+ returnValue = new this.bjsAMMO.btCompoundShape();
906
+ }
907
+ else {
908
+ returnValue = new this.bjsAMMO.btBvhTriangleMeshShape(triMesh);
909
+ }
910
+ }
911
+ break;
912
+ }
913
+ }
914
+ // Otherwise create convexHullImpostor
915
+ // eslint-disable-next-line no-fallthrough
916
+ case PhysicsImpostor.ConvexHullImpostor: {
917
+ if (this.onCreateCustomConvexHullImpostor) {
918
+ returnValue = this.onCreateCustomConvexHullImpostor(impostor);
919
+ }
920
+ else {
921
+ const convexHull = new this.bjsAMMO.btConvexHullShape();
922
+ const triangleCount = this._addHullVerts(convexHull, object, object);
923
+ if (triangleCount == 0) {
924
+ // Cleanup Unused Convex Hull Shape
925
+ impostor._pluginData.toDispose.push(convexHull);
926
+ returnValue = new this.bjsAMMO.btCompoundShape();
927
+ }
928
+ else {
929
+ returnValue = convexHull;
930
+ }
931
+ }
932
+ break;
933
+ }
934
+ case PhysicsImpostor.NoImpostor:
935
+ // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
936
+ returnValue = new this.bjsAMMO.btSphereShape(impostorExtents.x / 2);
937
+ break;
938
+ case PhysicsImpostor.CustomImpostor:
939
+ // Only usable when the plugin's onCreateCustomShape is set
940
+ returnValue = this._createCustom(impostor);
941
+ break;
942
+ case PhysicsImpostor.SoftbodyImpostor:
943
+ // Only usable with a mesh that has sufficient and shared vertices
944
+ returnValue = this._createSoftbody(impostor);
945
+ break;
946
+ case PhysicsImpostor.ClothImpostor:
947
+ // Only usable with a ground mesh that has sufficient and shared vertices
948
+ returnValue = this._createCloth(impostor);
949
+ break;
950
+ case PhysicsImpostor.RopeImpostor:
951
+ // Only usable with a line mesh or an extruded mesh that is updatable
952
+ returnValue = this._createRope(impostor);
953
+ break;
954
+ default:
955
+ Logger.Warn("The impostor type is not currently supported by the ammo plugin.");
956
+ break;
957
+ }
958
+ return returnValue;
959
+ }
960
+ /**
961
+ * Sets the mesh body position/rotation from the babylon impostor
962
+ * @param impostor imposter containing the physics body and babylon object
963
+ */
964
+ setTransformationFromPhysicsBody(impostor) {
965
+ impostor.physicsBody.getMotionState().getWorldTransform(this._tmpAmmoTransform);
966
+ impostor.object.position.set(this._tmpAmmoTransform.getOrigin().x(), this._tmpAmmoTransform.getOrigin().y(), this._tmpAmmoTransform.getOrigin().z());
967
+ if (!impostor.object.rotationQuaternion) {
968
+ if (impostor.object.rotation) {
969
+ this._tmpQuaternion.set(this._tmpAmmoTransform.getRotation().x(), this._tmpAmmoTransform.getRotation().y(), this._tmpAmmoTransform.getRotation().z(), this._tmpAmmoTransform.getRotation().w());
970
+ this._tmpQuaternion.toEulerAnglesToRef(impostor.object.rotation);
971
+ }
972
+ }
973
+ else {
974
+ impostor.object.rotationQuaternion.set(this._tmpAmmoTransform.getRotation().x(), this._tmpAmmoTransform.getRotation().y(), this._tmpAmmoTransform.getRotation().z(), this._tmpAmmoTransform.getRotation().w());
975
+ }
976
+ }
977
+ /**
978
+ * Sets the babylon object's position/rotation from the physics body's position/rotation
979
+ * @param impostor imposter containing the physics body and babylon object
980
+ * @param newPosition new position
981
+ * @param newRotation new rotation
982
+ */
983
+ setPhysicsBodyTransformation(impostor, newPosition, newRotation) {
984
+ const trans = impostor.physicsBody.getWorldTransform();
985
+ // If rotation/position has changed update and activate rigged body
986
+ if (Math.abs(trans.getOrigin().x() - newPosition.x) > Epsilon ||
987
+ Math.abs(trans.getOrigin().y() - newPosition.y) > Epsilon ||
988
+ Math.abs(trans.getOrigin().z() - newPosition.z) > Epsilon ||
989
+ Math.abs(trans.getRotation().x() - newRotation.x) > Epsilon ||
990
+ Math.abs(trans.getRotation().y() - newRotation.y) > Epsilon ||
991
+ Math.abs(trans.getRotation().z() - newRotation.z) > Epsilon ||
992
+ Math.abs(trans.getRotation().w() - newRotation.w) > Epsilon) {
993
+ this._tmpAmmoVectorA.setValue(newPosition.x, newPosition.y, newPosition.z);
994
+ trans.setOrigin(this._tmpAmmoVectorA);
995
+ this._tmpAmmoQuaternion.setValue(newRotation.x, newRotation.y, newRotation.z, newRotation.w);
996
+ trans.setRotation(this._tmpAmmoQuaternion);
997
+ impostor.physicsBody.setWorldTransform(trans);
998
+ if (impostor.mass == 0) {
999
+ // Kinematic objects must be updated using motion state
1000
+ const motionState = impostor.physicsBody.getMotionState();
1001
+ if (motionState) {
1002
+ motionState.setWorldTransform(trans);
1003
+ }
1004
+ }
1005
+ else {
1006
+ impostor.physicsBody.activate();
1007
+ }
1008
+ }
1009
+ }
1010
+ /**
1011
+ * If this plugin is supported
1012
+ * @returns true if its supported
1013
+ */
1014
+ isSupported() {
1015
+ return this.bjsAMMO !== undefined;
1016
+ }
1017
+ /**
1018
+ * Sets the linear velocity of the physics body
1019
+ * @param impostor imposter to set the velocity on
1020
+ * @param velocity velocity to set
1021
+ */
1022
+ setLinearVelocity(impostor, velocity) {
1023
+ this._tmpAmmoVectorA.setValue(velocity.x, velocity.y, velocity.z);
1024
+ if (impostor.soft) {
1025
+ impostor.physicsBody.linearVelocity(this._tmpAmmoVectorA);
1026
+ }
1027
+ else {
1028
+ impostor.physicsBody.setLinearVelocity(this._tmpAmmoVectorA);
1029
+ }
1030
+ }
1031
+ /**
1032
+ * Sets the angular velocity of the physics body
1033
+ * @param impostor imposter to set the velocity on
1034
+ * @param velocity velocity to set
1035
+ */
1036
+ setAngularVelocity(impostor, velocity) {
1037
+ this._tmpAmmoVectorA.setValue(velocity.x, velocity.y, velocity.z);
1038
+ if (impostor.soft) {
1039
+ impostor.physicsBody.angularVelocity(this._tmpAmmoVectorA);
1040
+ }
1041
+ else {
1042
+ impostor.physicsBody.setAngularVelocity(this._tmpAmmoVectorA);
1043
+ }
1044
+ }
1045
+ /**
1046
+ * gets the linear velocity
1047
+ * @param impostor imposter to get linear velocity from
1048
+ * @returns linear velocity
1049
+ */
1050
+ getLinearVelocity(impostor) {
1051
+ let v;
1052
+ if (impostor.soft) {
1053
+ v = impostor.physicsBody.linearVelocity();
1054
+ }
1055
+ else {
1056
+ v = impostor.physicsBody.getLinearVelocity();
1057
+ }
1058
+ if (!v) {
1059
+ return null;
1060
+ }
1061
+ const result = new Vector3(v.x(), v.y(), v.z());
1062
+ this.bjsAMMO.destroy(v);
1063
+ return result;
1064
+ }
1065
+ /**
1066
+ * gets the angular velocity
1067
+ * @param impostor imposter to get angular velocity from
1068
+ * @returns angular velocity
1069
+ */
1070
+ getAngularVelocity(impostor) {
1071
+ let v;
1072
+ if (impostor.soft) {
1073
+ v = impostor.physicsBody.angularVelocity();
1074
+ }
1075
+ else {
1076
+ v = impostor.physicsBody.getAngularVelocity();
1077
+ }
1078
+ if (!v) {
1079
+ return null;
1080
+ }
1081
+ const result = new Vector3(v.x(), v.y(), v.z());
1082
+ this.bjsAMMO.destroy(v);
1083
+ return result;
1084
+ }
1085
+ /**
1086
+ * Sets the mass of physics body
1087
+ * @param impostor imposter to set the mass on
1088
+ * @param mass mass to set
1089
+ */
1090
+ setBodyMass(impostor, mass) {
1091
+ if (impostor.soft) {
1092
+ impostor.physicsBody.setTotalMass(mass, false);
1093
+ }
1094
+ else {
1095
+ impostor.physicsBody.setMassProps(mass);
1096
+ }
1097
+ impostor._pluginData.mass = mass;
1098
+ }
1099
+ /**
1100
+ * Gets the mass of the physics body
1101
+ * @param impostor imposter to get the mass from
1102
+ * @returns mass
1103
+ */
1104
+ getBodyMass(impostor) {
1105
+ return impostor._pluginData.mass || 0;
1106
+ }
1107
+ /**
1108
+ * Gets friction of the impostor
1109
+ * @param impostor impostor to get friction from
1110
+ * @returns friction value
1111
+ */
1112
+ getBodyFriction(impostor) {
1113
+ return impostor._pluginData.friction || 0;
1114
+ }
1115
+ /**
1116
+ * Sets friction of the impostor
1117
+ * @param impostor impostor to set friction on
1118
+ * @param friction friction value
1119
+ */
1120
+ setBodyFriction(impostor, friction) {
1121
+ if (impostor.soft) {
1122
+ impostor.physicsBody.get_m_cfg().set_kDF(friction);
1123
+ }
1124
+ else {
1125
+ impostor.physicsBody.setFriction(friction);
1126
+ }
1127
+ impostor._pluginData.friction = friction;
1128
+ }
1129
+ /**
1130
+ * Gets restitution of the impostor
1131
+ * @param impostor impostor to get restitution from
1132
+ * @returns restitution value
1133
+ */
1134
+ getBodyRestitution(impostor) {
1135
+ return impostor._pluginData.restitution || 0;
1136
+ }
1137
+ /**
1138
+ * Sets restitution of the impostor
1139
+ * @param impostor impostor to set resitution on
1140
+ * @param restitution resitution value
1141
+ */
1142
+ setBodyRestitution(impostor, restitution) {
1143
+ impostor.physicsBody.setRestitution(restitution);
1144
+ impostor._pluginData.restitution = restitution;
1145
+ }
1146
+ /**
1147
+ * Gets pressure inside the impostor
1148
+ * @param impostor impostor to get pressure from
1149
+ * @returns pressure value
1150
+ */
1151
+ getBodyPressure(impostor) {
1152
+ if (!impostor.soft) {
1153
+ Logger.Warn("Pressure is not a property of a rigid body");
1154
+ return 0;
1155
+ }
1156
+ return impostor._pluginData.pressure || 0;
1157
+ }
1158
+ /**
1159
+ * Sets pressure inside a soft body impostor
1160
+ * Cloth and rope must remain 0 pressure
1161
+ * @param impostor impostor to set pressure on
1162
+ * @param pressure pressure value
1163
+ */
1164
+ setBodyPressure(impostor, pressure) {
1165
+ if (impostor.soft) {
1166
+ if (impostor.type === PhysicsImpostor.SoftbodyImpostor) {
1167
+ impostor.physicsBody.get_m_cfg().set_kPR(pressure);
1168
+ impostor._pluginData.pressure = pressure;
1169
+ }
1170
+ else {
1171
+ impostor.physicsBody.get_m_cfg().set_kPR(0);
1172
+ impostor._pluginData.pressure = 0;
1173
+ }
1174
+ }
1175
+ else {
1176
+ Logger.Warn("Pressure can only be applied to a softbody");
1177
+ }
1178
+ }
1179
+ /**
1180
+ * Gets stiffness of the impostor
1181
+ * @param impostor impostor to get stiffness from
1182
+ * @returns pressure value
1183
+ */
1184
+ getBodyStiffness(impostor) {
1185
+ if (!impostor.soft) {
1186
+ Logger.Warn("Stiffness is not a property of a rigid body");
1187
+ return 0;
1188
+ }
1189
+ return impostor._pluginData.stiffness || 0;
1190
+ }
1191
+ /**
1192
+ * Sets stiffness of the impostor
1193
+ * @param impostor impostor to set stiffness on
1194
+ * @param stiffness stiffness value from 0 to 1
1195
+ */
1196
+ setBodyStiffness(impostor, stiffness) {
1197
+ if (impostor.soft) {
1198
+ stiffness = stiffness < 0 ? 0 : stiffness;
1199
+ stiffness = stiffness > 1 ? 1 : stiffness;
1200
+ impostor.physicsBody.get_m_materials().at(0).set_m_kLST(stiffness);
1201
+ impostor._pluginData.stiffness = stiffness;
1202
+ }
1203
+ else {
1204
+ Logger.Warn("Stiffness cannot be applied to a rigid body");
1205
+ }
1206
+ }
1207
+ /**
1208
+ * Gets velocityIterations of the impostor
1209
+ * @param impostor impostor to get velocity iterations from
1210
+ * @returns velocityIterations value
1211
+ */
1212
+ getBodyVelocityIterations(impostor) {
1213
+ if (!impostor.soft) {
1214
+ Logger.Warn("Velocity iterations is not a property of a rigid body");
1215
+ return 0;
1216
+ }
1217
+ return impostor._pluginData.velocityIterations || 0;
1218
+ }
1219
+ /**
1220
+ * Sets velocityIterations of the impostor
1221
+ * @param impostor impostor to set velocity iterations on
1222
+ * @param velocityIterations velocityIterations value
1223
+ */
1224
+ setBodyVelocityIterations(impostor, velocityIterations) {
1225
+ if (impostor.soft) {
1226
+ velocityIterations = velocityIterations < 0 ? 0 : velocityIterations;
1227
+ impostor.physicsBody.get_m_cfg().set_viterations(velocityIterations);
1228
+ impostor._pluginData.velocityIterations = velocityIterations;
1229
+ }
1230
+ else {
1231
+ Logger.Warn("Velocity iterations cannot be applied to a rigid body");
1232
+ }
1233
+ }
1234
+ /**
1235
+ * Gets positionIterations of the impostor
1236
+ * @param impostor impostor to get position iterations from
1237
+ * @returns positionIterations value
1238
+ */
1239
+ getBodyPositionIterations(impostor) {
1240
+ if (!impostor.soft) {
1241
+ Logger.Warn("Position iterations is not a property of a rigid body");
1242
+ return 0;
1243
+ }
1244
+ return impostor._pluginData.positionIterations || 0;
1245
+ }
1246
+ /**
1247
+ * Sets positionIterations of the impostor
1248
+ * @param impostor impostor to set position on
1249
+ * @param positionIterations positionIterations value
1250
+ */
1251
+ setBodyPositionIterations(impostor, positionIterations) {
1252
+ if (impostor.soft) {
1253
+ positionIterations = positionIterations < 0 ? 0 : positionIterations;
1254
+ impostor.physicsBody.get_m_cfg().set_piterations(positionIterations);
1255
+ impostor._pluginData.positionIterations = positionIterations;
1256
+ }
1257
+ else {
1258
+ Logger.Warn("Position iterations cannot be applied to a rigid body");
1259
+ }
1260
+ }
1261
+ /**
1262
+ * Append an anchor to a cloth object
1263
+ * @param impostor is the cloth impostor to add anchor to
1264
+ * @param otherImpostor is the rigid impostor to anchor to
1265
+ * @param width ratio across width from 0 to 1
1266
+ * @param height ratio up height from 0 to 1
1267
+ * @param influence the elasticity between cloth impostor and anchor from 0, very stretchy to 1, little stretch
1268
+ * @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
1269
+ */
1270
+ appendAnchor(impostor, otherImpostor, width, height, influence = 1, noCollisionBetweenLinkedBodies = false) {
1271
+ const segs = impostor.segments;
1272
+ const nbAcross = Math.round((segs - 1) * width);
1273
+ const nbUp = Math.round((segs - 1) * height);
1274
+ const nbDown = segs - 1 - nbUp;
1275
+ const node = nbAcross + segs * nbDown;
1276
+ impostor.physicsBody.appendAnchor(node, otherImpostor.physicsBody, noCollisionBetweenLinkedBodies, influence);
1277
+ }
1278
+ /**
1279
+ * Append an hook to a rope object
1280
+ * @param impostor is the rope impostor to add hook to
1281
+ * @param otherImpostor is the rigid impostor to hook to
1282
+ * @param length ratio along the rope from 0 to 1
1283
+ * @param influence the elasticity between soft impostor and anchor from 0, very stretchy to 1, little stretch
1284
+ * @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
1285
+ */
1286
+ appendHook(impostor, otherImpostor, length, influence = 1, noCollisionBetweenLinkedBodies = false) {
1287
+ const node = Math.round(impostor.segments * length);
1288
+ impostor.physicsBody.appendAnchor(node, otherImpostor.physicsBody, noCollisionBetweenLinkedBodies, influence);
1289
+ }
1290
+ /**
1291
+ * Sleeps the physics body and stops it from being active
1292
+ * @param impostor impostor to sleep
1293
+ */
1294
+ sleepBody(impostor) {
1295
+ impostor.physicsBody.forceActivationState(0);
1296
+ }
1297
+ /**
1298
+ * Activates the physics body
1299
+ * @param impostor impostor to activate
1300
+ */
1301
+ wakeUpBody(impostor) {
1302
+ impostor.physicsBody.activate();
1303
+ }
1304
+ /**
1305
+ * Updates the distance parameters of the joint
1306
+ */
1307
+ updateDistanceJoint() {
1308
+ Logger.Warn("updateDistanceJoint is not currently supported by the Ammo physics plugin");
1309
+ }
1310
+ /**
1311
+ * Sets a motor on the joint
1312
+ * @param joint joint to set motor on
1313
+ * @param speed speed of the motor
1314
+ * @param maxForce maximum force of the motor
1315
+ */
1316
+ setMotor(joint, speed, maxForce) {
1317
+ joint.physicsJoint.enableAngularMotor(true, speed, maxForce);
1318
+ }
1319
+ /**
1320
+ * Sets the motors limit
1321
+ */
1322
+ setLimit() {
1323
+ Logger.Warn("setLimit is not currently supported by the Ammo physics plugin");
1324
+ }
1325
+ /**
1326
+ * Syncs the position and rotation of a mesh with the impostor
1327
+ * @param mesh mesh to sync
1328
+ * @param impostor impostor to update the mesh with
1329
+ */
1330
+ syncMeshWithImpostor(mesh, impostor) {
1331
+ const body = impostor.physicsBody;
1332
+ body.getMotionState().getWorldTransform(this._tmpAmmoTransform);
1333
+ mesh.position.x = this._tmpAmmoTransform.getOrigin().x();
1334
+ mesh.position.y = this._tmpAmmoTransform.getOrigin().y();
1335
+ mesh.position.z = this._tmpAmmoTransform.getOrigin().z();
1336
+ if (mesh.rotationQuaternion) {
1337
+ mesh.rotationQuaternion.x = this._tmpAmmoTransform.getRotation().x();
1338
+ mesh.rotationQuaternion.y = this._tmpAmmoTransform.getRotation().y();
1339
+ mesh.rotationQuaternion.z = this._tmpAmmoTransform.getRotation().z();
1340
+ mesh.rotationQuaternion.w = this._tmpAmmoTransform.getRotation().w();
1341
+ }
1342
+ }
1343
+ /**
1344
+ * Gets the radius of the impostor
1345
+ * @param impostor impostor to get radius from
1346
+ * @returns the radius
1347
+ */
1348
+ getRadius(impostor) {
1349
+ const extents = impostor.getObjectExtents();
1350
+ return extents.x / 2;
1351
+ }
1352
+ /**
1353
+ * Gets the box size of the impostor
1354
+ * @param impostor impostor to get box size from
1355
+ * @param result the resulting box size
1356
+ */
1357
+ getBoxSizeToRef(impostor, result) {
1358
+ const extents = impostor.getObjectExtents();
1359
+ result.x = extents.x;
1360
+ result.y = extents.y;
1361
+ result.z = extents.z;
1362
+ }
1363
+ /**
1364
+ * Disposes of the impostor
1365
+ */
1366
+ dispose() {
1367
+ // Dispose of world
1368
+ this.bjsAMMO.destroy(this.world);
1369
+ this.bjsAMMO.destroy(this._solver);
1370
+ this.bjsAMMO.destroy(this._overlappingPairCache);
1371
+ this.bjsAMMO.destroy(this._dispatcher);
1372
+ this.bjsAMMO.destroy(this._collisionConfiguration);
1373
+ // Dispose of temp variables
1374
+ this.bjsAMMO.destroy(this._tmpAmmoVectorA);
1375
+ this.bjsAMMO.destroy(this._tmpAmmoVectorB);
1376
+ this.bjsAMMO.destroy(this._tmpAmmoVectorC);
1377
+ this.bjsAMMO.destroy(this._tmpAmmoTransform);
1378
+ this.bjsAMMO.destroy(this._tmpAmmoQuaternion);
1379
+ this.bjsAMMO.destroy(this._tmpAmmoConcreteContactResultCallback);
1380
+ this.world = null;
1381
+ }
1382
+ /**
1383
+ * Does a raycast in the physics world
1384
+ * @param from where should the ray start?
1385
+ * @param to where should the ray end?
1386
+ * @returns PhysicsRaycastResult
1387
+ */
1388
+ raycast(from, to) {
1389
+ this.raycastToRef(from, to, this._raycastResult);
1390
+ return this._raycastResult;
1391
+ }
1392
+ /**
1393
+ * Does a raycast in the physics world
1394
+ * @param from when should the ray start?
1395
+ * @param to when should the ray end?
1396
+ * @param result resulting PhysicsRaycastResult
1397
+ */
1398
+ raycastToRef(from, to, result) {
1399
+ this._tmpAmmoVectorRCA = new this.bjsAMMO.btVector3(from.x, from.y, from.z);
1400
+ this._tmpAmmoVectorRCB = new this.bjsAMMO.btVector3(to.x, to.y, to.z);
1401
+ const rayCallback = new this.bjsAMMO.ClosestRayResultCallback(this._tmpAmmoVectorRCA, this._tmpAmmoVectorRCB);
1402
+ this.world.rayTest(this._tmpAmmoVectorRCA, this._tmpAmmoVectorRCB, rayCallback);
1403
+ result.reset(from, to);
1404
+ if (rayCallback.hasHit()) {
1405
+ // TODO: do we want/need the body? If so, set all the data
1406
+ /*
1407
+ var rigidBody = this.bjsAMMO.btRigidBody.prototype.upcast(
1408
+ rayCallback.get_m_collisionObject()
1409
+ );
1410
+ var body = {};
1411
+ */
1412
+ result.setHitData({
1413
+ x: rayCallback.get_m_hitNormalWorld().x(),
1414
+ y: rayCallback.get_m_hitNormalWorld().y(),
1415
+ z: rayCallback.get_m_hitNormalWorld().z(),
1416
+ }, {
1417
+ x: rayCallback.get_m_hitPointWorld().x(),
1418
+ y: rayCallback.get_m_hitPointWorld().y(),
1419
+ z: rayCallback.get_m_hitPointWorld().z(),
1420
+ });
1421
+ result.calculateHitDistance();
1422
+ }
1423
+ this.bjsAMMO.destroy(rayCallback);
1424
+ this.bjsAMMO.destroy(this._tmpAmmoVectorRCA);
1425
+ this.bjsAMMO.destroy(this._tmpAmmoVectorRCB);
1426
+ }
1427
+ }
1428
+ AmmoJSPlugin._DISABLE_COLLISION_FLAG = 4;
1429
+ AmmoJSPlugin._KINEMATIC_FLAG = 2;
1430
+ AmmoJSPlugin._DISABLE_DEACTIVATION_FLAG = 4;
1431
+ //# sourceMappingURL=ammoJSPlugin.js.map