@onerjs/core 8.41.4 → 8.41.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/Cameras/Inputs/geospatialCameraPointersInput.d.ts +16 -0
  2. package/Cameras/Inputs/geospatialCameraPointersInput.js +19 -3
  3. package/Cameras/Inputs/geospatialCameraPointersInput.js.map +1 -1
  4. package/Cameras/Limits/geospatialLimits.d.ts +0 -6
  5. package/Cameras/Limits/geospatialLimits.js +0 -6
  6. package/Cameras/Limits/geospatialLimits.js.map +1 -1
  7. package/Cameras/geospatialCamera.d.ts +5 -0
  8. package/Cameras/geospatialCamera.js +38 -10
  9. package/Cameras/geospatialCamera.js.map +1 -1
  10. package/Engines/abstractEngine.d.ts +2 -2
  11. package/Engines/abstractEngine.js +2 -2
  12. package/Engines/abstractEngine.js.map +1 -1
  13. package/Engines/webgpuEngine.d.ts +1 -4
  14. package/Engines/webgpuEngine.js +8 -6
  15. package/Engines/webgpuEngine.js.map +1 -1
  16. package/FrameGraph/frameGraphContext.js +1 -1
  17. package/FrameGraph/frameGraphContext.js.map +1 -1
  18. package/FrameGraph/frameGraphRenderContext.js +2 -2
  19. package/FrameGraph/frameGraphRenderContext.js.map +1 -1
  20. package/Lights/Shadows/cascadedShadowGenerator.js +1 -1
  21. package/Lights/Shadows/cascadedShadowGenerator.js.map +1 -1
  22. package/Lights/Shadows/shadowGenerator.js +1 -1
  23. package/Lights/Shadows/shadowGenerator.js.map +1 -1
  24. package/Lights/lightingVolume.js +1 -1
  25. package/Lights/lightingVolume.js.map +1 -1
  26. package/Materials/Textures/Procedurals/proceduralTexture.js +1 -1
  27. package/Materials/Textures/Procedurals/proceduralTexture.js.map +1 -1
  28. package/Maths/math.path.js +3 -3
  29. package/Maths/math.path.js.map +1 -1
  30. package/Meshes/Builders/capsuleBuilder.js +0 -3
  31. package/Meshes/Builders/capsuleBuilder.js.map +1 -1
  32. package/Meshes/Builders/cylinderBuilder.d.ts +1 -1
  33. package/Meshes/Builders/cylinderBuilder.js +1 -2
  34. package/Meshes/Builders/cylinderBuilder.js.map +1 -1
  35. package/Meshes/Builders/decalBuilder.js +2 -0
  36. package/Meshes/Builders/decalBuilder.js.map +1 -1
  37. package/Meshes/Builders/discBuilder.js +0 -1
  38. package/Meshes/Builders/discBuilder.js.map +1 -1
  39. package/Meshes/Builders/groundBuilder.d.ts +50 -54
  40. package/Meshes/Builders/groundBuilder.js +50 -54
  41. package/Meshes/Builders/groundBuilder.js.map +1 -1
  42. package/Meshes/Builders/tiledBoxBuilder.d.ts +0 -26
  43. package/Meshes/Builders/tiledBoxBuilder.js +0 -26
  44. package/Meshes/Builders/tiledBoxBuilder.js.map +1 -1
  45. package/Meshes/Builders/tiledPlaneBuilder.d.ts +0 -25
  46. package/Meshes/Builders/tiledPlaneBuilder.js +0 -25
  47. package/Meshes/Builders/tiledPlaneBuilder.js.map +1 -1
  48. package/Meshes/Builders/torusBuilder.d.ts +0 -13
  49. package/Meshes/Builders/torusBuilder.js +0 -13
  50. package/Meshes/Builders/torusBuilder.js.map +1 -1
  51. package/Meshes/Builders/torusKnotBuilder.d.ts +0 -19
  52. package/Meshes/Builders/torusKnotBuilder.js +0 -19
  53. package/Meshes/Builders/torusKnotBuilder.js.map +1 -1
  54. package/Meshes/Compression/dracoCompressionWorker.js.map +1 -1
  55. package/Meshes/Compression/dracoDecoder.js.map +1 -1
  56. package/Meshes/Compression/dracoDecoder.types.d.ts +11 -0
  57. package/Meshes/Compression/dracoDecoder.types.js.map +1 -1
  58. package/Meshes/Compression/dracoEncoder.js.map +1 -1
  59. package/Meshes/Compression/meshoptCompression.js +0 -2
  60. package/Meshes/Compression/meshoptCompression.js.map +1 -1
  61. package/Meshes/GreasedLine/greasedLineRibbonMesh.js +0 -8
  62. package/Meshes/GreasedLine/greasedLineRibbonMesh.js.map +1 -1
  63. package/Meshes/Node/Blocks/Instances/instantiateBaseBlock.d.ts +1 -0
  64. package/Meshes/Node/Blocks/Instances/instantiateBaseBlock.js +1 -0
  65. package/Meshes/Node/Blocks/Instances/instantiateBaseBlock.js.map +1 -1
  66. package/Meshes/Node/Blocks/Instances/instantiateOnFacesBlock.d.ts +1 -0
  67. package/Meshes/Node/Blocks/Instances/instantiateOnFacesBlock.js +1 -0
  68. package/Meshes/Node/Blocks/Instances/instantiateOnFacesBlock.js.map +1 -1
  69. package/Meshes/Node/Blocks/Instances/instantiateOnVerticesBlock.d.ts +1 -0
  70. package/Meshes/Node/Blocks/Instances/instantiateOnVerticesBlock.js +1 -0
  71. package/Meshes/Node/Blocks/Instances/instantiateOnVerticesBlock.js.map +1 -1
  72. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.d.ts +1 -0
  73. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.js +1 -0
  74. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.js.map +1 -1
  75. package/Meshes/Node/Blocks/Matrices/scalingBlock.d.ts +1 -0
  76. package/Meshes/Node/Blocks/Matrices/scalingBlock.js +1 -0
  77. package/Meshes/Node/Blocks/Matrices/scalingBlock.js.map +1 -1
  78. package/Meshes/Node/Blocks/Matrices/translationBlock.d.ts +1 -0
  79. package/Meshes/Node/Blocks/Matrices/translationBlock.js +1 -0
  80. package/Meshes/Node/Blocks/Matrices/translationBlock.js.map +1 -1
  81. package/Meshes/Node/Blocks/Set/aggregatorBlock.d.ts +1 -0
  82. package/Meshes/Node/Blocks/Set/aggregatorBlock.js +1 -0
  83. package/Meshes/Node/Blocks/Set/aggregatorBlock.js.map +1 -1
  84. package/Meshes/Node/Blocks/Set/latticeBlock.d.ts +1 -0
  85. package/Meshes/Node/Blocks/Set/latticeBlock.js +1 -0
  86. package/Meshes/Node/Blocks/Set/latticeBlock.js.map +1 -1
  87. package/Meshes/Node/Blocks/Set/setColorsBlock.d.ts +1 -0
  88. package/Meshes/Node/Blocks/Set/setColorsBlock.js +1 -0
  89. package/Meshes/Node/Blocks/Set/setColorsBlock.js.map +1 -1
  90. package/Meshes/Node/Blocks/Set/setMaterialIDBlock.d.ts +1 -0
  91. package/Meshes/Node/Blocks/Set/setMaterialIDBlock.js +1 -0
  92. package/Meshes/Node/Blocks/Set/setMaterialIDBlock.js.map +1 -1
  93. package/Meshes/Node/Blocks/Set/setNormalsBlock.d.ts +1 -0
  94. package/Meshes/Node/Blocks/Set/setNormalsBlock.js +1 -0
  95. package/Meshes/Node/Blocks/Set/setNormalsBlock.js.map +1 -1
  96. package/Meshes/Node/Blocks/Set/setPositionsBlock.d.ts +1 -0
  97. package/Meshes/Node/Blocks/Set/setPositionsBlock.js +1 -0
  98. package/Meshes/Node/Blocks/Set/setPositionsBlock.js.map +1 -1
  99. package/Meshes/Node/Blocks/Set/setTangentsBlock.d.ts +1 -0
  100. package/Meshes/Node/Blocks/Set/setTangentsBlock.js +1 -0
  101. package/Meshes/Node/Blocks/Set/setTangentsBlock.js.map +1 -1
  102. package/Meshes/Node/Blocks/Set/setUVsBlock.d.ts +1 -0
  103. package/Meshes/Node/Blocks/Set/setUVsBlock.js +1 -0
  104. package/Meshes/Node/Blocks/Set/setUVsBlock.js.map +1 -1
  105. package/Meshes/Node/Blocks/Sources/boxBlock.d.ts +2 -0
  106. package/Meshes/Node/Blocks/Sources/boxBlock.js +2 -0
  107. package/Meshes/Node/Blocks/Sources/boxBlock.js.map +1 -1
  108. package/Meshes/Node/Blocks/Sources/capsuleBlock.d.ts +2 -0
  109. package/Meshes/Node/Blocks/Sources/capsuleBlock.js +2 -0
  110. package/Meshes/Node/Blocks/Sources/capsuleBlock.js.map +1 -1
  111. package/Meshes/Node/Blocks/Sources/cylinderBlock.d.ts +2 -0
  112. package/Meshes/Node/Blocks/Sources/cylinderBlock.js +2 -0
  113. package/Meshes/Node/Blocks/Sources/cylinderBlock.js.map +1 -1
  114. package/Meshes/Node/Blocks/Sources/discBlock.d.ts +2 -0
  115. package/Meshes/Node/Blocks/Sources/discBlock.js +2 -0
  116. package/Meshes/Node/Blocks/Sources/discBlock.js.map +1 -1
  117. package/Meshes/Node/Blocks/Sources/gridBlock.d.ts +2 -0
  118. package/Meshes/Node/Blocks/Sources/gridBlock.js +2 -0
  119. package/Meshes/Node/Blocks/Sources/gridBlock.js.map +1 -1
  120. package/Meshes/Node/Blocks/Sources/icoSphereBlock.d.ts +2 -0
  121. package/Meshes/Node/Blocks/Sources/icoSphereBlock.js +2 -0
  122. package/Meshes/Node/Blocks/Sources/icoSphereBlock.js.map +1 -1
  123. package/Meshes/Node/Blocks/Sources/meshBlock.d.ts +1 -0
  124. package/Meshes/Node/Blocks/Sources/meshBlock.js +1 -0
  125. package/Meshes/Node/Blocks/Sources/meshBlock.js.map +1 -1
  126. package/Meshes/Node/Blocks/Sources/planeBlock.d.ts +2 -0
  127. package/Meshes/Node/Blocks/Sources/planeBlock.js +2 -0
  128. package/Meshes/Node/Blocks/Sources/planeBlock.js.map +1 -1
  129. package/Meshes/Node/Blocks/Sources/pointListBlock.d.ts +2 -1
  130. package/Meshes/Node/Blocks/Sources/pointListBlock.js +2 -1
  131. package/Meshes/Node/Blocks/Sources/pointListBlock.js.map +1 -1
  132. package/Meshes/Node/Blocks/Sources/sphereBlock.d.ts +2 -0
  133. package/Meshes/Node/Blocks/Sources/sphereBlock.js +2 -0
  134. package/Meshes/Node/Blocks/Sources/sphereBlock.js.map +1 -1
  135. package/Meshes/Node/Blocks/Sources/torusBlock.d.ts +2 -0
  136. package/Meshes/Node/Blocks/Sources/torusBlock.js +2 -0
  137. package/Meshes/Node/Blocks/Sources/torusBlock.js.map +1 -1
  138. package/Meshes/Node/Blocks/Teleport/teleportInBlock.d.ts +1 -0
  139. package/Meshes/Node/Blocks/Teleport/teleportInBlock.js +1 -0
  140. package/Meshes/Node/Blocks/Teleport/teleportInBlock.js.map +1 -1
  141. package/Meshes/Node/Blocks/Teleport/teleportOutBlock.d.ts +3 -0
  142. package/Meshes/Node/Blocks/Teleport/teleportOutBlock.js +3 -0
  143. package/Meshes/Node/Blocks/Teleport/teleportOutBlock.js.map +1 -1
  144. package/Meshes/Node/Blocks/Textures/geometryTextureBlock.d.ts +1 -0
  145. package/Meshes/Node/Blocks/Textures/geometryTextureBlock.js +1 -1
  146. package/Meshes/Node/Blocks/Textures/geometryTextureBlock.js.map +1 -1
  147. package/Meshes/Node/Blocks/Textures/geometryTextureFetchBlock.d.ts +1 -0
  148. package/Meshes/Node/Blocks/Textures/geometryTextureFetchBlock.js +1 -0
  149. package/Meshes/Node/Blocks/Textures/geometryTextureFetchBlock.js.map +1 -1
  150. package/Meshes/Node/Blocks/booleanGeometryBlock.d.ts +1 -0
  151. package/Meshes/Node/Blocks/booleanGeometryBlock.js +1 -1
  152. package/Meshes/Node/Blocks/booleanGeometryBlock.js.map +1 -1
  153. package/Meshes/Node/Blocks/cleanGeometryBlock.d.ts +1 -0
  154. package/Meshes/Node/Blocks/cleanGeometryBlock.js +1 -0
  155. package/Meshes/Node/Blocks/cleanGeometryBlock.js.map +1 -1
  156. package/Meshes/Node/Blocks/conditionBlock.d.ts +2 -0
  157. package/Meshes/Node/Blocks/conditionBlock.js +2 -0
  158. package/Meshes/Node/Blocks/conditionBlock.js.map +1 -1
  159. package/Meshes/Node/Blocks/geometryClampBlock.d.ts +1 -0
  160. package/Meshes/Node/Blocks/geometryClampBlock.js +1 -0
  161. package/Meshes/Node/Blocks/geometryClampBlock.js.map +1 -1
  162. package/Meshes/Node/Blocks/geometryCollectionBlock.d.ts +1 -0
  163. package/Meshes/Node/Blocks/geometryCollectionBlock.js +1 -0
  164. package/Meshes/Node/Blocks/geometryCollectionBlock.js.map +1 -1
  165. package/Meshes/Node/Blocks/geometryCurveBlock.d.ts +2 -0
  166. package/Meshes/Node/Blocks/geometryCurveBlock.js +2 -0
  167. package/Meshes/Node/Blocks/geometryCurveBlock.js.map +1 -1
  168. package/Meshes/Node/Blocks/geometryEaseBlock.d.ts +2 -0
  169. package/Meshes/Node/Blocks/geometryEaseBlock.js +2 -0
  170. package/Meshes/Node/Blocks/geometryEaseBlock.js.map +1 -1
  171. package/Meshes/Node/Blocks/geometryInputBlock.d.ts +3 -0
  172. package/Meshes/Node/Blocks/geometryInputBlock.js +3 -0
  173. package/Meshes/Node/Blocks/geometryInputBlock.js.map +1 -1
  174. package/Meshes/Node/Blocks/geometryOptimizeBlock.d.ts +1 -0
  175. package/Meshes/Node/Blocks/geometryOptimizeBlock.js +1 -0
  176. package/Meshes/Node/Blocks/geometryOptimizeBlock.js.map +1 -1
  177. package/Meshes/Node/Blocks/geometryTransformBlock.d.ts +1 -0
  178. package/Meshes/Node/Blocks/geometryTransformBlock.js +1 -0
  179. package/Meshes/Node/Blocks/geometryTransformBlock.js.map +1 -1
  180. package/Meshes/Node/Blocks/geometryTrigonometryBlock.d.ts +2 -0
  181. package/Meshes/Node/Blocks/geometryTrigonometryBlock.js +2 -0
  182. package/Meshes/Node/Blocks/geometryTrigonometryBlock.js.map +1 -1
  183. package/Meshes/Node/Blocks/mappingBlock.d.ts +1 -0
  184. package/Meshes/Node/Blocks/mappingBlock.js +1 -0
  185. package/Meshes/Node/Blocks/mappingBlock.js.map +1 -1
  186. package/Meshes/Node/Blocks/mathBlock.d.ts +1 -0
  187. package/Meshes/Node/Blocks/mathBlock.js +1 -0
  188. package/Meshes/Node/Blocks/mathBlock.js.map +1 -1
  189. package/Meshes/Node/Blocks/mergeGeometryBlock.d.ts +1 -0
  190. package/Meshes/Node/Blocks/mergeGeometryBlock.js +1 -0
  191. package/Meshes/Node/Blocks/mergeGeometryBlock.js.map +1 -1
  192. package/Meshes/Node/Blocks/randomBlock.d.ts +2 -0
  193. package/Meshes/Node/Blocks/randomBlock.js +2 -0
  194. package/Meshes/Node/Blocks/randomBlock.js.map +1 -1
  195. package/Meshes/Node/Blocks/subdivideBlock.d.ts +1 -0
  196. package/Meshes/Node/Blocks/subdivideBlock.js +1 -0
  197. package/Meshes/Node/Blocks/subdivideBlock.js.map +1 -1
  198. package/Meshes/Node/Interfaces/nodeGeometryTextureData.d.ts +3 -0
  199. package/Meshes/Node/Interfaces/nodeGeometryTextureData.js.map +1 -1
  200. package/Meshes/Node/nodeGeometry.js +0 -2
  201. package/Meshes/Node/nodeGeometry.js.map +1 -1
  202. package/Meshes/Node/nodeGeometryBlockConnectionPoint.js +0 -1
  203. package/Meshes/Node/nodeGeometryBlockConnectionPoint.js.map +1 -1
  204. package/Meshes/Node/nodeGeometryBuildState.js +0 -1
  205. package/Meshes/Node/nodeGeometryBuildState.js.map +1 -1
  206. package/Meshes/WebGL/webGLDataBuffer.d.ts +2 -0
  207. package/Meshes/WebGL/webGLDataBuffer.js +2 -0
  208. package/Meshes/WebGL/webGLDataBuffer.js.map +1 -1
  209. package/Meshes/WebGPU/webgpuDataBuffer.d.ts +4 -0
  210. package/Meshes/WebGPU/webgpuDataBuffer.js +4 -0
  211. package/Meshes/WebGPU/webgpuDataBuffer.js.map +1 -1
  212. package/Meshes/abstractMesh.d.ts +1 -0
  213. package/Meshes/abstractMesh.decalMap.d.ts +1 -0
  214. package/Meshes/abstractMesh.decalMap.js.map +1 -1
  215. package/Meshes/abstractMesh.js +1 -6
  216. package/Meshes/abstractMesh.js.map +1 -1
  217. package/Meshes/csg.js +0 -6
  218. package/Meshes/csg.js.map +1 -1
  219. package/Meshes/csg2.js +1 -2
  220. package/Meshes/csg2.js.map +1 -1
  221. package/Meshes/geodesicMesh.d.ts +26 -0
  222. package/Meshes/geodesicMesh.js +18 -3
  223. package/Meshes/geodesicMesh.js.map +1 -1
  224. package/Meshes/groundMesh.d.ts +1 -0
  225. package/Meshes/groundMesh.js +1 -0
  226. package/Meshes/groundMesh.js.map +1 -1
  227. package/Meshes/index.js +0 -2
  228. package/Meshes/index.js.map +1 -1
  229. package/Meshes/instancedMesh.d.ts +18 -3
  230. package/Meshes/instancedMesh.js +10 -3
  231. package/Meshes/instancedMesh.js.map +1 -1
  232. package/Meshes/mesh.d.ts +286 -204
  233. package/Meshes/mesh.js +251 -197
  234. package/Meshes/mesh.js.map +1 -1
  235. package/Meshes/mesh.vertexData.d.ts +15 -19
  236. package/Meshes/mesh.vertexData.js +15 -19
  237. package/Meshes/mesh.vertexData.js.map +1 -1
  238. package/Meshes/meshSimplification.d.ts +0 -1
  239. package/Meshes/meshSimplification.js +6 -1
  240. package/Meshes/meshSimplification.js.map +1 -1
  241. package/Meshes/meshSimplificationSceneComponent.d.ts +2 -0
  242. package/Meshes/meshSimplificationSceneComponent.js.map +1 -1
  243. package/Meshes/meshUVSpaceRenderer.d.ts +1 -0
  244. package/Meshes/meshUVSpaceRenderer.js.map +1 -1
  245. package/Meshes/polygonMesh.js +4 -0
  246. package/Meshes/polygonMesh.js.map +1 -1
  247. package/Meshes/subMesh.project.d.ts +1 -0
  248. package/Meshes/subMesh.project.js.map +1 -1
  249. package/Meshes/thinInstanceMesh.d.ts +5 -0
  250. package/Meshes/thinInstanceMesh.js.map +1 -1
  251. package/Meshes/transformNode.d.ts +1 -1
  252. package/Meshes/transformNode.js +1 -1
  253. package/Meshes/transformNode.js.map +1 -1
  254. package/Physics/v2/Plugins/havokPlugin.d.ts +75 -2
  255. package/Physics/v2/Plugins/havokPlugin.js +243 -52
  256. package/Physics/v2/Plugins/havokPlugin.js.map +1 -1
  257. package/Probes/reflectionProbe.js +1 -1
  258. package/Probes/reflectionProbe.js.map +1 -1
  259. package/Rendering/depthRenderer.js +1 -1
  260. package/Rendering/depthRenderer.js.map +1 -1
  261. package/package.json +1 -1
  262. package/scene.d.ts +0 -3
  263. package/scene.js +18 -5
  264. package/scene.js.map +1 -1
@@ -11,6 +11,7 @@ import { InstancedMesh } from "../../../Meshes/instancedMesh.js";
11
11
  import { VertexBuffer } from "../../../Buffers/buffer.js";
12
12
  import { BuildArray } from "../../../Misc/arrayTools.js";
13
13
  import { Observable } from "../../../Misc/observable.js";
14
+ import { FloatingOriginCurrentScene } from "../../../Materials/floatingOriginMatrixOverrides.js";
14
15
  class MeshAccumulator {
15
16
  /**
16
17
  * Constructor of the mesh accumulator
@@ -210,6 +211,45 @@ class TriggerEvent {
210
211
  * The Havok Physics plugin
211
212
  */
212
213
  export class HavokPlugin {
214
+ /**
215
+ * Finds an existing world region that contains the given world position,
216
+ * or creates a new world region centered at that position.
217
+ *
218
+ * When floatingOriginMode is enabled, we use multiple Havok worlds to maintain
219
+ * float32 precision across a large world. Each world region has its own fixed
220
+ * floating origin, and bodies within that region are simulated relative to it.
221
+ *
222
+ * @param worldPosition - The world position of the body being created
223
+ * @returns The world region to use for this body
224
+ */
225
+ _getOrCreateWorldRegion(worldPosition) {
226
+ // Check if floating origin mode is enabled
227
+ const scene = FloatingOriginCurrentScene.getScene();
228
+ if (!scene?.floatingOriginMode) {
229
+ // When floating origin mode is disabled, use the default world region
230
+ return this._worldRegions[0];
231
+ }
232
+ // Find an existing region that contains this position
233
+ for (const region of this._worldRegions) {
234
+ const distance = Vector3.Distance(worldPosition, region.floatingOrigin);
235
+ if (distance <= this._floatingOriginWorldRadius) {
236
+ return region;
237
+ }
238
+ }
239
+ // No existing region found - create a new one centered at this position
240
+ const newWorld = this._hknp.HP_World_Create()[1];
241
+ // Apply stored gravity to new world
242
+ this._hknp.HP_World_SetGravity(newWorld, this._currentGravity);
243
+ // Copy velocity limits from main world
244
+ this._hknp.HP_World_SetSpeedLimit(newWorld, this.getMaxLinearVelocity(), this.getMaxAngularVelocity());
245
+ const newRegion = {
246
+ world: newWorld,
247
+ floatingOrigin: worldPosition.clone(),
248
+ gravity: [...this._currentGravity],
249
+ };
250
+ this._worldRegions.push(newRegion);
251
+ return newRegion;
252
+ }
213
253
  constructor(_useDeltaForWorldStep = true, hpInjection = HK, parameters = {}) {
214
254
  this._useDeltaForWorldStep = _useDeltaForWorldStep;
215
255
  /**
@@ -230,6 +270,20 @@ export class HavokPlugin {
230
270
  // Map from constraint id to the pair of bodies, where the first is the parent and the second is the child
231
271
  this._constraintToBodyIdPair = new Map();
232
272
  this._bodyCollisionEndedObservable = new Map();
273
+ /**
274
+ * Array of world regions. The first region is always the default world with origin at Vector3.Zero.
275
+ * Additional regions are created as needed for floating origin mode.
276
+ */
277
+ this._worldRegions = [];
278
+ /**
279
+ * Stored gravity value to apply to new world regions.
280
+ */
281
+ this._currentGravity = [0, -9.81, 0];
282
+ /**
283
+ * Radius of each floating origin world region.
284
+ * Bodies within this radius of a world region's origin will use that world.
285
+ */
286
+ this._floatingOriginWorldRadius = 100000;
233
287
  /**
234
288
  * Observable for collision started and collision continued events
235
289
  */
@@ -254,8 +308,15 @@ export class HavokPlugin {
254
308
  return;
255
309
  }
256
310
  this.world = this._hknp.HP_World_Create()[1];
311
+ // Add the default world as the first region with origin at zero
312
+ this._worldRegions.push({
313
+ world: this.world,
314
+ floatingOrigin: Vector3.Zero(),
315
+ gravity: [...this._currentGravity],
316
+ });
257
317
  this._queryCollector = this._hknp.HP_QueryCollector_Create(1)[1];
258
318
  this.setMaxQueryCollectorHits(parameters.maxQueryCollectorHits ?? 1);
319
+ this._floatingOriginWorldRadius = parameters.floatingOriginWorldRadius ?? 100000;
259
320
  }
260
321
  /**
261
322
  * If this plugin is supported
@@ -268,10 +329,41 @@ export class HavokPlugin {
268
329
  * Sets the gravity of the physics world.
269
330
  *
270
331
  * @param gravity - The gravity vector to set.
332
+ * @param worldPosition - Optional world position to specify which region's gravity to set.
333
+ * If provided, only the region containing this position will be updated.
334
+ * If not provided, all regions will be updated (default behavior).
335
+ * This is useful for planetary scenarios where gravity direction varies by location.
336
+ */
337
+ setGravity(gravity, worldPosition) {
338
+ const gravityArray = this._bVecToV3(gravity);
339
+ if (worldPosition) {
340
+ // Set gravity for a specific region based on world position
341
+ const region = this._getOrCreateWorldRegion(worldPosition);
342
+ region.gravity = gravityArray;
343
+ this._hknp.HP_World_SetGravity(region.world, gravityArray);
344
+ }
345
+ else {
346
+ // Set gravity for all regions (default behavior)
347
+ this._currentGravity = gravityArray;
348
+ for (const region of this._worldRegions) {
349
+ region.gravity = gravityArray;
350
+ this._hknp.HP_World_SetGravity(region.world, gravityArray);
351
+ }
352
+ }
353
+ }
354
+ /**
355
+ * Gets the gravity of the physics world or a specific region.
271
356
  *
357
+ * @param worldPosition - Optional world position to get the gravity for that region.
358
+ * If not provided, returns the default gravity.
359
+ * @returns The gravity vector.
272
360
  */
273
- setGravity(gravity) {
274
- this._hknp.HP_World_SetGravity(this.world, this._bVecToV3(gravity));
361
+ getGravity(worldPosition) {
362
+ if (worldPosition) {
363
+ const region = this._getOrCreateWorldRegion(worldPosition);
364
+ return new Vector3(region.gravity[0], region.gravity[1], region.gravity[2]);
365
+ }
366
+ return new Vector3(this._currentGravity[0], this._currentGravity[1], this._currentGravity[2]);
275
367
  }
276
368
  /**
277
369
  * Sets the fixed time step for the physics engine.
@@ -334,16 +426,23 @@ export class HavokPlugin {
334
426
  this.setPhysicsBodyTransformation(physicsBody, physicsBody.transformNode);
335
427
  }
336
428
  const deltaTime = this._useDeltaForWorldStep ? delta : this._fixedTimeStep;
337
- this._hknp.HP_World_SetIdealStepTime(this.world, deltaTime);
338
- this._hknp.HP_World_Step(this.world, deltaTime);
429
+ // Step all world regions
430
+ for (const region of this._worldRegions) {
431
+ this._hknp.HP_World_SetIdealStepTime(region.world, deltaTime);
432
+ this._hknp.HP_World_Step(region.world, deltaTime);
433
+ }
434
+ // Get body buffer from the default world (first region)
339
435
  this._bodyBuffer = this._hknp.HP_World_GetBodyBuffer(this.world)[1];
340
436
  for (const physicsBody of physicsBodies) {
341
437
  if (!physicsBody.disableSync) {
342
438
  this.sync(physicsBody);
343
439
  }
344
440
  }
345
- this._notifyCollisions();
346
- this._notifyTriggers();
441
+ // Notify collisions and triggers for all world regions
442
+ for (const region of this._worldRegions) {
443
+ this._notifyCollisions(region.world);
444
+ this._notifyTriggers(region.world);
445
+ }
347
446
  }
348
447
  /**
349
448
  * Returns the version of the physics engine plugin.
@@ -361,7 +460,9 @@ export class HavokPlugin {
361
460
  * @param maxAngularVelocity maximum allowed angular velocity
362
461
  */
363
462
  setVelocityLimits(maxLinearVelocity, maxAngularVelocity) {
364
- this._hknp.HP_World_SetSpeedLimit(this.world, maxLinearVelocity, maxAngularVelocity);
463
+ for (const region of this._worldRegions) {
464
+ this._hknp.HP_World_SetSpeedLimit(region.world, maxLinearVelocity, maxAngularVelocity);
465
+ }
365
466
  }
366
467
  /**
367
468
  * @returns maximum allowed linear velocity
@@ -391,9 +492,13 @@ export class HavokPlugin {
391
492
  initBody(body, motionType, position, orientation) {
392
493
  body._pluginData = new BodyPluginData(this._hknp.HP_Body_Create()[1]);
393
494
  this._internalSetMotionType(body._pluginData, motionType);
394
- const transform = [this._bVecToV3(position), this._bQuatToV4(orientation)]; //<todo temp transform?
495
+ // Get the world region for this body's position
496
+ const worldRegion = this._getOrCreateWorldRegion(position);
497
+ body._pluginData.worldRegion = worldRegion;
498
+ const offset = worldRegion.floatingOrigin;
499
+ const transform = [[position._x - offset._x, position._y - offset._y, position._z - offset._z], this._bQuatToV4(orientation)];
395
500
  this._hknp.HP_Body_SetQTransform(body._pluginData.hpBodyId, transform);
396
- this._hknp.HP_World_AddBody(this.world, body._pluginData.hpBodyId, body.startAsleep);
501
+ this._hknp.HP_World_AddBody(worldRegion.world, body._pluginData.hpBodyId, body.startAsleep);
397
502
  this._bodies.set(body._pluginData.hpBodyId[0], { body: body, index: 0 });
398
503
  }
399
504
  /**
@@ -405,13 +510,13 @@ export class HavokPlugin {
405
510
  if (body._pluginDataInstances && body._pluginDataInstances.length > 0) {
406
511
  for (const instance of body._pluginDataInstances) {
407
512
  this._bodyCollisionObservable.delete(instance.hpBodyId[0]);
408
- this._hknp.HP_World_RemoveBody(this.world, instance.hpBodyId);
513
+ this._hknp.HP_World_RemoveBody(instance.worldRegion.world, instance.hpBodyId);
409
514
  this._bodies.delete(instance.hpBodyId[0]);
410
515
  }
411
516
  }
412
517
  if (body._pluginData) {
413
518
  this._bodyCollisionObservable.delete(body._pluginData.hpBodyId[0]);
414
- this._hknp.HP_World_RemoveBody(this.world, body._pluginData.hpBodyId);
519
+ this._hknp.HP_World_RemoveBody(body._pluginData.worldRegion.world, body._pluginData.hpBodyId);
415
520
  this._bodies.delete(body._pluginData.hpBodyId[0]);
416
521
  }
417
522
  }
@@ -443,15 +548,29 @@ export class HavokPlugin {
443
548
  _createOrUpdateBodyInstances(body, motionType, matrixData, startIndex, endIndex, update) {
444
549
  const rotation = TmpVectors.Quaternion[0];
445
550
  const rotationMatrix = Matrix.Identity();
551
+ const worldPos = TmpVectors.Vector3[0];
446
552
  for (let i = startIndex; i < endIndex; i++) {
447
- const position = [matrixData[i * 16 + 12], matrixData[i * 16 + 13], matrixData[i * 16 + 14]];
553
+ // Get world position for this instance
554
+ worldPos.set(matrixData[i * 16 + 12], matrixData[i * 16 + 13], matrixData[i * 16 + 14]);
448
555
  let hkbody;
556
+ let pluginData;
449
557
  if (!update) {
450
558
  hkbody = this._hknp.HP_Body_Create()[1];
559
+ pluginData = new BodyPluginData(hkbody);
560
+ if (body._pluginDataInstances.length) {
561
+ // If an instance already exists, copy any user-provided mass properties
562
+ pluginData.userMassProps = body._pluginDataInstances[0].userMassProps;
563
+ }
451
564
  }
452
565
  else {
453
- hkbody = body._pluginDataInstances[i].hpBodyId;
566
+ pluginData = body._pluginDataInstances[i];
567
+ hkbody = pluginData.hpBodyId;
454
568
  }
569
+ // Get the world region for this instance's position
570
+ const worldRegion = this._getOrCreateWorldRegion(worldPos);
571
+ const offset = worldRegion.floatingOrigin;
572
+ // Subtract floating origin offset to get small coordinates for Havok (float32 precision)
573
+ const position = [worldPos._x - offset._x, worldPos._y - offset._y, worldPos._z - offset._z];
455
574
  rotationMatrix.setRowFromFloats(0, matrixData[i * 16 + 0], matrixData[i * 16 + 1], matrixData[i * 16 + 2], 0);
456
575
  rotationMatrix.setRowFromFloats(1, matrixData[i * 16 + 4], matrixData[i * 16 + 5], matrixData[i * 16 + 6], 0);
457
576
  rotationMatrix.setRowFromFloats(2, matrixData[i * 16 + 8], matrixData[i * 16 + 9], matrixData[i * 16 + 10], 0);
@@ -459,15 +578,12 @@ export class HavokPlugin {
459
578
  const transform = [position, [rotation.x, rotation.y, rotation.z, rotation.w]];
460
579
  this._hknp.HP_Body_SetQTransform(hkbody, transform);
461
580
  if (!update) {
462
- const pluginData = new BodyPluginData(hkbody);
463
- if (body._pluginDataInstances.length) {
464
- // If an instance already exists, copy any user-provided mass properties
465
- pluginData.userMassProps = body._pluginDataInstances[0].userMassProps;
466
- }
467
581
  this._internalSetMotionType(pluginData, motionType);
468
582
  this._internalUpdateMassProperties(pluginData);
469
583
  body._pluginDataInstances.push(pluginData);
470
- this._hknp.HP_World_AddBody(this.world, hkbody, body.startAsleep);
584
+ // Add to the appropriate world
585
+ pluginData.worldRegion = worldRegion;
586
+ this._hknp.HP_World_AddBody(worldRegion.world, hkbody, body.startAsleep);
471
587
  pluginData.worldTransformOffset = this._hknp.HP_Body_GetWorldTransformOffset(hkbody)[1];
472
588
  }
473
589
  }
@@ -504,7 +620,7 @@ export class HavokPlugin {
504
620
  for (let i = 0; i < instancesToRemove; i++) {
505
621
  const hkbody = body._pluginDataInstances.pop();
506
622
  this._bodies.delete(hkbody.hpBodyId[0]);
507
- this._hknp.HP_World_RemoveBody(this.world, hkbody.hpBodyId);
623
+ this._hknp.HP_World_RemoveBody(hkbody.worldRegion.world, hkbody.hpBodyId);
508
624
  this._hknp.HP_Body_Release(hkbody.hpBodyId);
509
625
  }
510
626
  this._createOrUpdateBodyInstances(body, motionType, matrixData, 0, instancesCount, true);
@@ -535,6 +651,8 @@ export class HavokPlugin {
535
651
  * physical behavior of the body.
536
652
  */
537
653
  syncTransform(body, transformNode) {
654
+ // Get the floating origin offset - this was subtracted when positions were sent to Havok
655
+ // We need to add it back to get the correct world position
538
656
  if (body._pluginDataInstances.length) {
539
657
  // instances
540
658
  const m = transformNode;
@@ -544,26 +662,40 @@ export class HavokPlugin {
544
662
  }
545
663
  const instancesCount = body._pluginDataInstances.length;
546
664
  for (let i = 0; i < instancesCount; i++) {
547
- const bufOffset = body._pluginDataInstances[i].worldTransformOffset;
548
- const transformBuffer = new Float32Array(this._hknp.HEAPU8.buffer, this._bodyBuffer + bufOffset, 16);
665
+ const pluginData = body._pluginDataInstances[i];
666
+ // Use instance's world region offset
667
+ const instanceOffset = pluginData.worldRegion.floatingOrigin;
668
+ const bodyBuffer = this._bodyBuffer;
669
+ const bufOffset = pluginData.worldTransformOffset;
670
+ const transformBuffer = new Float32Array(this._hknp.HEAPU8.buffer, bodyBuffer + bufOffset, 16);
549
671
  const index = i * 16;
550
672
  for (let mi = 0; mi < 15; mi++) {
551
673
  if ((mi & 3) != 3) {
552
674
  matrixData[index + mi] = transformBuffer[mi];
553
675
  }
554
676
  }
677
+ // Add back the floating origin offset to get world position
678
+ // (Havok stores position - offset, so we add offset back)
679
+ matrixData[index + 12] += instanceOffset._x;
680
+ matrixData[index + 13] += instanceOffset._y;
681
+ matrixData[index + 14] += instanceOffset._z;
555
682
  matrixData[index + 15] = 1;
556
683
  }
557
684
  m.thinInstanceBufferUpdated("matrix");
558
685
  }
559
686
  else {
560
687
  try {
561
- // regular
562
688
  const bodyTransform = this._hknp.HP_Body_GetQTransform(body._pluginData.hpBodyId)[1];
563
689
  const bodyTranslation = bodyTransform[0];
564
690
  const bodyOrientation = bodyTransform[1];
565
691
  const quat = TmpVectors.Quaternion[0];
692
+ // Use body's world region offset
693
+ const offset = body._pluginData.worldRegion.floatingOrigin;
566
694
  quat.set(bodyOrientation[0], bodyOrientation[1], bodyOrientation[2], bodyOrientation[3]);
695
+ // Add back the floating origin offset to get world position
696
+ const worldX = bodyTranslation[0] + offset._x;
697
+ const worldY = bodyTranslation[1] + offset._y;
698
+ const worldZ = bodyTranslation[2] + offset._z;
567
699
  const parent = transformNode.parent;
568
700
  // transform position/orientation in parent space
569
701
  if (parent && !parent.getWorldMatrix().isIdentity()) {
@@ -573,7 +705,7 @@ export class HavokPlugin {
573
705
  quat.normalize();
574
706
  const finalTransform = TmpVectors.Matrix[0];
575
707
  const finalTranslation = TmpVectors.Vector3[0];
576
- finalTranslation.copyFromFloats(bodyTranslation[0], bodyTranslation[1], bodyTranslation[2]);
708
+ finalTranslation.copyFromFloats(worldX, worldY, worldZ);
577
709
  Matrix.ComposeToRef(transformNode.absoluteScaling, quat, finalTranslation, finalTransform);
578
710
  const parentInverseTransform = TmpVectors.Matrix[1];
579
711
  parent.getWorldMatrix().invertToRef(parentInverseTransform);
@@ -585,7 +717,7 @@ export class HavokPlugin {
585
717
  transformNode.scaling.copyFrom(TmpVectors.Vector3[1]);
586
718
  }
587
719
  else {
588
- transformNode.position.set(bodyTranslation[0], bodyTranslation[1], bodyTranslation[2]);
720
+ transformNode.position.set(worldX, worldY, worldZ);
589
721
  if (transformNode.rotationQuaternion) {
590
722
  transformNode.rotationQuaternion.copyFrom(quat);
591
723
  }
@@ -938,7 +1070,8 @@ export class HavokPlugin {
938
1070
  */
939
1071
  applyImpulse(body, impulse, location, instanceIndex) {
940
1072
  this._applyToBodyOrInstances(body, (pluginRef) => {
941
- this._hknp.HP_Body_ApplyImpulse(pluginRef.hpBodyId, this._bVecToV3(location), this._bVecToV3(impulse));
1073
+ const offset = pluginRef.worldRegion.floatingOrigin;
1074
+ this._hknp.HP_Body_ApplyImpulse(pluginRef.hpBodyId, this._bVecToV3WithOffset(location, offset), this._bVecToV3(impulse));
942
1075
  }, instanceIndex);
943
1076
  }
944
1077
  /**
@@ -1036,8 +1169,9 @@ export class HavokPlugin {
1036
1169
  this._createOrUpdateBodyInstances(body, body.getMotionType(), matrixData, 0, instancesCount, true);
1037
1170
  }
1038
1171
  else {
1039
- // regular
1040
- this._hknp.HP_Body_SetQTransform(body._pluginData.hpBodyId, this._getTransformInfos(node));
1172
+ // regular - use body's world region offset
1173
+ const offset = body._pluginData.worldRegion.floatingOrigin;
1174
+ this._hknp.HP_Body_SetQTransform(body._pluginData.hpBodyId, this._getTransformInfos(node, offset));
1041
1175
  }
1042
1176
  }
1043
1177
  else if (body.getPrestepType() == PhysicsPrestepType.ACTION) {
@@ -1059,7 +1193,8 @@ export class HavokPlugin {
1059
1193
  */
1060
1194
  setTargetTransform(body, position, rotation, instanceIndex) {
1061
1195
  this._applyToBodyOrInstances(body, (pluginRef) => {
1062
- this._hknp.HP_Body_SetTargetQTransform(pluginRef.hpBodyId, [this._bVecToV3(position), this._bQuatToV4(rotation)]);
1196
+ const offset = pluginRef.worldRegion.floatingOrigin;
1197
+ this._hknp.HP_Body_SetTargetQTransform(pluginRef.hpBodyId, [this._bVecToV3WithOffset(position, offset), this._bQuatToV4(rotation)]);
1063
1198
  }, instanceIndex);
1064
1199
  }
1065
1200
  /**
@@ -1341,12 +1476,13 @@ export class HavokPlugin {
1341
1476
  * It first checks if the node has a rotation quaternion, and if not, it creates one from the node's rotation.
1342
1477
  * It then creates an array containing the position and orientation of the node and returns it.
1343
1478
  * @param node - The transform node.
1479
+ * @param offset - The floating origin offset to apply.
1344
1480
  * @returns An array containing the position and orientation of the node.
1345
1481
  */
1346
- _getTransformInfos(node) {
1482
+ _getTransformInfos(node, offset) {
1347
1483
  if (node.parent) {
1348
1484
  node.computeWorldMatrix(true);
1349
- return [this._bVecToV3(node.absolutePosition), this._bQuatToV4(node.absoluteRotationQuaternion)];
1485
+ return [this._bVecToV3WithOffset(node.absolutePosition, offset), this._bQuatToV4(node.absoluteRotationQuaternion)];
1350
1486
  }
1351
1487
  let orientation = TmpVectors.Quaternion[0];
1352
1488
  if (node.rotationQuaternion) {
@@ -1356,7 +1492,7 @@ export class HavokPlugin {
1356
1492
  const r = node.rotation;
1357
1493
  Quaternion.FromEulerAnglesToRef(r.x, r.y, r.z, orientation);
1358
1494
  }
1359
- const transform = [this._bVecToV3(node.position), this._bQuatToV4(orientation)];
1495
+ const transform = [this._bVecToV3WithOffset(node.position, offset), this._bQuatToV4(orientation)];
1360
1496
  return transform;
1361
1497
  }
1362
1498
  /**
@@ -1905,7 +2041,10 @@ export class HavokPlugin {
1905
2041
  const hitPos = hitData[3];
1906
2042
  const hitNormal = hitData[4];
1907
2043
  const hitTriangle = hitData[5];
1908
- result.setHitData({ x: hitNormal[0], y: hitNormal[1], z: hitNormal[2] }, { x: hitPos[0], y: hitPos[1], z: hitPos[2] }, hitTriangle);
2044
+ // Add floating origin offset back to hit position using the hit body's world region offset
2045
+ // If no hit body (shouldn't happen), use zero offset from default region
2046
+ const offset = hitBody?.body?._pluginData?.worldRegion?.floatingOrigin ?? this._worldRegions[0].floatingOrigin;
2047
+ result.setHitData({ x: hitNormal[0], y: hitNormal[1], z: hitNormal[2] }, { x: hitPos[0] + offset._x, y: hitPos[1] + offset._y, z: hitPos[2] + offset._z }, hitTriangle);
1909
2048
  }
1910
2049
  /**
1911
2050
  * Performs a raycast from a given start point to a given end point and stores the result in a given PhysicsRaycastResult object.
@@ -1929,9 +2068,15 @@ export class HavokPlugin {
1929
2068
  for (const raycastResult of results) {
1930
2069
  raycastResult.reset(from, to);
1931
2070
  }
1932
- const hkQuery = [this._bVecToV3(from), this._bVecToV3(to), [queryMembership, queryCollideWith], shouldHitTriggers, bodyToIgnore];
2071
+ // Use the ignored body's world region if available, otherwise use default region
2072
+ const worldRegion = query?.ignoreBody?._pluginData?.worldRegion ?? this._worldRegions[0];
2073
+ const offset = worldRegion.floatingOrigin;
2074
+ const world = worldRegion.world;
2075
+ const offsetFrom = this._bVecToV3WithOffset(from, offset);
2076
+ const offsetTo = this._bVecToV3WithOffset(to, offset);
2077
+ const hkQuery = [offsetFrom, offsetTo, [queryMembership, queryCollideWith], shouldHitTriggers, bodyToIgnore];
1933
2078
  const queryCollector = results.length === 1 || !this._multiQueryCollector ? this._queryCollector : this._multiQueryCollector;
1934
- this._hknp.HP_World_CastRayWithCollector(this.world, queryCollector, hkQuery);
2079
+ this._hknp.HP_World_CastRayWithCollector(world, queryCollector, hkQuery);
1935
2080
  const numHits = this._hknp.HP_QueryCollector_GetNumHits(queryCollector)[1];
1936
2081
  if (numHits <= 0) {
1937
2082
  return;
@@ -1948,7 +2093,8 @@ export class HavokPlugin {
1948
2093
  for (let i = 0; i < numHits; i++) {
1949
2094
  const [, hitData] = this._hknp.HP_QueryCollector_GetCastRayResult(queryCollector, i)[1];
1950
2095
  const hitPos = hitData[3];
1951
- from.subtractFromFloatsToRef(hitPos[0], hitPos[1], hitPos[2], this._tmpVec3[0]);
2096
+ // Use offsetFrom for distance calculation since hitPos is in Havok's offset space
2097
+ this._tmpVec3[0].set(offsetFrom[0] - hitPos[0], offsetFrom[1] - hitPos[1], offsetFrom[2] - hitPos[2]);
1952
2098
  const distance = this._tmpVec3[0].lengthSquared();
1953
2099
  hitDatas[i] = {
1954
2100
  hitData,
@@ -1974,8 +2120,12 @@ export class HavokPlugin {
1974
2120
  const queryCollideWith = query?.collisionFilter?.collideWith ?? ~0;
1975
2121
  result.reset();
1976
2122
  const bodyToIgnore = query.ignoreBody ? [BigInt(query.ignoreBody._pluginData.hpBodyId[0])] : [BigInt(0)];
1977
- const hkQuery = [this._bVecToV3(query.position), query.maxDistance, [queryMembership, queryCollideWith], query.shouldHitTriggers, bodyToIgnore];
1978
- this._hknp.HP_World_PointProximityWithCollector(this.world, this._queryCollector, hkQuery);
2123
+ // Use the ignored body's world region if available, otherwise use default region
2124
+ const worldRegion = query.ignoreBody?._pluginData?.worldRegion ?? this._worldRegions[0];
2125
+ const offset = worldRegion.floatingOrigin;
2126
+ const world = worldRegion.world;
2127
+ const hkQuery = [this._bVecToV3WithOffset(query.position, offset), query.maxDistance, [queryMembership, queryCollideWith], query.shouldHitTriggers, bodyToIgnore];
2128
+ this._hknp.HP_World_PointProximityWithCollector(world, this._queryCollector, hkQuery);
1979
2129
  if (this._hknp.HP_QueryCollector_GetNumHits(this._queryCollector)[1] > 0) {
1980
2130
  const [distance, hitData] = this._hknp.HP_QueryCollector_GetPointProximityResult(this._queryCollector, 0)[1];
1981
2131
  this._populateHitData(hitData, result);
@@ -1993,8 +2143,12 @@ export class HavokPlugin {
1993
2143
  hitShapeResult.reset();
1994
2144
  const shapeId = query.shape._pluginData;
1995
2145
  const bodyToIgnore = query.ignoreBody ? [BigInt(query.ignoreBody._pluginData.hpBodyId[0])] : [BigInt(0)];
1996
- const hkQuery = [shapeId, this._bVecToV3(query.position), this._bQuatToV4(query.rotation), query.maxDistance, query.shouldHitTriggers, bodyToIgnore];
1997
- this._hknp.HP_World_ShapeProximityWithCollector(this.world, this._queryCollector, hkQuery);
2146
+ // Use the ignored body's world region if available, otherwise use default region
2147
+ const worldRegion = query.ignoreBody?._pluginData?.worldRegion ?? this._worldRegions[0];
2148
+ const offset = worldRegion.floatingOrigin;
2149
+ const world = worldRegion.world;
2150
+ const hkQuery = [shapeId, this._bVecToV3WithOffset(query.position, offset), this._bQuatToV4(query.rotation), query.maxDistance, query.shouldHitTriggers, bodyToIgnore];
2151
+ this._hknp.HP_World_ShapeProximityWithCollector(world, this._queryCollector, hkQuery);
1998
2152
  if (this._hknp.HP_QueryCollector_GetNumHits(this._queryCollector)[1] > 0) {
1999
2153
  const [distance, hitInputData, hitShapeData] = this._hknp.HP_QueryCollector_GetShapeProximityResult(this._queryCollector, 0)[1];
2000
2154
  this._populateHitData(hitInputData, inputShapeResult);
@@ -2014,8 +2168,19 @@ export class HavokPlugin {
2014
2168
  hitShapeResult.reset();
2015
2169
  const shapeId = query.shape._pluginData;
2016
2170
  const bodyToIgnore = query.ignoreBody ? [BigInt(query.ignoreBody._pluginData.hpBodyId[0])] : [BigInt(0)];
2017
- const hkQuery = [shapeId, this._bQuatToV4(query.rotation), this._bVecToV3(query.startPosition), this._bVecToV3(query.endPosition), query.shouldHitTriggers, bodyToIgnore];
2018
- this._hknp.HP_World_ShapeCastWithCollector(this.world, this._queryCollector, hkQuery);
2171
+ // Use the ignored body's world region if available, otherwise use default region
2172
+ const worldRegion = query.ignoreBody?._pluginData?.worldRegion ?? this._worldRegions[0];
2173
+ const offset = worldRegion.floatingOrigin;
2174
+ const world = worldRegion.world;
2175
+ const hkQuery = [
2176
+ shapeId,
2177
+ this._bQuatToV4(query.rotation),
2178
+ this._bVecToV3WithOffset(query.startPosition, offset),
2179
+ this._bVecToV3WithOffset(query.endPosition, offset),
2180
+ query.shouldHitTriggers,
2181
+ bodyToIgnore,
2182
+ ];
2183
+ this._hknp.HP_World_ShapeCastWithCollector(world, this._queryCollector, hkQuery);
2019
2184
  if (this._hknp.HP_QueryCollector_GetNumHits(this._queryCollector)[1] > 0) {
2020
2185
  const [fractionAlongRay, hitInputData, hitShapeData] = this._hknp.HP_QueryCollector_GetShapeCastResult(this._queryCollector, 0)[1];
2021
2186
  this._populateHitData(hitInputData, inputShapeResult);
@@ -2093,8 +2258,9 @@ export class HavokPlugin {
2093
2258
  this._hknp.HP_Body_SetEventMask(body._pluginData.hpBodyId, currentCollideEvents);
2094
2259
  }
2095
2260
  }
2096
- _notifyTriggers() {
2097
- let eventAddress = this._hknp.HP_World_GetTriggerEvents(this.world)[1];
2261
+ _notifyTriggers(world) {
2262
+ const targetWorld = world ?? this.world;
2263
+ let eventAddress = this._hknp.HP_World_GetTriggerEvents(targetWorld)[1];
2098
2264
  const event = new TriggerEvent();
2099
2265
  while (eventAddress) {
2100
2266
  TriggerEvent.readToRef(this._hknp.HEAPU8.buffer, eventAddress, event);
@@ -2111,20 +2277,28 @@ export class HavokPlugin {
2111
2277
  };
2112
2278
  this.onTriggerCollisionObservable.notifyObservers(triggerCollisionInfo);
2113
2279
  }
2114
- eventAddress = this._hknp.HP_World_GetNextTriggerEvent(this.world, eventAddress);
2280
+ eventAddress = this._hknp.HP_World_GetNextTriggerEvent(targetWorld, eventAddress);
2115
2281
  }
2116
2282
  }
2117
2283
  /**
2118
2284
  * Runs thru all detected collisions and filter by body
2285
+ * @param world optional world to check collisions for (defaults to main world)
2119
2286
  */
2120
- _notifyCollisions() {
2121
- let eventAddress = this._hknp.HP_World_GetCollisionEvents(this.world)[1];
2287
+ _notifyCollisions(world) {
2288
+ const targetWorld = world ?? this.world;
2289
+ let eventAddress = this._hknp.HP_World_GetCollisionEvents(targetWorld)[1];
2122
2290
  const event = new CollisionEvent();
2123
- const worldAddr = Number(this.world);
2291
+ const worldAddr = Number(targetWorld);
2124
2292
  while (eventAddress) {
2125
2293
  CollisionEvent.readToRef(this._hknp.HEAPU8.buffer, eventAddress, event);
2126
2294
  const bodyInfoA = this._bodies.get(event.contactOnA.bodyId);
2127
2295
  const bodyInfoB = this._bodies.get(event.contactOnB.bodyId);
2296
+ // Add floating origin offset back to collision contact positions using the body's world region offset
2297
+ // If body doesn't exist, use default region's offset (zero)
2298
+ const offsetA = bodyInfoA?.body?._pluginData?.worldRegion?.floatingOrigin ?? this._worldRegions[0].floatingOrigin;
2299
+ event.contactOnA.position.addInPlace(offsetA);
2300
+ const offsetB = bodyInfoB?.body?._pluginData?.worldRegion?.floatingOrigin ?? this._worldRegions[0].floatingOrigin;
2301
+ event.contactOnB.position.addInPlace(offsetB);
2128
2302
  // Bodies may have been disposed between events. Check both still exist.
2129
2303
  if (bodyInfoA && bodyInfoB) {
2130
2304
  const collisionInfo = {
@@ -2212,12 +2386,16 @@ export class HavokPlugin {
2212
2386
  }
2213
2387
  if (this._multiQueryCollector) {
2214
2388
  this._hknp.HP_QueryCollector_Release(this._multiQueryCollector);
2215
- this._multiQueryCollector;
2389
+ this._multiQueryCollector = undefined;
2216
2390
  }
2217
- if (this.world) {
2218
- this._hknp.HP_World_Release(this.world);
2219
- this.world = undefined;
2391
+ // Dispose all world regions (includes the default world)
2392
+ for (const region of this._worldRegions) {
2393
+ if (region.world) {
2394
+ this._hknp.HP_World_Release(region.world);
2395
+ }
2220
2396
  }
2397
+ this._worldRegions.length = 0;
2398
+ this.world = undefined;
2221
2399
  }
2222
2400
  _v3ToBvecRef(v, vec3) {
2223
2401
  vec3.set(v[0], v[1], v[2]);
@@ -2225,6 +2403,19 @@ export class HavokPlugin {
2225
2403
  _bVecToV3(v) {
2226
2404
  return [v._x, v._y, v._z];
2227
2405
  }
2406
+ /**
2407
+ * Converts a Vector3 to Havok format with floating origin offset subtracted.
2408
+ * Use this for world-space positions being sent to Havok.
2409
+ * @param v - The vector to convert
2410
+ * @param offset - Optional offset to use. If not provided, no offset is applied.
2411
+ * @returns The converted vector
2412
+ */
2413
+ _bVecToV3WithOffset(v, offset) {
2414
+ if (offset) {
2415
+ return [v._x - offset._x, v._y - offset._y, v._z - offset._z];
2416
+ }
2417
+ return [v._x, v._y, v._z];
2418
+ }
2228
2419
  _bQuatToV4(q) {
2229
2420
  return [q._x, q._y, q._z, q._w];
2230
2421
  }