@onerjs/core 8.56.4 → 9.0.1

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 (722) hide show
  1. package/Animations/animatable.core.js +36 -0
  2. package/Animations/animatable.core.js.map +1 -1
  3. package/Animations/animationGroup.pure.d.ts +61 -1
  4. package/Animations/animationGroup.pure.js +191 -2
  5. package/Animations/animationGroup.pure.js.map +1 -1
  6. package/Animations/index.d.ts +1 -0
  7. package/Animations/index.js +1 -0
  8. package/Animations/index.js.map +1 -1
  9. package/Animations/pure.d.ts +1 -0
  10. package/Animations/pure.js +1 -0
  11. package/Animations/pure.js.map +1 -1
  12. package/Animations/rootMotion.d.ts +560 -0
  13. package/Animations/rootMotion.js +1709 -0
  14. package/Animations/rootMotion.js.map +1 -0
  15. package/Animations/runtimeAnimation.d.ts +57 -0
  16. package/Animations/runtimeAnimation.js +127 -3
  17. package/Animations/runtimeAnimation.js.map +1 -1
  18. package/Cameras/arcRotateCamera.pure.d.ts +2 -0
  19. package/Cameras/arcRotateCamera.pure.js +2 -0
  20. package/Cameras/arcRotateCamera.pure.js.map +1 -1
  21. package/Cameras/targetCamera.pure.d.ts +2 -0
  22. package/Cameras/targetCamera.pure.js +13 -2
  23. package/Cameras/targetCamera.pure.js.map +1 -1
  24. package/Collisions/gpuPicker.js +5 -5
  25. package/Collisions/gpuPicker.js.map +1 -1
  26. package/Engines/AbstractEngine/abstractEngine.query.pure.js +4 -2
  27. package/Engines/AbstractEngine/abstractEngine.query.pure.js.map +1 -1
  28. package/Engines/AbstractEngine/abstractEngine.query.types.d.ts +11 -2
  29. package/Engines/AbstractEngine/abstractEngine.query.types.js.map +1 -1
  30. package/Engines/AbstractEngine/abstractEngine.renderPass.pure.js +1 -0
  31. package/Engines/AbstractEngine/abstractEngine.renderPass.pure.js.map +1 -1
  32. package/Engines/Extensions/engine.multiRender.pure.js +63 -0
  33. package/Engines/Extensions/engine.multiRender.pure.js.map +1 -1
  34. package/Engines/Extensions/engine.multiRender.types.d.ts +13 -0
  35. package/Engines/Extensions/engine.multiRender.types.js.map +1 -1
  36. package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js +2 -2
  37. package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js.map +1 -1
  38. package/Engines/Extensions/engine.prefilteredCubeTexture.types.d.ts +2 -1
  39. package/Engines/Extensions/engine.prefilteredCubeTexture.types.js.map +1 -1
  40. package/Engines/Extensions/index.d.ts +1 -0
  41. package/Engines/Extensions/index.js +1 -0
  42. package/Engines/Extensions/index.js.map +1 -1
  43. package/Engines/Extensions/pure.d.ts +1 -1
  44. package/Engines/Extensions/pure.js +1 -1
  45. package/Engines/Extensions/pure.js.map +1 -1
  46. package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js +88 -39
  47. package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js.map +1 -1
  48. package/Engines/Native/Extensions/nativeEngine.cubeTexture.types.d.ts +20 -2
  49. package/Engines/Native/Extensions/nativeEngine.cubeTexture.types.js.map +1 -1
  50. package/Engines/Native/nativeHardwareTexture.d.ts +8 -1
  51. package/Engines/Native/nativeHardwareTexture.js +7 -0
  52. package/Engines/Native/nativeHardwareTexture.js.map +1 -1
  53. package/Engines/Native/nativeHelpers.js +56 -1
  54. package/Engines/Native/nativeHelpers.js.map +1 -1
  55. package/Engines/Native/nativeInterfaces.d.ts +37 -8
  56. package/Engines/Native/nativeInterfaces.js.map +1 -1
  57. package/Engines/Native/nativeRenderTargetWrapper.d.ts +40 -0
  58. package/Engines/Native/nativeRenderTargetWrapper.js +265 -5
  59. package/Engines/Native/nativeRenderTargetWrapper.js.map +1 -1
  60. package/Engines/Processors/shaderCodeCursor.d.ts +1 -0
  61. package/Engines/Processors/shaderCodeCursor.js +40 -3
  62. package/Engines/Processors/shaderCodeCursor.js.map +1 -1
  63. package/Engines/WebGPU/Extensions/engine.multiRender.pure.js +4 -0
  64. package/Engines/WebGPU/Extensions/engine.multiRender.pure.js.map +1 -1
  65. package/Engines/WebGPU/Extensions/engine.multiRender.types.d.ts +13 -0
  66. package/Engines/WebGPU/Extensions/engine.multiRender.types.js.map +1 -1
  67. package/Engines/WebGPU/Extensions/engine.query.pure.js +11 -3
  68. package/Engines/WebGPU/Extensions/engine.query.pure.js.map +1 -1
  69. package/Engines/WebGPU/Extensions/engine.renderTarget.pure.js +1 -0
  70. package/Engines/WebGPU/Extensions/engine.renderTarget.pure.js.map +1 -1
  71. package/Engines/WebGPU/Extensions/index.d.ts +1 -0
  72. package/Engines/WebGPU/Extensions/index.js +1 -0
  73. package/Engines/WebGPU/Extensions/index.js.map +1 -1
  74. package/Engines/WebGPU/Extensions/pure.d.ts +1 -1
  75. package/Engines/WebGPU/Extensions/pure.js +1 -1
  76. package/Engines/WebGPU/Extensions/pure.js.map +1 -1
  77. package/Engines/WebGPU/webgpuBundleList.d.ts +2 -0
  78. package/Engines/WebGPU/webgpuBundleList.js +4 -0
  79. package/Engines/WebGPU/webgpuBundleList.js.map +1 -1
  80. package/Engines/WebGPU/webgpuCacheRenderPipeline.js +5 -2
  81. package/Engines/WebGPU/webgpuCacheRenderPipeline.js.map +1 -1
  82. package/Engines/WebGPU/webgpuHardwareTexture.js +3 -1
  83. package/Engines/WebGPU/webgpuHardwareTexture.js.map +1 -1
  84. package/Engines/WebGPU/webgpuOcclusionQuery.js +1 -1
  85. package/Engines/WebGPU/webgpuOcclusionQuery.js.map +1 -1
  86. package/Engines/WebGPU/webgpuSnapshotRendering.d.ts +4 -0
  87. package/Engines/WebGPU/webgpuSnapshotRendering.js +40 -7
  88. package/Engines/WebGPU/webgpuSnapshotRendering.js.map +1 -1
  89. package/Engines/WebGPU/webgpuTextureHelper.d.ts +1 -1
  90. package/Engines/WebGPU/webgpuTextureHelper.js +2 -2
  91. package/Engines/WebGPU/webgpuTextureHelper.js.map +1 -1
  92. package/Engines/WebGPU/webgpuTextureManager.d.ts +2 -0
  93. package/Engines/WebGPU/webgpuTextureManager.js +286 -13
  94. package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
  95. package/Engines/abstractEngine.pure.d.ts +17 -1
  96. package/Engines/abstractEngine.pure.js +17 -5
  97. package/Engines/abstractEngine.pure.js.map +1 -1
  98. package/Engines/constants.d.ts +4 -0
  99. package/Engines/constants.js +4 -0
  100. package/Engines/constants.js.map +1 -1
  101. package/Engines/engine.pure.d.ts +0 -1
  102. package/Engines/engine.pure.js +0 -7
  103. package/Engines/engine.pure.js.map +1 -1
  104. package/Engines/nativeEngine.pure.js +1 -1
  105. package/Engines/nativeEngine.pure.js.map +1 -1
  106. package/Engines/thinEngine.pure.d.ts +15 -0
  107. package/Engines/thinEngine.pure.js +61 -14
  108. package/Engines/thinEngine.pure.js.map +1 -1
  109. package/Engines/thinNativeEngine.pure.d.ts +218 -17
  110. package/Engines/thinNativeEngine.pure.js +1438 -165
  111. package/Engines/thinNativeEngine.pure.js.map +1 -1
  112. package/Engines/thinWebGPUEngine.d.ts +4 -0
  113. package/Engines/thinWebGPUEngine.js +16 -2
  114. package/Engines/thinWebGPUEngine.js.map +1 -1
  115. package/Engines/webgpuEngine.pure.d.ts +17 -3
  116. package/Engines/webgpuEngine.pure.js +56 -13
  117. package/Engines/webgpuEngine.pure.js.map +1 -1
  118. package/FlowGraph/Blocks/Data/Math/flowGraphMathBlocks.pure.js +2 -2
  119. package/FlowGraph/Blocks/Data/Math/flowGraphMathBlocks.pure.js.map +1 -1
  120. package/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.pure.d.ts +10 -0
  121. package/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.pure.js +24 -12
  122. package/FlowGraph/Blocks/Data/Transformers/flowGraphJsonPointerParserBlock.pure.js.map +1 -1
  123. package/FlowGraph/Blocks/Data/Utils/flowGraphArrayIndexBlock.pure.d.ts +11 -2
  124. package/FlowGraph/Blocks/Data/Utils/flowGraphArrayIndexBlock.pure.js +1 -1
  125. package/FlowGraph/Blocks/Data/Utils/flowGraphArrayIndexBlock.pure.js.map +1 -1
  126. package/FlowGraph/Blocks/Data/flowGraphGetPropertyBlock.pure.d.ts +7 -0
  127. package/FlowGraph/Blocks/Data/flowGraphGetPropertyBlock.pure.js +43 -0
  128. package/FlowGraph/Blocks/Data/flowGraphGetPropertyBlock.pure.js.map +1 -1
  129. package/FlowGraph/Blocks/Event/flowGraphMeshPickEventBlock.pure.d.ts +9 -1
  130. package/FlowGraph/Blocks/Event/flowGraphMeshPickEventBlock.pure.js +6 -8
  131. package/FlowGraph/Blocks/Event/flowGraphMeshPickEventBlock.pure.js.map +1 -1
  132. package/FlowGraph/Blocks/Event/flowGraphPointerOutEventBlock.pure.d.ts +2 -0
  133. package/FlowGraph/Blocks/Event/flowGraphPointerOutEventBlock.pure.js +5 -1
  134. package/FlowGraph/Blocks/Event/flowGraphPointerOutEventBlock.pure.js.map +1 -1
  135. package/FlowGraph/Blocks/Event/flowGraphPointerOverEventBlock.pure.d.ts +2 -0
  136. package/FlowGraph/Blocks/Event/flowGraphPointerOverEventBlock.pure.js +5 -1
  137. package/FlowGraph/Blocks/Event/flowGraphPointerOverEventBlock.pure.js.map +1 -1
  138. package/FlowGraph/Blocks/Event/flowGraphReceiveCustomEventBlock.pure.d.ts +9 -0
  139. package/FlowGraph/Blocks/Event/flowGraphReceiveCustomEventBlock.pure.js +34 -9
  140. package/FlowGraph/Blocks/Event/flowGraphReceiveCustomEventBlock.pure.js.map +1 -1
  141. package/FlowGraph/Blocks/Event/flowGraphSceneReadyEventBlock.pure.d.ts +2 -0
  142. package/FlowGraph/Blocks/Event/flowGraphSceneReadyEventBlock.pure.js +4 -0
  143. package/FlowGraph/Blocks/Event/flowGraphSceneReadyEventBlock.pure.js.map +1 -1
  144. package/FlowGraph/Blocks/Event/flowGraphSceneTickEventBlock.pure.d.ts +18 -4
  145. package/FlowGraph/Blocks/Event/flowGraphSceneTickEventBlock.pure.js +24 -6
  146. package/FlowGraph/Blocks/Event/flowGraphSceneTickEventBlock.pure.js.map +1 -1
  147. package/FlowGraph/Blocks/Event/flowGraphSendCustomEventBlock.pure.js +19 -7
  148. package/FlowGraph/Blocks/Event/flowGraphSendCustomEventBlock.pure.js.map +1 -1
  149. package/FlowGraph/Blocks/Execution/Animation/flowGraphInterpolationBlock.pure.js +3 -3
  150. package/FlowGraph/Blocks/Execution/Animation/flowGraphInterpolationBlock.pure.js.map +1 -1
  151. package/FlowGraph/Blocks/Execution/Animation/flowGraphPlayAnimationBlock.pure.d.ts +20 -2
  152. package/FlowGraph/Blocks/Execution/Animation/flowGraphPlayAnimationBlock.pure.js +85 -25
  153. package/FlowGraph/Blocks/Execution/Animation/flowGraphPlayAnimationBlock.pure.js.map +1 -1
  154. package/FlowGraph/Blocks/Execution/Animation/flowGraphStopAnimationBlock.pure.d.ts +16 -1
  155. package/FlowGraph/Blocks/Execution/Animation/flowGraphStopAnimationBlock.pure.js +64 -14
  156. package/FlowGraph/Blocks/Execution/Animation/flowGraphStopAnimationBlock.pure.js.map +1 -1
  157. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphCancelDelayBlock.pure.d.ts +12 -1
  158. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphCancelDelayBlock.pure.js +8 -0
  159. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphCancelDelayBlock.pure.js.map +1 -1
  160. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphForLoopBlock.pure.js +4 -1
  161. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphForLoopBlock.pure.js.map +1 -1
  162. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphThrottleBlock.pure.d.ts +12 -1
  163. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphThrottleBlock.pure.js +5 -1
  164. package/FlowGraph/Blocks/Execution/ControlFlow/flowGraphThrottleBlock.pure.js.map +1 -1
  165. package/FlowGraph/Blocks/Execution/flowGraphConsoleLogBlock.pure.js +64 -16
  166. package/FlowGraph/Blocks/Execution/flowGraphConsoleLogBlock.pure.js.map +1 -1
  167. package/FlowGraph/Blocks/Execution/flowGraphSetPropertyBlock.pure.d.ts +2 -0
  168. package/FlowGraph/Blocks/Execution/flowGraphSetPropertyBlock.pure.js +14 -2
  169. package/FlowGraph/Blocks/Execution/flowGraphSetPropertyBlock.pure.js.map +1 -1
  170. package/FlowGraph/Blocks/Execution/flowGraphSetVariableBlock.pure.d.ts +5 -1
  171. package/FlowGraph/Blocks/Execution/flowGraphSetVariableBlock.pure.js +23 -8
  172. package/FlowGraph/Blocks/Execution/flowGraphSetVariableBlock.pure.js.map +1 -1
  173. package/FlowGraph/CustomTypes/flowGraphInteger.pure.d.ts +5 -0
  174. package/FlowGraph/CustomTypes/flowGraphInteger.pure.js +7 -0
  175. package/FlowGraph/CustomTypes/flowGraphInteger.pure.js.map +1 -1
  176. package/FlowGraph/CustomTypes/flowGraphMatrix.d.ts +10 -0
  177. package/FlowGraph/CustomTypes/flowGraphMatrix.js +14 -0
  178. package/FlowGraph/CustomTypes/flowGraphMatrix.js.map +1 -1
  179. package/FlowGraph/flowGraph.d.ts +6 -1
  180. package/FlowGraph/flowGraph.js +41 -9
  181. package/FlowGraph/flowGraph.js.map +1 -1
  182. package/FlowGraph/flowGraphAnimationHelpers.d.ts +24 -0
  183. package/FlowGraph/flowGraphAnimationHelpers.js +21 -0
  184. package/FlowGraph/flowGraphAnimationHelpers.js.map +1 -0
  185. package/FlowGraph/flowGraphBlock.js +3 -0
  186. package/FlowGraph/flowGraphBlock.js.map +1 -1
  187. package/FlowGraph/flowGraphConnection.d.ts +7 -0
  188. package/FlowGraph/flowGraphConnection.js +7 -0
  189. package/FlowGraph/flowGraphConnection.js.map +1 -1
  190. package/FlowGraph/flowGraphContext.d.ts +2 -1
  191. package/FlowGraph/flowGraphContext.js +5 -3
  192. package/FlowGraph/flowGraphContext.js.map +1 -1
  193. package/FlowGraph/flowGraphCoordinator.d.ts +15 -1
  194. package/FlowGraph/flowGraphCoordinator.js +47 -16
  195. package/FlowGraph/flowGraphCoordinator.js.map +1 -1
  196. package/FlowGraph/flowGraphEventBlock.d.ts +5 -0
  197. package/FlowGraph/flowGraphEventBlock.js +7 -0
  198. package/FlowGraph/flowGraphEventBlock.js.map +1 -1
  199. package/FlowGraph/flowGraphHostResolver.d.ts +2 -1
  200. package/FlowGraph/flowGraphHostResolver.js.map +1 -1
  201. package/FlowGraph/flowGraphParser.js +60 -2
  202. package/FlowGraph/flowGraphParser.js.map +1 -1
  203. package/FlowGraph/flowGraphValidator.js +0 -4
  204. package/FlowGraph/flowGraphValidator.js.map +1 -1
  205. package/FlowGraph/index.d.ts +2 -0
  206. package/FlowGraph/index.js +2 -0
  207. package/FlowGraph/index.js.map +1 -1
  208. package/FlowGraph/pure.d.ts +2 -0
  209. package/FlowGraph/pure.js +2 -0
  210. package/FlowGraph/pure.js.map +1 -1
  211. package/FlowGraph/serialization.d.ts +4 -2
  212. package/FlowGraph/serialization.js +12 -24
  213. package/FlowGraph/serialization.js.map +1 -1
  214. package/FlowGraph/typeDefinitions.d.ts +9 -1
  215. package/FlowGraph/typeDefinitions.js.map +1 -1
  216. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.d.ts +5 -0
  217. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.js +8 -0
  218. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.js.map +1 -0
  219. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.pure.d.ts +87 -0
  220. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.pure.js +295 -0
  221. package/FrameGraph/Node/Blocks/PostProcesses/meshBlendingPostProcessBlock.pure.js.map +1 -0
  222. package/FrameGraph/Node/Blocks/PostProcesses/pure.d.ts +1 -0
  223. package/FrameGraph/Node/Blocks/PostProcesses/pure.js +1 -0
  224. package/FrameGraph/Node/Blocks/PostProcesses/pure.js.map +1 -1
  225. package/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.js +4 -4
  226. package/FrameGraph/Node/Blocks/Rendering/baseObjectRendererBlock.js.map +1 -1
  227. package/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.pure.d.ts +5 -1
  228. package/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.pure.js +13 -1
  229. package/FrameGraph/Node/Blocks/Rendering/geometryRendererBlock.pure.js.map +1 -1
  230. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.d.ts +1 -0
  231. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.js +4 -0
  232. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.js.map +1 -0
  233. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.pure.d.ts +54 -0
  234. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.pure.js +155 -0
  235. package/FrameGraph/Node/Blocks/Textures/minMaxReducerBlock.pure.js.map +1 -0
  236. package/FrameGraph/Node/Blocks/Textures/pure.d.ts +1 -0
  237. package/FrameGraph/Node/Blocks/Textures/pure.js +1 -0
  238. package/FrameGraph/Node/Blocks/Textures/pure.js.map +1 -1
  239. package/FrameGraph/Node/Blocks/allBlocks.pure.js +4 -0
  240. package/FrameGraph/Node/Blocks/allBlocks.pure.js.map +1 -1
  241. package/FrameGraph/Node/Blocks/index.d.ts +2 -0
  242. package/FrameGraph/Node/Blocks/index.js +2 -0
  243. package/FrameGraph/Node/Blocks/index.js.map +1 -1
  244. package/FrameGraph/Node/Blocks/inputBlock.pure.js +20 -1
  245. package/FrameGraph/Node/Blocks/inputBlock.pure.js.map +1 -1
  246. package/FrameGraph/Node/Blocks/pure.d.ts +2 -0
  247. package/FrameGraph/Node/Blocks/pure.js +2 -0
  248. package/FrameGraph/Node/Blocks/pure.js.map +1 -1
  249. package/FrameGraph/Node/Types/nodeRenderGraphTypes.d.ts +4 -2
  250. package/FrameGraph/Node/Types/nodeRenderGraphTypes.js +4 -2
  251. package/FrameGraph/Node/Types/nodeRenderGraphTypes.js.map +1 -1
  252. package/FrameGraph/Node/nodeRenderGraph.js +1 -1
  253. package/FrameGraph/Node/nodeRenderGraph.js.map +1 -1
  254. package/FrameGraph/Tasks/Layers/selectionOutlineTask.js +1 -0
  255. package/FrameGraph/Tasks/Layers/selectionOutlineTask.js.map +1 -1
  256. package/FrameGraph/Tasks/Misc/cullObjectsTask.js +5 -1
  257. package/FrameGraph/Tasks/Misc/cullObjectsTask.js.map +1 -1
  258. package/FrameGraph/Tasks/Misc/lightingVolumeTask.js +1 -0
  259. package/FrameGraph/Tasks/Misc/lightingVolumeTask.js.map +1 -1
  260. package/FrameGraph/Tasks/Misc/minMaxReducerTask.d.ts +62 -0
  261. package/FrameGraph/Tasks/Misc/minMaxReducerTask.js +159 -0
  262. package/FrameGraph/Tasks/Misc/minMaxReducerTask.js.map +1 -0
  263. package/FrameGraph/Tasks/PostProcesses/meshBlendingTask.d.ts +69 -0
  264. package/FrameGraph/Tasks/PostProcesses/meshBlendingTask.js +223 -0
  265. package/FrameGraph/Tasks/PostProcesses/meshBlendingTask.js.map +1 -0
  266. package/FrameGraph/Tasks/Rendering/geometryRendererTask.d.ts +25 -3
  267. package/FrameGraph/Tasks/Rendering/geometryRendererTask.js +72 -34
  268. package/FrameGraph/Tasks/Rendering/geometryRendererTask.js.map +1 -1
  269. package/FrameGraph/Tasks/Rendering/objectRendererTask.js +3 -1
  270. package/FrameGraph/Tasks/Rendering/objectRendererTask.js.map +1 -1
  271. package/FrameGraph/frameGraph.d.ts +4 -0
  272. package/FrameGraph/frameGraph.js +14 -0
  273. package/FrameGraph/frameGraph.js.map +1 -1
  274. package/FrameGraph/frameGraphObjectList.d.ts +6 -1
  275. package/FrameGraph/frameGraphObjectList.js.map +1 -1
  276. package/FrameGraph/frameGraphRenderContext.d.ts +3 -1
  277. package/FrameGraph/frameGraphRenderContext.js +5 -5
  278. package/FrameGraph/frameGraphRenderContext.js.map +1 -1
  279. package/FrameGraph/index.d.ts +2 -0
  280. package/FrameGraph/index.js +2 -0
  281. package/FrameGraph/index.js.map +1 -1
  282. package/FrameGraph/pure.d.ts +2 -0
  283. package/FrameGraph/pure.js +2 -0
  284. package/FrameGraph/pure.js.map +1 -1
  285. package/Inputs/scene.inputManager.d.ts +4 -0
  286. package/Inputs/scene.inputManager.js +50 -8
  287. package/Inputs/scene.inputManager.js.map +1 -1
  288. package/Lights/Clustered/clusteredLightingSceneComponent.pure.d.ts +5 -0
  289. package/Lights/Clustered/clusteredLightingSceneComponent.pure.js +22 -1
  290. package/Lights/Clustered/clusteredLightingSceneComponent.pure.js.map +1 -1
  291. package/Lights/Shadows/cascadedShadowGenerator.pure.js +7 -3
  292. package/Lights/Shadows/cascadedShadowGenerator.pure.js.map +1 -1
  293. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.d.ts +7 -0
  294. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.js +8 -0
  295. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.js.map +1 -0
  296. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.pure.d.ts +54 -0
  297. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.pure.js +81 -0
  298. package/Materials/GaussianSplatting/gaussianPointSplattingBlitMaterial.pure.js.map +1 -0
  299. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.d.ts +7 -0
  300. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.js +8 -0
  301. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.js.map +1 -0
  302. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.pure.d.ts +60 -0
  303. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.pure.js +90 -0
  304. package/Materials/GaussianSplatting/gaussianPointSplattingDepthBlitMaterial.pure.js.map +1 -0
  305. package/Materials/GaussianSplatting/gaussianSplattingDebugMaterialPlugin.pure.d.ts +31 -0
  306. package/Materials/GaussianSplatting/gaussianSplattingDebugMaterialPlugin.pure.js +103 -5
  307. package/Materials/GaussianSplatting/gaussianSplattingDebugMaterialPlugin.pure.js.map +1 -1
  308. package/Materials/GaussianSplatting/gaussianSplattingGpuPickingMaterialPlugin.pure.js +6 -6
  309. package/Materials/GaussianSplatting/gaussianSplattingGpuPickingMaterialPlugin.pure.js.map +1 -1
  310. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.d.ts +26 -1
  311. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +153 -49
  312. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
  313. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.d.ts +1 -0
  314. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.js +4 -0
  315. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.js.map +1 -0
  316. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.pure.d.ts +83 -0
  317. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.pure.js +191 -0
  318. package/Materials/GaussianSplatting/gaussianSplattingOverdrawMaterialPlugin.pure.js.map +1 -0
  319. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.d.ts +1 -0
  320. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.js +4 -0
  321. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.js.map +1 -0
  322. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.pure.d.ts +62 -0
  323. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.pure.js +125 -0
  324. package/Materials/GaussianSplatting/gaussianSplattingSizeMaterialPlugin.pure.js.map +1 -0
  325. package/Materials/GaussianSplatting/gaussianSplattingSolidColorMaterialPlugin.pure.js +5 -5
  326. package/Materials/GaussianSplatting/gaussianSplattingSolidColorMaterialPlugin.pure.js.map +1 -1
  327. package/Materials/GaussianSplatting/pure.d.ts +4 -0
  328. package/Materials/GaussianSplatting/pure.js +4 -0
  329. package/Materials/GaussianSplatting/pure.js.map +1 -1
  330. package/Materials/Node/Blocks/Dual/imageSourceBlock.pure.d.ts +1 -0
  331. package/Materials/Node/Blocks/Dual/imageSourceBlock.pure.js +12 -0
  332. package/Materials/Node/Blocks/Dual/imageSourceBlock.pure.js.map +1 -1
  333. package/Materials/Node/Blocks/Fragment/fragmentOutputBlock.pure.js +11 -1
  334. package/Materials/Node/Blocks/Fragment/fragmentOutputBlock.pure.js.map +1 -1
  335. package/Materials/Node/Blocks/Fragment/prePassOutputBlock.pure.js +17 -2
  336. package/Materials/Node/Blocks/Fragment/prePassOutputBlock.pure.js.map +1 -1
  337. package/Materials/Node/Blocks/GaussianSplatting/gaussianSplattingBlock.pure.js +2 -2
  338. package/Materials/Node/Blocks/GaussianSplatting/gaussianSplattingBlock.pure.js.map +1 -1
  339. package/Materials/Node/nodeMaterial.pure.d.ts +4 -0
  340. package/Materials/Node/nodeMaterial.pure.js +4 -0
  341. package/Materials/Node/nodeMaterial.pure.js.map +1 -1
  342. package/Materials/Node/nodeMaterialBuildState.d.ts +1 -1
  343. package/Materials/Node/nodeMaterialBuildState.js +25 -3
  344. package/Materials/Node/nodeMaterialBuildState.js.map +1 -1
  345. package/Materials/PBR/openpbrMaterial.pure.d.ts +2 -0
  346. package/Materials/PBR/pbrBaseMaterial.pure.d.ts +2 -0
  347. package/Materials/Textures/Procedurals/proceduralTexture.pure.d.ts +14 -14
  348. package/Materials/Textures/Procedurals/proceduralTexture.pure.js +37 -13
  349. package/Materials/Textures/Procedurals/proceduralTexture.pure.js.map +1 -1
  350. package/Materials/Textures/baseTexture.pure.js +3 -0
  351. package/Materials/Textures/baseTexture.pure.js.map +1 -1
  352. package/Materials/Textures/cubeTexture.pure.js +1 -1
  353. package/Materials/Textures/cubeTexture.pure.js.map +1 -1
  354. package/Materials/Textures/internalTexture.d.ts +8 -1
  355. package/Materials/Textures/internalTexture.js +9 -2
  356. package/Materials/Textures/internalTexture.js.map +1 -1
  357. package/Materials/Textures/mirrorTexture.pure.js +3 -1
  358. package/Materials/Textures/mirrorTexture.pure.js.map +1 -1
  359. package/Materials/Textures/rawTexture2DArray.functions.d.ts +3 -3
  360. package/Materials/Textures/rawTexture2DArray.functions.js.map +1 -1
  361. package/Materials/Textures/rawTexture3D.d.ts +1 -1
  362. package/Materials/Textures/rawTexture3D.js +1 -1
  363. package/Materials/Textures/rawTexture3D.js.map +1 -1
  364. package/Materials/Textures/texture.pure.js +1 -1
  365. package/Materials/Textures/texture.pure.js.map +1 -1
  366. package/Materials/Textures/textureHelper.functions.d.ts +14 -0
  367. package/Materials/Textures/textureHelper.functions.js +24 -0
  368. package/Materials/Textures/textureHelper.functions.js.map +1 -1
  369. package/Materials/ditheredTileFadeMaterialPlugin.d.ts +210 -0
  370. package/Materials/ditheredTileFadeMaterialPlugin.js +509 -0
  371. package/Materials/ditheredTileFadeMaterialPlugin.js.map +1 -0
  372. package/Materials/effectRenderer.pure.d.ts +4 -0
  373. package/Materials/effectRenderer.pure.js +3 -2
  374. package/Materials/effectRenderer.pure.js.map +1 -1
  375. package/Materials/index.d.ts +5 -0
  376. package/Materials/index.js +5 -0
  377. package/Materials/index.js.map +1 -1
  378. package/Materials/material.pure.js +25 -12
  379. package/Materials/material.pure.js.map +1 -1
  380. package/Materials/materialHelper.geometryrendering.d.ts +46 -1
  381. package/Materials/materialHelper.geometryrendering.js +105 -8
  382. package/Materials/materialHelper.geometryrendering.js.map +1 -1
  383. package/Materials/prepass.defines.d.ts +2 -0
  384. package/Materials/prepass.defines.js +2 -0
  385. package/Materials/prepass.defines.js.map +1 -1
  386. package/Materials/pure.d.ts +5 -0
  387. package/Materials/pure.js +5 -0
  388. package/Materials/pure.js.map +1 -1
  389. package/Materials/standardMaterial.pure.d.ts +10 -0
  390. package/Materials/standardMaterial.pure.js +30 -5
  391. package/Materials/standardMaterial.pure.js.map +1 -1
  392. package/Meshes/Builders/polygonBuilder.pure.d.ts +4 -0
  393. package/Meshes/Builders/polygonBuilder.pure.js +3 -0
  394. package/Meshes/Builders/polygonBuilder.pure.js.map +1 -1
  395. package/Meshes/GaussianSplatting/gaussianPointSplattingController.d.ts +8 -0
  396. package/Meshes/GaussianSplatting/gaussianPointSplattingController.js +11 -0
  397. package/Meshes/GaussianSplatting/gaussianPointSplattingController.js.map +1 -0
  398. package/Meshes/GaussianSplatting/gaussianPointSplattingController.pure.d.ts +231 -0
  399. package/Meshes/GaussianSplatting/gaussianPointSplattingController.pure.js +1212 -0
  400. package/Meshes/GaussianSplatting/gaussianPointSplattingController.pure.js.map +1 -0
  401. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.d.ts +14 -0
  402. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.js +15 -0
  403. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.js.map +1 -0
  404. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.pure.d.ts +285 -0
  405. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.pure.js +812 -0
  406. package/Meshes/GaussianSplatting/gaussianPointSplattingRenderer.pure.js.map +1 -0
  407. package/Meshes/GaussianSplatting/gaussianSplatting.functions.d.ts +19 -0
  408. package/Meshes/GaussianSplatting/gaussianSplatting.functions.js +23 -0
  409. package/Meshes/GaussianSplatting/gaussianSplatting.functions.js.map +1 -0
  410. package/Meshes/GaussianSplatting/gaussianSplattingMesh.d.ts +1 -0
  411. package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +2 -0
  412. package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
  413. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +163 -14
  414. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +239 -24
  415. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
  416. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +34 -4
  417. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +125 -25
  418. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
  419. package/Meshes/GaussianSplatting/pure.d.ts +2 -0
  420. package/Meshes/GaussianSplatting/pure.js +2 -0
  421. package/Meshes/GaussianSplatting/pure.js.map +1 -1
  422. package/Meshes/Node/Blocks/booleanGeometryBlock.pure.js +25 -11
  423. package/Meshes/Node/Blocks/booleanGeometryBlock.pure.js.map +1 -1
  424. package/Meshes/abstractMesh.pure.d.ts +30 -0
  425. package/Meshes/abstractMesh.pure.js +54 -0
  426. package/Meshes/abstractMesh.pure.js.map +1 -1
  427. package/Meshes/index.d.ts +2 -0
  428. package/Meshes/index.js +2 -0
  429. package/Meshes/index.js.map +1 -1
  430. package/Meshes/instancedMesh.pure.d.ts +5 -0
  431. package/Meshes/instancedMesh.pure.js +12 -0
  432. package/Meshes/instancedMesh.pure.js.map +1 -1
  433. package/Meshes/mesh.pure.js +23 -8
  434. package/Meshes/mesh.pure.js.map +1 -1
  435. package/Meshes/meshBlendingTag.d.ts +47 -0
  436. package/Meshes/meshBlendingTag.js +64 -0
  437. package/Meshes/meshBlendingTag.js.map +1 -0
  438. package/Meshes/polygonMesh.js +2 -2
  439. package/Meshes/polygonMesh.js.map +1 -1
  440. package/Meshes/pure.d.ts +2 -0
  441. package/Meshes/pure.js +2 -0
  442. package/Meshes/pure.js.map +1 -1
  443. package/Meshes/subMesh.pure.d.ts +11 -2
  444. package/Meshes/subMesh.pure.js +20 -5
  445. package/Meshes/subMesh.pure.js.map +1 -1
  446. package/Meshes/thinInstanceMesh.pure.js +1 -0
  447. package/Meshes/thinInstanceMesh.pure.js.map +1 -1
  448. package/Misc/andOrNotEvaluator.js +4 -0
  449. package/Misc/andOrNotEvaluator.js.map +1 -1
  450. package/Misc/fileTools.pure.js +21 -0
  451. package/Misc/fileTools.pure.js.map +1 -1
  452. package/Misc/minMaxReducer.pure.d.ts +6 -0
  453. package/Misc/minMaxReducer.pure.js +10 -0
  454. package/Misc/minMaxReducer.pure.js.map +1 -1
  455. package/Misc/snapshotRenderingHelper.js +2 -2
  456. package/Misc/snapshotRenderingHelper.js.map +1 -1
  457. package/Misc/thinMinMaxReducer.d.ts +19 -2
  458. package/Misc/thinMinMaxReducer.js +74 -21
  459. package/Misc/thinMinMaxReducer.js.map +1 -1
  460. package/Misc/tools.pure.js +1 -1
  461. package/Misc/tools.pure.js.map +1 -1
  462. package/Particles/Node/Blocks/Update/updateNoiseBlock.pure.js +19 -7
  463. package/Particles/Node/Blocks/Update/updateNoiseBlock.pure.js.map +1 -1
  464. package/Particles/Node/Blocks/particleSourceTextureBlock.pure.js +3 -2
  465. package/Particles/Node/Blocks/particleSourceTextureBlock.pure.js.map +1 -1
  466. package/Particles/gpuParticleSystem.pure.d.ts +4 -0
  467. package/Particles/gpuParticleSystem.pure.js +101 -32
  468. package/Particles/gpuParticleSystem.pure.js.map +1 -1
  469. package/Particles/particle.js +3 -2
  470. package/Particles/particle.js.map +1 -1
  471. package/Particles/solidParticleSystem.js +7 -1
  472. package/Particles/solidParticleSystem.js.map +1 -1
  473. package/Particles/thinParticleSystem.function.d.ts +6 -0
  474. package/Particles/thinParticleSystem.function.js +144 -88
  475. package/Particles/thinParticleSystem.function.js.map +1 -1
  476. package/Particles/thinParticleSystem.pure.d.ts +8 -0
  477. package/Particles/thinParticleSystem.pure.js +154 -28
  478. package/Particles/thinParticleSystem.pure.js.map +1 -1
  479. package/Particles/webgl2ParticleSystem.pure.d.ts +1 -0
  480. package/Particles/webgl2ParticleSystem.pure.js +12 -4
  481. package/Particles/webgl2ParticleSystem.pure.js.map +1 -1
  482. package/Physics/v2/ragdoll.d.ts +2 -4
  483. package/Physics/v2/ragdoll.js +11 -4
  484. package/Physics/v2/ragdoll.js.map +1 -1
  485. package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.pure.js +7 -0
  486. package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.pure.js.map +1 -1
  487. package/PostProcesses/index.d.ts +2 -0
  488. package/PostProcesses/index.js +2 -0
  489. package/PostProcesses/index.js.map +1 -1
  490. package/PostProcesses/meshBlendingBlueNoise.d.ts +15 -0
  491. package/PostProcesses/meshBlendingBlueNoise.js +77 -0
  492. package/PostProcesses/meshBlendingBlueNoise.js.map +1 -0
  493. package/PostProcesses/meshBlendingPostProcess.d.ts +131 -0
  494. package/PostProcesses/meshBlendingPostProcess.js +315 -0
  495. package/PostProcesses/meshBlendingPostProcess.js.map +1 -0
  496. package/PostProcesses/pure.d.ts +2 -0
  497. package/PostProcesses/pure.js +2 -0
  498. package/PostProcesses/pure.js.map +1 -1
  499. package/PostProcesses/thinMeshBlendingPostProcess.d.ts +339 -0
  500. package/PostProcesses/thinMeshBlendingPostProcess.js +771 -0
  501. package/PostProcesses/thinMeshBlendingPostProcess.js.map +1 -0
  502. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js +6 -6
  503. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js.map +1 -1
  504. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.d.ts +12 -0
  505. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js +50 -25
  506. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js.map +1 -1
  507. package/Rendering/boundingBoxRenderer.pure.js +2 -1
  508. package/Rendering/boundingBoxRenderer.pure.js.map +1 -1
  509. package/Rendering/depthRenderer.pure.d.ts +9 -0
  510. package/Rendering/depthRenderer.pure.js +15 -4
  511. package/Rendering/depthRenderer.pure.js.map +1 -1
  512. package/Rendering/edgesRenderer.pure.d.ts +4 -2
  513. package/Rendering/edgesRenderer.pure.js +11 -2
  514. package/Rendering/edgesRenderer.pure.js.map +1 -1
  515. package/Rendering/fluidRenderer/fluidRenderingObject.d.ts +14 -0
  516. package/Rendering/fluidRenderer/fluidRenderingObject.js +26 -0
  517. package/Rendering/fluidRenderer/fluidRenderingObject.js.map +1 -1
  518. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.d.ts +13 -3
  519. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js +22 -9
  520. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js.map +1 -1
  521. package/Rendering/fluidRenderer/fluidRenderingTargetRenderer.js +3 -0
  522. package/Rendering/fluidRenderer/fluidRenderingTargetRenderer.js.map +1 -1
  523. package/Rendering/geometryBufferRenderer.pure.d.ts +38 -4
  524. package/Rendering/geometryBufferRenderer.pure.js +130 -18
  525. package/Rendering/geometryBufferRenderer.pure.js.map +1 -1
  526. package/Rendering/objectRenderer.d.ts +7 -1
  527. package/Rendering/objectRenderer.js +45 -7
  528. package/Rendering/objectRenderer.js.map +1 -1
  529. package/Rendering/outlineRenderer.pure.js +6 -2
  530. package/Rendering/outlineRenderer.pure.js.map +1 -1
  531. package/Rendering/prePassRenderer.pure.js +3 -3
  532. package/Rendering/prePassRenderer.pure.js.map +1 -1
  533. package/Rendering/renderingManager.d.ts +1 -1
  534. package/Rendering/renderingManager.js +5 -4
  535. package/Rendering/renderingManager.js.map +1 -1
  536. package/Shaders/ShadersInclude/defaultFragmentAlpha.d.ts +5 -0
  537. package/Shaders/ShadersInclude/defaultFragmentAlpha.js +34 -0
  538. package/Shaders/ShadersInclude/defaultFragmentAlpha.js.map +1 -0
  539. package/Shaders/ShadersInclude/gaussianSplatting.js +3 -1
  540. package/Shaders/ShadersInclude/gaussianSplatting.js.map +1 -1
  541. package/Shaders/ShadersInclude/gaussianSplattingVertexDeclaration.js +5 -1
  542. package/Shaders/ShadersInclude/gaussianSplattingVertexDeclaration.js.map +1 -1
  543. package/Shaders/ShadersInclude/geometryRenderingFragment.d.ts +5 -0
  544. package/Shaders/ShadersInclude/geometryRenderingFragment.js +74 -0
  545. package/Shaders/ShadersInclude/geometryRenderingFragment.js.map +1 -0
  546. package/Shaders/ShadersInclude/lightsFragmentFunctions.js +27 -3
  547. package/Shaders/ShadersInclude/lightsFragmentFunctions.js.map +1 -1
  548. package/Shaders/ShadersInclude/mrtFragmentDeclaration.js +89 -0
  549. package/Shaders/ShadersInclude/mrtFragmentDeclaration.js.map +1 -1
  550. package/Shaders/ShadersInclude/oitDeclaration.js +1 -1
  551. package/Shaders/ShadersInclude/oitDeclaration.js.map +1 -1
  552. package/Shaders/ShadersInclude/openpbrBlockPrePass.js +24 -17
  553. package/Shaders/ShadersInclude/openpbrBlockPrePass.js.map +1 -1
  554. package/Shaders/ShadersInclude/pbrBlockPrePass.js +27 -20
  555. package/Shaders/ShadersInclude/pbrBlockPrePass.js.map +1 -1
  556. package/Shaders/ShadersInclude/pbrDebug.js +6 -2
  557. package/Shaders/ShadersInclude/pbrDebug.js.map +1 -1
  558. package/Shaders/ShadersInclude/prePassDeclaration.js +95 -2
  559. package/Shaders/ShadersInclude/prePassDeclaration.js.map +1 -1
  560. package/Shaders/default.fragment.js +31 -40
  561. package/Shaders/default.fragment.js.map +1 -1
  562. package/Shaders/depthOfField.fragment.js +13 -9
  563. package/Shaders/depthOfField.fragment.js.map +1 -1
  564. package/Shaders/fluidRenderingParticleDepth.vertex.js +16 -1
  565. package/Shaders/fluidRenderingParticleDepth.vertex.js.map +1 -1
  566. package/Shaders/fluidRenderingParticleThickness.vertex.js +16 -1
  567. package/Shaders/fluidRenderingParticleThickness.vertex.js.map +1 -1
  568. package/Shaders/gaussianSplatting.fragment.js +63 -3
  569. package/Shaders/gaussianSplatting.fragment.js.map +1 -1
  570. package/Shaders/gaussianSplatting.vertex.js +80 -0
  571. package/Shaders/gaussianSplatting.vertex.js.map +1 -1
  572. package/Shaders/geometry.fragment.js +17 -11
  573. package/Shaders/geometry.fragment.js.map +1 -1
  574. package/Shaders/gpuRenderParticles.fragment.js +43 -1
  575. package/Shaders/gpuRenderParticles.fragment.js.map +1 -1
  576. package/Shaders/gpuRenderParticles.vertex.js +96 -16
  577. package/Shaders/gpuRenderParticles.vertex.js.map +1 -1
  578. package/Shaders/meshBlending.fragment.d.ts +5 -0
  579. package/Shaders/meshBlending.fragment.js +519 -0
  580. package/Shaders/meshBlending.fragment.js.map +1 -0
  581. package/Shaders/minmaxRedux.fragment.js +6 -1
  582. package/Shaders/minmaxRedux.fragment.js.map +1 -1
  583. package/Shaders/particles.fragment.js +43 -1
  584. package/Shaders/particles.fragment.js.map +1 -1
  585. package/Shaders/particles.vertex.js +84 -3
  586. package/Shaders/particles.vertex.js.map +1 -1
  587. package/Shaders/sprites.fragment.js +52 -2
  588. package/Shaders/sprites.fragment.js.map +1 -1
  589. package/Shaders/sprites.vertex.js +62 -1
  590. package/Shaders/sprites.vertex.js.map +1 -1
  591. package/ShadersWGSL/ShadersInclude/defaultFragmentAlpha.d.ts +5 -0
  592. package/ShadersWGSL/ShadersInclude/defaultFragmentAlpha.js +33 -0
  593. package/ShadersWGSL/ShadersInclude/defaultFragmentAlpha.js.map +1 -0
  594. package/ShadersWGSL/ShadersInclude/gaussianPointSplatting.d.ts +5 -0
  595. package/ShadersWGSL/ShadersInclude/gaussianPointSplatting.js +65 -0
  596. package/ShadersWGSL/ShadersInclude/gaussianPointSplatting.js.map +1 -0
  597. package/ShadersWGSL/ShadersInclude/gaussianPointSplattingScan.d.ts +5 -0
  598. package/ShadersWGSL/ShadersInclude/gaussianPointSplattingScan.js +17 -0
  599. package/ShadersWGSL/ShadersInclude/gaussianPointSplattingScan.js.map +1 -0
  600. package/ShadersWGSL/ShadersInclude/gaussianSplatting.d.ts +1 -0
  601. package/ShadersWGSL/ShadersInclude/gaussianSplatting.js +6 -78
  602. package/ShadersWGSL/ShadersInclude/gaussianSplatting.js.map +1 -1
  603. package/ShadersWGSL/ShadersInclude/gaussianSplattingFragmentDeclaration.js +2 -2
  604. package/ShadersWGSL/ShadersInclude/gaussianSplattingFragmentDeclaration.js.map +1 -1
  605. package/ShadersWGSL/ShadersInclude/gaussianSplattingShared.d.ts +5 -0
  606. package/ShadersWGSL/ShadersInclude/gaussianSplattingShared.js +79 -0
  607. package/ShadersWGSL/ShadersInclude/gaussianSplattingShared.js.map +1 -0
  608. package/ShadersWGSL/ShadersInclude/geometryRenderingFragment.d.ts +6 -0
  609. package/ShadersWGSL/ShadersInclude/geometryRenderingFragment.js +76 -0
  610. package/ShadersWGSL/ShadersInclude/geometryRenderingFragment.js.map +1 -0
  611. package/ShadersWGSL/ShadersInclude/lightFragment.js +1 -1
  612. package/ShadersWGSL/ShadersInclude/lightFragment.js.map +1 -1
  613. package/ShadersWGSL/ShadersInclude/lightsFragmentFunctions.js +27 -3
  614. package/ShadersWGSL/ShadersInclude/lightsFragmentFunctions.js.map +1 -1
  615. package/ShadersWGSL/ShadersInclude/meshBlendTagFragmentOutput.d.ts +5 -0
  616. package/ShadersWGSL/ShadersInclude/meshBlendTagFragmentOutput.js +18 -0
  617. package/ShadersWGSL/ShadersInclude/meshBlendTagFragmentOutput.js.map +1 -0
  618. package/ShadersWGSL/ShadersInclude/openpbrBlockPrePass.d.ts +1 -0
  619. package/ShadersWGSL/ShadersInclude/openpbrBlockPrePass.js +11 -25
  620. package/ShadersWGSL/ShadersInclude/openpbrBlockPrePass.js.map +1 -1
  621. package/ShadersWGSL/ShadersInclude/pbrBlockPrePass.d.ts +1 -0
  622. package/ShadersWGSL/ShadersInclude/pbrBlockPrePass.js +11 -25
  623. package/ShadersWGSL/ShadersInclude/pbrBlockPrePass.js.map +1 -1
  624. package/ShadersWGSL/ShadersInclude/pbrDebug.js +5 -1
  625. package/ShadersWGSL/ShadersInclude/pbrDebug.js.map +1 -1
  626. package/ShadersWGSL/ShadersInclude/prePassDeclaration.js +6 -1
  627. package/ShadersWGSL/ShadersInclude/prePassDeclaration.js.map +1 -1
  628. package/ShadersWGSL/default.fragment.js +17 -48
  629. package/ShadersWGSL/default.fragment.js.map +1 -1
  630. package/ShadersWGSL/fluidRenderingParticleDepth.vertex.js +15 -2
  631. package/ShadersWGSL/fluidRenderingParticleDepth.vertex.js.map +1 -1
  632. package/ShadersWGSL/fluidRenderingParticleThickness.vertex.js +15 -2
  633. package/ShadersWGSL/fluidRenderingParticleThickness.vertex.js.map +1 -1
  634. package/ShadersWGSL/gaussianPointSplattingBlit.fragment.d.ts +5 -0
  635. package/ShadersWGSL/gaussianPointSplattingBlit.fragment.js +22 -0
  636. package/ShadersWGSL/gaussianPointSplattingBlit.fragment.js.map +1 -0
  637. package/ShadersWGSL/gaussianPointSplattingBlit.vertex.d.ts +5 -0
  638. package/ShadersWGSL/gaussianPointSplattingBlit.vertex.js +19 -0
  639. package/ShadersWGSL/gaussianPointSplattingBlit.vertex.js.map +1 -0
  640. package/ShadersWGSL/gaussianPointSplattingDepthBlit.fragment.d.ts +5 -0
  641. package/ShadersWGSL/gaussianPointSplattingDepthBlit.fragment.js +21 -0
  642. package/ShadersWGSL/gaussianPointSplattingDepthBlit.fragment.js.map +1 -0
  643. package/ShadersWGSL/gaussianSplatting.fragment.js +63 -2
  644. package/ShadersWGSL/gaussianSplatting.fragment.js.map +1 -1
  645. package/ShadersWGSL/gaussianSplatting.vertex.js +82 -1
  646. package/ShadersWGSL/gaussianSplatting.vertex.js.map +1 -1
  647. package/ShadersWGSL/gaussianSplattingDepth.vertex.js +2 -1
  648. package/ShadersWGSL/gaussianSplattingDepth.vertex.js.map +1 -1
  649. package/ShadersWGSL/gaussianSplattingVoxel.vertex.js +2 -1
  650. package/ShadersWGSL/gaussianSplattingVoxel.vertex.js.map +1 -1
  651. package/ShadersWGSL/geometry.fragment.js +37 -2
  652. package/ShadersWGSL/geometry.fragment.js.map +1 -1
  653. package/ShadersWGSL/gpsHiZBuild.compute.d.ts +5 -0
  654. package/ShadersWGSL/gpsHiZBuild.compute.js +16 -0
  655. package/ShadersWGSL/gpsHiZBuild.compute.js.map +1 -0
  656. package/ShadersWGSL/gpsPartition.compute.d.ts +5 -0
  657. package/ShadersWGSL/gpsPartition.compute.js +27 -0
  658. package/ShadersWGSL/gpsPartition.compute.js.map +1 -0
  659. package/ShadersWGSL/gpsPreprocess.compute.d.ts +5 -0
  660. package/ShadersWGSL/gpsPreprocess.compute.js +86 -0
  661. package/ShadersWGSL/gpsPreprocess.compute.js.map +1 -0
  662. package/ShadersWGSL/gpsResolve.compute.d.ts +5 -0
  663. package/ShadersWGSL/gpsResolve.compute.js +41 -0
  664. package/ShadersWGSL/gpsResolve.compute.js.map +1 -0
  665. package/ShadersWGSL/gpsScanAdd.compute.d.ts +5 -0
  666. package/ShadersWGSL/gpsScanAdd.compute.js +22 -0
  667. package/ShadersWGSL/gpsScanAdd.compute.js.map +1 -0
  668. package/ShadersWGSL/gpsScanBlocks.compute.d.ts +5 -0
  669. package/ShadersWGSL/gpsScanBlocks.compute.js +23 -0
  670. package/ShadersWGSL/gpsScanBlocks.compute.js.map +1 -0
  671. package/ShadersWGSL/gpsScanSums.compute.d.ts +5 -0
  672. package/ShadersWGSL/gpsScanSums.compute.js +30 -0
  673. package/ShadersWGSL/gpsScanSums.compute.js.map +1 -0
  674. package/ShadersWGSL/gpsSplat.compute.d.ts +5 -0
  675. package/ShadersWGSL/gpsSplat.compute.js +37 -0
  676. package/ShadersWGSL/gpsSplat.compute.js.map +1 -0
  677. package/ShadersWGSL/gpuRenderParticles.fragment.js +47 -2
  678. package/ShadersWGSL/gpuRenderParticles.fragment.js.map +1 -1
  679. package/ShadersWGSL/gpuRenderParticles.vertex.js +110 -7
  680. package/ShadersWGSL/gpuRenderParticles.vertex.js.map +1 -1
  681. package/ShadersWGSL/meshBlending.fragment.d.ts +5 -0
  682. package/ShadersWGSL/meshBlending.fragment.js +576 -0
  683. package/ShadersWGSL/meshBlending.fragment.js.map +1 -0
  684. package/ShadersWGSL/minmaxRedux.fragment.js +20 -3
  685. package/ShadersWGSL/minmaxRedux.fragment.js.map +1 -1
  686. package/ShadersWGSL/openpbr.fragment.js +2 -1
  687. package/ShadersWGSL/openpbr.fragment.js.map +1 -1
  688. package/ShadersWGSL/particles.fragment.js +45 -1
  689. package/ShadersWGSL/particles.fragment.js.map +1 -1
  690. package/ShadersWGSL/particles.vertex.js +86 -4
  691. package/ShadersWGSL/particles.vertex.js.map +1 -1
  692. package/ShadersWGSL/pbr.fragment.js +2 -1
  693. package/ShadersWGSL/pbr.fragment.js.map +1 -1
  694. package/ShadersWGSL/sprites.fragment.js +56 -2
  695. package/ShadersWGSL/sprites.fragment.js.map +1 -1
  696. package/ShadersWGSL/sprites.vertex.js +62 -1
  697. package/ShadersWGSL/sprites.vertex.js.map +1 -1
  698. package/Sprites/spriteManager.d.ts +13 -0
  699. package/Sprites/spriteManager.js +15 -0
  700. package/Sprites/spriteManager.js.map +1 -1
  701. package/Sprites/spriteRenderer.d.ts +24 -1
  702. package/Sprites/spriteRenderer.js +368 -50
  703. package/Sprites/spriteRenderer.js.map +1 -1
  704. package/Sprites/thinSprite.d.ts +4 -0
  705. package/Sprites/thinSprite.js +4 -0
  706. package/Sprites/thinSprite.js.map +1 -1
  707. package/States/alphaCullingState.d.ts +3 -1
  708. package/States/alphaCullingState.js +18 -3
  709. package/States/alphaCullingState.js.map +1 -1
  710. package/XR/features/WebXRSpaceWarp.pure.js +2 -1
  711. package/XR/features/WebXRSpaceWarp.pure.js.map +1 -1
  712. package/XR/webXRDefaultExperience.d.ts +5 -1
  713. package/XR/webXRDefaultExperience.js.map +1 -1
  714. package/XR/webXREnterExitUI.d.ts +2 -1
  715. package/XR/webXREnterExitUI.js.map +1 -1
  716. package/assetContainer.d.ts +1 -0
  717. package/assetContainer.js +5 -1
  718. package/assetContainer.js.map +1 -1
  719. package/package.json +1 -1
  720. package/scene.pure.d.ts +36 -2
  721. package/scene.pure.js +63 -4
  722. package/scene.pure.js.map +1 -1
@@ -0,0 +1,1709 @@
1
+ import { Animation } from "./animation.pure.js";
2
+ import { Matrix, Quaternion, TmpVectors, Vector3 } from "../Maths/math.vector.pure.js";
3
+ import { Observable } from "../Misc/observable.pure.js";
4
+ import { Logger } from "../Misc/logger.js";
5
+ import { TransformNode } from "../Meshes/transformNode.pure.js";
6
+ import { AbstractMesh } from "../Meshes/abstractMesh.pure.js";
7
+ /**
8
+ * Where the travel of a {@link RootMotionClip} comes from.
9
+ */
10
+ export var RootMotionSource;
11
+ (function (RootMotionSource) {
12
+ /**
13
+ * No motion was found: the clip neither moves its root nor walks its contact nodes.
14
+ */
15
+ RootMotionSource[RootMotionSource["None"] = 0] = "None";
16
+ /**
17
+ * The root node's own animation - the clip's ground truth. Its travel (and turning, when extracted) is left out of
18
+ * the in-place animation group and applied to the character node instead.
19
+ */
20
+ RootMotionSource[RootMotionSource["Root"] = 1] = "Root";
21
+ /**
22
+ * Deduced from the contact nodes (usually the feet) of an in-place clip: whatever a planted contact gives up in
23
+ * character space, the character travels. The travel is not in the clip, so nothing is left out of it.
24
+ */
25
+ RootMotionSource[RootMotionSource["FootContact"] = 2] = "FootContact";
26
+ })(RootMotionSource || (RootMotionSource = {}));
27
+ /**
28
+ * The channel of a node to run a clip's motion on: the one of its position, rotation and scaling channels preferred by
29
+ * {@link ClockBeats}.
30
+ * @param channels defines the node's channels
31
+ * @param fromFrame defines the first frame of the range played
32
+ * @param toFrame defines the last frame of the range played
33
+ * @returns the channel and the frames its keys span
34
+ */
35
+ function ClockChannel(channels, fromFrame, toFrame) {
36
+ let best = null;
37
+ for (const animation of [channels.position, channels.rotationQuaternion, channels.rotation, channels.scaling]) {
38
+ if (!animation) {
39
+ continue;
40
+ }
41
+ const keys = animation.getKeys();
42
+ const first = keys.length ? keys[0].frame : 0;
43
+ const last = keys.length ? keys[keys.length - 1].frame : 0;
44
+ const candidate = { animation, span: last - first, covers: last > first && first <= fromFrame && last >= toFrame };
45
+ if (!best || ClockBeats(candidate, best)) {
46
+ best = candidate;
47
+ }
48
+ }
49
+ return best;
50
+ }
51
+ /**
52
+ * Whether one channel is to run a clip's motion rather than another: one whose keys cover the range played before one
53
+ * whose keys do not; among channels that cover it a position channel first, the channel the mixer weighs linearly, then
54
+ * the widest; among channels that do not, the widest, since a channel keyed shorter clamps the analysis to its keys,
55
+ * then a position channel.
56
+ * @param candidate defines the channel considered
57
+ * @param other defines the channel preferred so far
58
+ * @returns whether the channel considered is preferred
59
+ */
60
+ function ClockBeats(candidate, other) {
61
+ if (candidate.covers !== other.covers) {
62
+ return candidate.covers;
63
+ }
64
+ const position = candidate.animation.targetProperty === "position";
65
+ const otherPosition = other.animation.targetProperty === "position";
66
+ if (candidate.covers && position !== otherPosition) {
67
+ return position;
68
+ }
69
+ if (candidate.span !== other.span) {
70
+ return candidate.span > other.span;
71
+ }
72
+ return position && !otherPosition;
73
+ }
74
+ /** Contact candidates must come this close to the lowest one during the clip, as a share of the character's height. */
75
+ const ContactHeightBand = 0.1;
76
+ /** A contact counts as on the ground within this share of the character's height above its own lowest point. */
77
+ const PlantedHeightBand = 0.05;
78
+ /** Values per sample in the motion track: translation x, y, z and the turn about the up axis. */
79
+ const TrackStride = 4;
80
+ /**
81
+ * Deduced travel counts only if its steps mostly head the same way: net travel over the length of the path stepped.
82
+ * Walks and runs measure 0.99 and more; a dance or an idle that shuffles about on the spot measures under 0.3.
83
+ */
84
+ const MinimumStraightness = 0.8;
85
+ /** Default snap of a direction of travel deduced from contacts, in radians. */
86
+ const DeducedDirectionSnapAngle = Math.PI / 18;
87
+ /** Frame step for the numeric tangents of rewritten cubic spline keys. */
88
+ const TangentDelta = 1e-3;
89
+ /** The root motion of each scene, updating the scene's controllers in one pass after animations. */
90
+ const SceneRootMotions = new WeakMap();
91
+ /**
92
+ * The root motion of an animation group: how far the clip carries the character over a cycle, and how far it turns it,
93
+ * so that the character can be moved by it and its feet stay planted instead of skating.
94
+ *
95
+ * The clip is analyzed once, when the RootMotionClip is created, without playing the group or changing it:
96
+ * 1. The root node's own animation is tried first, as the ground truth. If the root ends a cycle a meaningful distance
97
+ * from where it started, that travel is the root motion. Turning is read from the root the same way.
98
+ * 2. Otherwise the clip is treated as an in-place cycle and the travel is deduced from its contact nodes: a planted
99
+ * contact stays put in the world, so in character space it moves opposite to the character, and whatever it gives
100
+ * up the character gains. The direction of travel falls out of the same measurement, so the forward axis of
101
+ * the rig does not have to be known.
102
+ *
103
+ * The source group is never changed. The clip owns {@link RootMotionClip.animationGroup}, a clone of the source in
104
+ * which the root's travel and turning are left out, so it plays and loops in place: play that group, and give the clip
105
+ * to the {@link RootMotionController} of the character so the motion is applied to the character node instead.
106
+ *
107
+ * ```ts
108
+ * const walk = new RootMotionClip(walkGroup);
109
+ * const controller = new RootMotionController(walk.characterNode, [walk]);
110
+ * walk.animationGroup.start(true);
111
+ * ```
112
+ *
113
+ * The in-place group is a group of the scene, not of the source's asset container, so dispose the clip when it is done
114
+ * with; disposing the container does not. To play a clip additively, build it from the source as it is and make the
115
+ * in-place group additive: `AnimationGroup.MakeAnimationAdditive(clip.animationGroup, { referenceFrame: 0 })`, with
116
+ * {@link IRootMotionClipOptions.cloneAnimations} set so the source keeps its keys.
117
+ */
118
+ export class RootMotionClip {
119
+ /**
120
+ * The animation group the clip was analyzed from. It is never changed.
121
+ */
122
+ get sourceAnimationGroup() {
123
+ return this._sourceGroup;
124
+ }
125
+ /**
126
+ * The in-place animation group to play: a clone of the source with the root motion left out of the root's keys.
127
+ * Animations the extraction does not rewrite are shared with the source unless the clip was created with
128
+ * {@link IRootMotionClipOptions.cloneAnimations}. It belongs to the scene, and is disposed with the clip.
129
+ */
130
+ get animationGroup() {
131
+ return this._group;
132
+ }
133
+ /**
134
+ * The controller the clip was added to, if any.
135
+ */
136
+ get controller() {
137
+ return this._controller;
138
+ }
139
+ /**
140
+ * Where the travel comes from. {@link RootMotionSource.None} when no motion was found.
141
+ */
142
+ get source() {
143
+ return this._source;
144
+ }
145
+ /**
146
+ * The root node the clip was analyzed with, or null when the group animates no position. It carries the motion
147
+ * only when {@link RootMotionClip.source} is {@link RootMotionSource.Root}.
148
+ */
149
+ get rootNode() {
150
+ return this._rootNode;
151
+ }
152
+ /**
153
+ * The node the motion is measured in the local space of, and that a controller moves.
154
+ */
155
+ get characterNode() {
156
+ return this._characterNode;
157
+ }
158
+ /**
159
+ * The contact nodes used to deduce the travel. Empty unless the source is {@link RootMotionSource.FootContact}.
160
+ */
161
+ get contactNodes() {
162
+ return this._contactNodes;
163
+ }
164
+ /**
165
+ * The up axis in character space (unit length).
166
+ */
167
+ get upAxis() {
168
+ return this._upAxis;
169
+ }
170
+ /**
171
+ * The first frame of the range the clip is analyzed over: the group's range, with a bound outside the clock
172
+ * channel's keys replaced by that channel's first or last key, as playback does.
173
+ */
174
+ get fromFrame() {
175
+ return this._fromFrame;
176
+ }
177
+ /**
178
+ * The last frame of the range the clip is analyzed over.
179
+ */
180
+ get toFrame() {
181
+ return this._toFrame;
182
+ }
183
+ /**
184
+ * The direction the clip travels in over a cycle, in character space (unit length).
185
+ */
186
+ get travelDirection() {
187
+ return this._travelDirection;
188
+ }
189
+ /**
190
+ * The travel covered by one cycle of the clip, in character space.
191
+ */
192
+ get cycleOffset() {
193
+ return this._cycleOffset;
194
+ }
195
+ /**
196
+ * The distance covered by one cycle of the clip along the direction of travel, in character space units.
197
+ */
198
+ get cycleDistance() {
199
+ return Vector3.Dot(this._cycleOffset, this._travelDirection);
200
+ }
201
+ /**
202
+ * The turn covered by one cycle of the clip about the up axis, in radians. Zero unless rotation is extracted.
203
+ */
204
+ get cycleRotation() {
205
+ return this._cycleRotation;
206
+ }
207
+ /**
208
+ * Whether the root's turning is extracted and applied to the character.
209
+ */
210
+ get extractsRotation() {
211
+ return this._turns;
212
+ }
213
+ /**
214
+ * The length of one cycle of the clip in seconds, at a speed ratio of 1.
215
+ */
216
+ get duration() {
217
+ return this._duration;
218
+ }
219
+ /**
220
+ * The speed the clip implies at a speed ratio of 1, in character space units per second.
221
+ */
222
+ get averageSpeed() {
223
+ return this._duration > 0 ? this.cycleDistance / this._duration : 0;
224
+ }
225
+ /**
226
+ * The vertical extent of the animated hierarchy at the first frame, in character space units. Thresholds are
227
+ * relative to it.
228
+ */
229
+ get characterHeight() {
230
+ return this._characterHeight;
231
+ }
232
+ /**
233
+ * Analyzes an animation group and builds the in-place animation group to play instead of it.
234
+ * @param animationGroup defines the animation group to extract the root motion of; it is not changed
235
+ * @param options defines how the root motion is extracted
236
+ * @throws when the group has nothing to analyze, is additive, or animates the character node itself
237
+ */
238
+ constructor(animationGroup, options = {}) {
239
+ /**
240
+ * @internal
241
+ * The node of the clip's clock: the channel whose runtime animation the controller reads the evaluated progress
242
+ * from and turns into motion. It is the root node, or the first animated transform node when the group animates
243
+ * no position.
244
+ */
245
+ this._clockNode = null;
246
+ /** @internal The property of the clock's channel. */
247
+ this._clockProperty = "position";
248
+ /** @internal The very channel of the in-place group the analysis ran on, which another of the same property must not be taken for. */
249
+ this._clockAnimation = null;
250
+ /** @internal The runtime animation of the clock the controller followed last. */
251
+ this._clockRuntime = null;
252
+ /** @internal The animatable of the clock the controller followed last. */
253
+ this._clockAnimatable = null;
254
+ /** @internal The animatable the last search for the clock found. */
255
+ this._foundAnimatable = null;
256
+ /** @internal The animatable the clock's playback was synchronized with last, and the runtime animation of that root. */
257
+ this._syncRoot = null;
258
+ /** @internal The runtime animation the clock was synchronized with last. */
259
+ this._syncRuntime = null;
260
+ /** @internal The progress of the clock the controller consumed last. */
261
+ this._lastProgress = null;
262
+ /** @internal Whether the clock has been left unevaluated at a weight of zero since the progress consumed last. */
263
+ this._parked = false;
264
+ /** @internal The clock's runtime animation at the last reset, whose evaluation of then is not where the playback carries on from. */
265
+ this._staleRuntime = null;
266
+ /** @internal Its progress then. */
267
+ this._staleProgress = null;
268
+ /** @internal What the mixer wrote to the clock's channel this frame. */
269
+ this._writers = null;
270
+ /** @internal The controller the clip belongs to. */
271
+ this._controller = null;
272
+ /** Sideways travel over a cycle left in the root's keys after snapping the direction, removed without being applied. */
273
+ this._lateralDrift = Vector3.Zero();
274
+ this._channels = new Map();
275
+ this._source = 0 /* RootMotionSource.None */;
276
+ this._rootNode = null;
277
+ this._contactNodes = [];
278
+ this._travelDirection = new Vector3(0, 0, 1);
279
+ this._cycleOffset = Vector3.Zero();
280
+ this._cycleRotation = 0;
281
+ this._turns = false;
282
+ this._duration = 0;
283
+ this._characterHeight = 0;
284
+ this._fromFrame = 0;
285
+ this._toFrame = 0;
286
+ this._sampleCount = 1;
287
+ this._track = new Float32Array(2 * TrackStride);
288
+ /** Whether the root's own travel is left out of the in-place group - not so for a clip that only turns on the spot. */
289
+ this._removesRootTravel = false;
290
+ /** Whether the motion is a turn about the root's starting point: a clip that only turns on the spot. */
291
+ this._pivots = false;
292
+ /** The root's position before the clip, when the in-place group animates a position the source leaves alone. */
293
+ this._restoredPosition = null;
294
+ this._clockIndex = -1;
295
+ this._sampleBlend = 0;
296
+ this._lastOffset = Vector3.Zero();
297
+ this._rangeStart = Vector3.Zero();
298
+ this._rangeCycle = Vector3.Zero();
299
+ this._cyclesOffset = Vector3.Zero();
300
+ this._planarStep = Vector3.Zero();
301
+ this._yawQuaternion = new Quaternion();
302
+ this._yawMatrix = new Matrix();
303
+ this._sourceGroup = animationGroup;
304
+ this._upAxis = (options.upAxis ?? Vector3.UpReadOnly).normalizeToNew();
305
+ this._extractLateral = !!options.extractLateralMotion;
306
+ this._directionSnapAngle = options.directionSnapAngle;
307
+ const name = options.name ?? `${animationGroup.name} (in place)`;
308
+ if (animationGroup.isAdditive) {
309
+ throw new Error(`RootMotionClip: animation group "${animationGroup.name}" is additive. Build the clip from the group it was made additive from, then make the clip's in-place group additive.`);
310
+ }
311
+ const targetedAnimations = animationGroup.targetedAnimations;
312
+ if (!targetedAnimations.length) {
313
+ throw new Error(`RootMotionClip: animation group "${animationGroup.name}" has no animations.`);
314
+ }
315
+ for (const targetedAnimation of targetedAnimations) {
316
+ const target = targetedAnimation.target;
317
+ const property = targetedAnimation.animation.targetProperty;
318
+ if (!(target instanceof TransformNode)) {
319
+ continue;
320
+ }
321
+ if (property === "position" || property === "rotationQuaternion" || property === "rotation" || property === "scaling") {
322
+ let channels = this._channels.get(target);
323
+ if (!channels) {
324
+ channels = {};
325
+ this._channels.set(target, channels);
326
+ }
327
+ channels[property] = targetedAnimation.animation;
328
+ }
329
+ }
330
+ // The character node is where the motion goes; an animation of its position or rotation, or of a part of them,
331
+ // would overwrite it every frame.
332
+ const refuseAnimatedReceiver = (node) => {
333
+ if (targetedAnimations.some((targetedAnimation) => targetedAnimation.target === node && /^(position|rotationQuaternion|rotation)(\.|$)/.test(targetedAnimation.animation.targetProperty))) {
334
+ throw new Error(`RootMotionClip: animation group "${animationGroup.name}" animates the character node "${node.name}", which is to receive the motion. Parent the character under a node the group does not animate, or pass such an ancestor as characterNode.`);
335
+ }
336
+ };
337
+ if (options.characterNode) {
338
+ refuseAnimatedReceiver(options.characterNode);
339
+ }
340
+ this._rootNode = options.rootNode ? this._resolveNode(options.rootNode) : this._findRootNode();
341
+ const anchor = this._rootNode ?? this._firstAnimatedNode();
342
+ if (!anchor) {
343
+ throw new Error(`RootMotionClip: animation group "${animationGroup.name}" does not animate any transform node.`);
344
+ }
345
+ let character = options.characterNode ?? null;
346
+ if (!character || character === anchor || !anchor.isDescendantOf(character)) {
347
+ if (character) {
348
+ Logger.Warn(`RootMotionClip: the character node "${character.name}" is not an ancestor of the root node "${anchor.name}"; using the topmost ancestor instead.`);
349
+ }
350
+ character = this._topmostAncestor(anchor);
351
+ }
352
+ if (character === anchor) {
353
+ throw new Error(`RootMotionClip: the root node "${anchor.name}" has no parent to carry its motion. Parent the character under a node of its own.`);
354
+ }
355
+ refuseAnimatedReceiver(character);
356
+ this._characterNode = character;
357
+ // The motion runs on the root's own animation - its frame rate, its range and at runtime its playback - rather than
358
+ // whichever track happens to be first in the group, which could be a morph target at another frame rate: the
359
+ // channel of the root that covers the range played, since one keyed shorter would clamp the analysis to its own
360
+ // keys. A root the group does not animate, passed as the base of the hierarchy, runs on such a channel of an
361
+ // animated descendant: a position channel before any other, the channel the mixer weighs linearly, and the
362
+ // widest among those.
363
+ const playedFrom = animationGroup.from;
364
+ const playedTo = animationGroup.to;
365
+ let clockNode = null;
366
+ let clock = null;
367
+ const anchorChannels = this._channels.get(anchor);
368
+ const anchorClock = anchorChannels ? ClockChannel(anchorChannels, playedFrom, playedTo) : null;
369
+ if (anchorClock && anchorClock.span > 0) {
370
+ clockNode = anchor;
371
+ clock = anchorClock.animation;
372
+ }
373
+ else {
374
+ // The root has nothing to run on - it is not animated at all, or only by channels of a single key - so the
375
+ // clip runs on a channel of the hierarchy under it, itself as the last resort, chosen across those nodes by
376
+ // the same preference as among the channels of one.
377
+ let best = null;
378
+ for (const [node, channels] of this._channels) {
379
+ if (node !== anchor && !node.isDescendantOf(anchor)) {
380
+ continue;
381
+ }
382
+ const candidate = ClockChannel(channels, playedFrom, playedTo);
383
+ if (!best || ClockBeats(candidate, best)) {
384
+ best = candidate;
385
+ clockNode = node;
386
+ clock = candidate.animation;
387
+ }
388
+ }
389
+ }
390
+ if (!clockNode || !clock) {
391
+ throw new Error(`RootMotionClip: animation group "${animationGroup.name}" animates neither the root node "${anchor.name}" nor any node under it.`);
392
+ }
393
+ this._clockNode = clockNode;
394
+ this._clockProperty = clock.targetProperty;
395
+ // The group's range clamped to the clock's keys, the way playback clamps it: another track may run longer.
396
+ const keys = clock.getKeys();
397
+ const firstKey = keys[0].frame;
398
+ const lastKey = keys[keys.length - 1].frame;
399
+ this._fromFrame = animationGroup.from < firstKey || animationGroup.from > lastKey ? firstKey : animationGroup.from;
400
+ this._toFrame = animationGroup.to < firstKey || animationGroup.to > lastKey ? lastKey : animationGroup.to;
401
+ const framePerSecond = clock.framePerSecond;
402
+ this._duration = framePerSecond > 0 ? (this._toFrame - this._fromFrame) / framePerSecond : 0;
403
+ this._sampleCount = Math.max(2, Math.ceil(this._duration * (options.samplesPerSecond ?? 60)));
404
+ this._characterHeight = this._measureHeight(this._rootNode ?? this._characterNode);
405
+ const scale = this._characterHeight > 0 ? this._characterHeight : 1;
406
+ const minimumTravel = (options.minimumTravel ?? 0.1) * scale;
407
+ const minimumTurn = options.minimumTurn ?? Math.PI / 18;
408
+ const source = options.source;
409
+ const root = this._rootNode;
410
+ const rootChannels = root ? this._channels.get(root) : undefined;
411
+ const samples = this._sampleCount;
412
+ // Turning is only ever in the root's own rotation.
413
+ let yaw = null;
414
+ if (root && options.extractRotation !== false && (rootChannels?.rotationQuaternion || rootChannels?.rotation)) {
415
+ const measured = this._measureRootYaw();
416
+ // By the turn a loop leaves the character facing: a dance that spins twice ends facing the way it began and
417
+ // loops seamlessly as it is, while a 90 degree turn has to carry the character round.
418
+ if (options.extractRotation === true || Math.abs(WrapAngle(measured[samples])) >= minimumTurn) {
419
+ yaw = measured;
420
+ }
421
+ }
422
+ this._turns = !!yaw;
423
+ if (source === 1 /* RootMotionSource.Root */ && !rootChannels?.position) {
424
+ throw new Error(`RootMotionClip: the root node "${root.name}" has no position animation to take the travel from. Omit the source to deduce it from the contact nodes, or pass another rootNode.`);
425
+ }
426
+ let translation = null;
427
+ if ((source === undefined || source === 1 /* RootMotionSource.Root */) && root && rootChannels?.position) {
428
+ translation = this._measureRootTravel(yaw, minimumTravel, source === 1 /* RootMotionSource.Root */);
429
+ if (translation) {
430
+ this._source = 1 /* RootMotionSource.Root */;
431
+ this._removesRootTravel = true;
432
+ }
433
+ }
434
+ if (!translation && (source === undefined || source === 2 /* RootMotionSource.FootContact */)) {
435
+ translation = this._measureContactTravel(yaw, options.contactNodes, minimumTravel, source === 2 /* RootMotionSource.FootContact */);
436
+ if (translation) {
437
+ this._source = 2 /* RootMotionSource.FootContact */;
438
+ }
439
+ }
440
+ if (!translation && yaw) {
441
+ // Turning on the spot: the root keeps its travel, sway included; only the turn is taken out.
442
+ translation = new Float32Array((samples + 1) * 3);
443
+ this._source = 1 /* RootMotionSource.Root */;
444
+ }
445
+ if (translation && yaw && !this._removesRootTravel) {
446
+ // A turn that is not in the root's travel turns the character about the root's starting point, so a root off
447
+ // the character's axis stays where the clip has it, in place from one cycle to the next.
448
+ const start = this._positionInCharacter(root, this._fromFrame, new Vector3());
449
+ const pivot = new Vector3();
450
+ for (let i = 0; i <= samples; i++) {
451
+ this._rootTravelAt(start, start, yaw[i], true, pivot);
452
+ translation[i * 3] += pivot.x;
453
+ translation[i * 3 + 1] += pivot.y;
454
+ translation[i * 3 + 2] += pivot.z;
455
+ }
456
+ this._pivots = true;
457
+ }
458
+ if (translation) {
459
+ this._track = new Float32Array((samples + 1) * TrackStride);
460
+ for (let i = 0; i <= samples; i++) {
461
+ this._track[i * TrackStride] = translation[i * 3];
462
+ this._track[i * TrackStride + 1] = translation[i * 3 + 1];
463
+ this._track[i * TrackStride + 2] = translation[i * 3 + 2];
464
+ this._track[i * TrackStride + 3] = yaw ? yaw[i] : 0;
465
+ }
466
+ this._cycleOffset.fromArray(translation, samples * 3);
467
+ this._cycleRotation = yaw ? yaw[samples] : 0;
468
+ }
469
+ else {
470
+ this._turns = false;
471
+ this._travelDirection.set(0, 0, 1);
472
+ this._lateralDrift.setAll(0);
473
+ }
474
+ this._group = this._buildInPlaceGroup(name, !!options.cloneAnimations);
475
+ // The very channel of the in-place group the motion runs on - the last of that node and property, as the
476
+ // analysis took it - so that another channel of the same property is not followed in its place.
477
+ for (const targetedAnimation of this._group.targetedAnimations) {
478
+ if (targetedAnimation.target === this._clockNode && targetedAnimation.animation.targetProperty === this._clockProperty) {
479
+ this._clockAnimation = targetedAnimation.animation;
480
+ }
481
+ }
482
+ }
483
+ /**
484
+ * Gets the travel reached at a frame of the clip, relative to its first frame, in character space.
485
+ * @param frame defines the frame to sample
486
+ * @param result defines the vector receiving the travel
487
+ * @returns the result vector
488
+ */
489
+ getOffsetAtFrame(frame, result) {
490
+ const a = this._sampleAt(frame) * TrackStride;
491
+ const b = a + TrackStride;
492
+ const blend = this._sampleBlend;
493
+ const track = this._track;
494
+ return result.set(track[a] + (track[b] - track[a]) * blend, track[a + 1] + (track[b + 1] - track[a + 1]) * blend, track[a + 2] + (track[b + 2] - track[a + 2]) * blend);
495
+ }
496
+ /**
497
+ * Gets the turn reached at a frame of the clip about the up axis, relative to its first frame, in radians.
498
+ * @param frame defines the frame to sample
499
+ * @returns the turn in radians
500
+ */
501
+ getRotationAtFrame(frame) {
502
+ const a = this._sampleAt(frame) * TrackStride + 3;
503
+ return this._track[a] + (this._track[a + TrackStride] - this._track[a]) * this._sampleBlend;
504
+ }
505
+ /**
506
+ * Removes the clip from its controller and disposes the in-place animation group. The source group is untouched.
507
+ * When the in-place group animates the root's position although the source does not (a root that only turns), the
508
+ * root's position is put back to what it was when the clip was created.
509
+ */
510
+ dispose() {
511
+ this._controller?.removeClip(this);
512
+ this._group.dispose();
513
+ if (this._restoredPosition && this._rootNode) {
514
+ this._rootNode.position = this._restoredPosition.clone();
515
+ }
516
+ }
517
+ /**
518
+ * @internal
519
+ * Finds the runtime animation of the clock in the in-place group's current playback, leaving its animatable in
520
+ * _foundAnimatable.
521
+ * @returns the runtime animation once it has been evaluated, or null when the group is not playing the clock
522
+ */
523
+ _findClock() {
524
+ const animatables = this._group.animatables;
525
+ const cached = this._clockAnimatable;
526
+ if (cached && this._clockRuntime && animatables[this._clockIndex] === cached) {
527
+ this._foundAnimatable = cached;
528
+ return this._clockRuntime;
529
+ }
530
+ for (let i = 0; i < animatables.length; i++) {
531
+ const animatable = animatables[i];
532
+ if (animatable.target !== this._clockNode) {
533
+ continue;
534
+ }
535
+ const runtimes = animatable.getAnimations();
536
+ for (let j = 0; j < runtimes.length; j++) {
537
+ const runtime = runtimes[j];
538
+ if (runtime.target && (this._clockAnimation ? runtime.animation === this._clockAnimation : runtime.animation.targetProperty === this._clockProperty)) {
539
+ this._foundAnimatable = animatable;
540
+ this._clockIndex = i;
541
+ return runtime;
542
+ }
543
+ }
544
+ }
545
+ this._foundAnimatable = null;
546
+ return null;
547
+ }
548
+ /**
549
+ * @internal
550
+ * Forgets the playback the controller was following.
551
+ */
552
+ _forgetPlayback() {
553
+ this._clockRuntime = null;
554
+ this._clockAnimatable = null;
555
+ this._syncRoot = null;
556
+ this._syncRuntime = null;
557
+ this._lastProgress = null;
558
+ this._parked = false;
559
+ this._staleRuntime = null;
560
+ this._staleProgress = null;
561
+ }
562
+ /**
563
+ * @internal
564
+ * The motion between two progresses of a playback over a range, as a turn and then a translation in the character
565
+ * space of the earlier progress. Progress is unwrapped: whole cycles are in it, however many passed.
566
+ * @param from defines the first frame of the played range
567
+ * @param to defines the last frame of the played range
568
+ * @param lastProgress defines the earlier progress, in frames from the first frame
569
+ * @param progress defines the later progress, in frames from the first frame
570
+ * @param result defines the vector receiving the translation
571
+ * @returns the turn in radians
572
+ */
573
+ _motionBetween(from, to, lastProgress, progress, result) {
574
+ const range = to - from;
575
+ if (range === 0 || (this._source === 0 /* RootMotionSource.None */ && !this._turns)) {
576
+ result.setAll(0);
577
+ return 0;
578
+ }
579
+ const lastCycle = Math.floor(lastProgress / range);
580
+ const cycle = Math.floor(progress / range);
581
+ const lastFrame = from + lastProgress - lastCycle * range;
582
+ const frame = from + progress - cycle * range;
583
+ const cycles = cycle - lastCycle;
584
+ // The motion within the played range, relative to its start - a range played on its own loops by its own stride,
585
+ // not the whole clip's.
586
+ const startYaw = this.getRotationAtFrame(from);
587
+ const startOffset = this.getOffsetAtFrame(from, this._rangeStart);
588
+ const lastYaw = this._motionInRange(lastFrame, startYaw, startOffset, this._lastOffset);
589
+ let yaw = this._motionInRange(frame, startYaw, startOffset, result);
590
+ if (cycles !== 0) {
591
+ // Whole cycles passed: now = cycle^cycles, then the motion within the range.
592
+ const stepYaw = this._motionInRange(to, startYaw, startOffset, this._rangeCycle);
593
+ const cyclesYaw = this._cyclePower(cycles, this._rangeCycle, stepYaw, this._cyclesOffset);
594
+ this._rotateAboutUp(result, cyclesYaw, result).addInPlace(this._cyclesOffset);
595
+ yaw += cyclesYaw;
596
+ }
597
+ // Relative to where the character was: undo the turn it had already made.
598
+ this._rotateAboutUp(result.subtractInPlace(this._lastOffset), -lastYaw, result);
599
+ return yaw - lastYaw;
600
+ }
601
+ /**
602
+ * The motion at a frame relative to the motion at the start of the played range.
603
+ * @param frame defines the frame
604
+ * @param startYaw defines the turn at the start of the range
605
+ * @param startOffset defines the travel at the start of the range
606
+ * @param result defines the vector receiving the travel
607
+ * @returns the turn
608
+ */
609
+ _motionInRange(frame, startYaw, startOffset, result) {
610
+ this._rotateAboutUp(this.getOffsetAtFrame(frame, result).subtractInPlace(startOffset), -startYaw, result);
611
+ return this.getRotationAtFrame(frame) - startYaw;
612
+ }
613
+ /**
614
+ * A whole number of cycles of a planar motion - a turn about the up axis and then a translation - in closed form,
615
+ * for any number of cycles, forwards or back: the sum of the horizontal translation turned 0, 1, ... n-1 times is
616
+ * the translation turned (n - 1) / 2 times, sin(n * turn / 2) / sin(turn / 2) times as long, and n times the
617
+ * translation when there is no turn. The vertical part adds up. Nothing here is a matter of precision: no series
618
+ * is summed and no small angle is divided by.
619
+ * @param cycles defines the number of cycles, negative to go back
620
+ * @param step defines the translation of one cycle
621
+ * @param stepYaw defines the turn of one cycle
622
+ * @param result defines the vector receiving the translation of all the cycles
623
+ * @returns the turn of all the cycles
624
+ */
625
+ _cyclePower(cycles, step, stepYaw, result) {
626
+ // The turn only matters modulo a revolution; wrapped, whole revolutions read as no turn at all.
627
+ const turn = WrapAngle(stepYaw);
628
+ const halfSine = Math.sin(turn / 2);
629
+ const length = halfSine === 0 ? cycles : Math.sin((cycles * turn) / 2) / halfSine;
630
+ const up = this._upAxis;
631
+ const rise = Vector3.Dot(step, up) * cycles;
632
+ this._rotateAboutUp(this._horizontal(step, this._planarStep), ((cycles - 1) * turn) / 2, result).scaleInPlace(length);
633
+ result.addInPlace(up.scale(rise));
634
+ return cycles * stepYaw;
635
+ }
636
+ _measureRootYaw() {
637
+ const root = this._rootNode;
638
+ const samples = this._sampleCount;
639
+ const reference = this._rotationInCharacter(root, this._fromFrame, new Quaternion());
640
+ reference.conjugateInPlace();
641
+ const rotation = new Quaternion();
642
+ const yaw = new Float32Array(samples + 1);
643
+ let previous = 0;
644
+ for (let i = 0; i <= samples; i++) {
645
+ const wrapped = this._twist(this._rotationInCharacter(root, this._frameAt(i), rotation), reference);
646
+ // Unwrap, so a clip that turns past half a revolution keeps counting instead of jumping back.
647
+ previous = i === 0 ? wrapped : previous + WrapAngle(wrapped - WrapAngle(previous));
648
+ yaw[i] = previous;
649
+ }
650
+ return yaw;
651
+ }
652
+ _measureRootTravel(yaw, minimumTravel, forced) {
653
+ const root = this._rootNode;
654
+ const samples = this._sampleCount;
655
+ const positions = [];
656
+ for (let i = 0; i <= samples; i++) {
657
+ positions.push(this._positionInCharacter(root, this._frameAt(i), new Vector3()));
658
+ }
659
+ const start = positions[0];
660
+ // Net travel over the cycle, not how far the root strays: an in-place loop returns to where it started however
661
+ // much its hips surge and sway (a lurching walk can surge a fifth of the character's height), while a clip that
662
+ // really travels ends a stride or more away. A clip that travels and comes back, like a circle, reads as in place,
663
+ // which is safe: its feet do not slide either, so nothing is applied twice.
664
+ const net = this._horizontal(positions[samples].subtract(start), new Vector3());
665
+ if (!forced && net.length() < minimumTravel) {
666
+ return null;
667
+ }
668
+ if (net.lengthSquared() > 0) {
669
+ this._travelDirection.copyFrom(net).normalize();
670
+ }
671
+ if (!yaw && !this._extractLateral) {
672
+ this._snapTravelDirection(0);
673
+ // Whatever the root still drifts sideways of a snapped direction over a cycle would stay in the pose and pop
674
+ // back at every loop, so it is removed from the keys too, evenly over the cycle - but not applied.
675
+ this._horizontal(net, this._lateralDrift).subtractInPlace(this._travelDirection.scale(Vector3.Dot(net, this._travelDirection)));
676
+ }
677
+ const translation = new Float32Array((samples + 1) * 3);
678
+ const offset = new Vector3();
679
+ for (let i = 0; i <= samples; i++) {
680
+ this._rootTravelAt(positions[i], start, yaw ? yaw[i] : 0, !!yaw, offset).toArray(translation, i * 3);
681
+ }
682
+ return translation;
683
+ }
684
+ /**
685
+ * The travel removed from the root at a pose, so that the in-place root keeps the start position (turning) or its
686
+ * sway (straight).
687
+ * @param position defines the root position in character space
688
+ * @param start defines the root position in character space at the first frame
689
+ * @param yaw defines the turn at this pose
690
+ * @param turning defines whether turning is extracted
691
+ * @param result defines the vector receiving the travel
692
+ * @returns the result vector
693
+ */
694
+ _rootTravelAt(position, start, yaw, turning, result) {
695
+ if (turning) {
696
+ // Every horizontal move, since the direction of travel is turning with the character.
697
+ const pivot = this._rotateAboutUp(this._horizontal(start, TmpVectors.Vector3[3]), yaw, TmpVectors.Vector3[3]);
698
+ return this._horizontal(position, result).subtractInPlace(pivot);
699
+ }
700
+ return this._project(position.subtractToRef(start, result), result);
701
+ }
702
+ _measureContactTravel(yaw, explicitContacts, minimumTravel, forced) {
703
+ const samples = this._sampleCount;
704
+ const up = this._upAxis;
705
+ let contacts;
706
+ if (explicitContacts) {
707
+ contacts = explicitContacts.map((node) => this._resolveNode(node)).filter((node) => !!node);
708
+ }
709
+ else {
710
+ const base = this._rootNode ?? this._characterNode;
711
+ contacts = base.getDescendants(false, IsJoint).filter((node) => !node.getChildren(IsJoint, true).length);
712
+ }
713
+ if (!contacts.length) {
714
+ return null;
715
+ }
716
+ // Every candidate across the whole clip: a run starts with a foot in the air, so one frame cannot tell which
717
+ // nodes ever reach the ground.
718
+ const positions = contacts.map(() => []);
719
+ const lowest = contacts.map(() => Number.POSITIVE_INFINITY);
720
+ for (let i = 0; i <= samples; i++) {
721
+ const frame = this._frameAt(i);
722
+ for (let c = 0; c < contacts.length; c++) {
723
+ const position = this._positionInCharacter(contacts[c], frame, new Vector3());
724
+ positions[c].push(position);
725
+ lowest[c] = Math.min(lowest[c], Vector3.Dot(position, up));
726
+ }
727
+ }
728
+ if (!explicitContacts) {
729
+ const ground = Math.min(...lowest);
730
+ const kept = contacts.map((_, c) => lowest[c] <= ground + ContactHeightBand * this._characterHeight);
731
+ contacts = contacts.filter((_, c) => kept[c]);
732
+ const keptPositions = positions.filter((_, c) => kept[c]);
733
+ const keptLowest = lowest.filter((_, c) => kept[c]);
734
+ positions.length = 0;
735
+ positions.push(...keptPositions);
736
+ lowest.length = 0;
737
+ lowest.push(...keptLowest);
738
+ }
739
+ // A planted contact does not move in the world, so in character space it moves at exactly the opposite of the
740
+ // character's own velocity - and that velocity changes smoothly. A swinging contact sweeps forwards, even while
741
+ // touching down, when it can already be the lowest; a contact of a clip whose root carries the travel stands
742
+ // still. So each interval takes the contact on the ground whose step is closest to the ground speed of the
743
+ // interval before, starting from the clip's average ground speed measured with the slowest contact on the
744
+ // ground. With no contact on the ground - the flight of a run - the ground speed carries on.
745
+ // Steps are compared with the turn so far undone, so a turning path keeps a steady ground speed.
746
+ const tolerance = PlantedHeightBand * this._characterHeight;
747
+ const step = new Vector3();
748
+ const unturned = new Vector3();
749
+ const reference = new Vector3();
750
+ const translation = new Float32Array((samples + 1) * 3);
751
+ const travelled = Vector3.Zero();
752
+ const heading = Vector3.Zero();
753
+ let pathLength = 0;
754
+ const walk = (tracking) => {
755
+ const previous = reference.clone();
756
+ const sum = Vector3.Zero();
757
+ let grounded = 0;
758
+ travelled.setAll(0);
759
+ heading.setAll(0);
760
+ pathLength = 0;
761
+ for (let i = 1; i <= samples; i++) {
762
+ const turn = yaw ? yaw[i] : 0;
763
+ let best = Number.POSITIVE_INFINITY;
764
+ const chosen = new Vector3();
765
+ for (let c = 0; c < contacts.length; c++) {
766
+ const before = positions[c][i - 1];
767
+ const after = positions[c][i];
768
+ if (Vector3.Dot(before, up) > lowest[c] + tolerance || Vector3.Dot(after, up) > lowest[c] + tolerance) {
769
+ continue;
770
+ }
771
+ this._rotateAboutUp(this._horizontal(before.subtractToRef(after, step), step), -turn, unturned);
772
+ const score = tracking ? Vector3.DistanceSquared(unturned, previous) : unturned.lengthSquared();
773
+ if (score < best) {
774
+ best = score;
775
+ chosen.copyFrom(unturned);
776
+ }
777
+ }
778
+ if (best === Number.POSITIVE_INFINITY) {
779
+ chosen.copyFrom(previous);
780
+ }
781
+ else {
782
+ sum.addInPlace(chosen);
783
+ grounded++;
784
+ }
785
+ if (tracking) {
786
+ previous.copyFrom(chosen);
787
+ }
788
+ heading.addInPlace(chosen);
789
+ pathLength += chosen.length();
790
+ travelled.addInPlace(this._rotateAboutUp(chosen, turn, step)).toArray(translation, i * 3);
791
+ }
792
+ if (!tracking && grounded > 0) {
793
+ reference.copyFrom(sum).scaleInPlace(1 / grounded);
794
+ }
795
+ };
796
+ walk(false);
797
+ walk(true);
798
+ const straightness = pathLength > 0 ? heading.length() / pathLength : 0;
799
+ if (travelled.lengthSquared() > 0) {
800
+ this._travelDirection.copyFrom(travelled).normalize();
801
+ }
802
+ const distance = Vector3.Dot(travelled, this._travelDirection);
803
+ if (!forced && (distance < minimumTravel || straightness < MinimumStraightness)) {
804
+ return null;
805
+ }
806
+ if (!yaw) {
807
+ // Straight: only the travel along the direction, like the root path.
808
+ if (!this._extractLateral) {
809
+ this._snapTravelDirection(DeducedDirectionSnapAngle);
810
+ }
811
+ for (let i = 0; i <= samples; i++) {
812
+ step.fromArray(translation, i * 3);
813
+ this._travelDirection.scaleToRef(Vector3.Dot(step, this._travelDirection), step).toArray(translation, i * 3);
814
+ }
815
+ }
816
+ this._contactNodes = contacts;
817
+ return translation;
818
+ }
819
+ /**
820
+ * Clones the source group into the in-place group. When the root motion is in the root's keys, the root's channels
821
+ * are cloned with the motion left out: each key's pose, in character space, has the motion at its frame undone. The
822
+ * motion is the root's travel for a {@link RootMotionSource.Root} clip, plus the turn when rotation is extracted.
823
+ * Everything is computed from the source keys, which are not touched.
824
+ * @param name defines the name of the in-place group
825
+ * @param cloneAnimations defines whether every animation is cloned rather than only the rewritten root channels
826
+ * @returns the in-place group
827
+ */
828
+ _buildInPlaceGroup(name, cloneAnimations) {
829
+ const group = this._sourceGroup.clone(name);
830
+ // Cloning widens the range to the keys again; the in-place group plays what the source plays.
831
+ group.from = this._sourceGroup.from;
832
+ group.to = this._sourceGroup.to;
833
+ if (cloneAnimations) {
834
+ for (const targetedAnimation of group.targetedAnimations) {
835
+ targetedAnimation.animation = CloneAnimation(targetedAnimation.animation, true);
836
+ }
837
+ }
838
+ const root = this._rootNode;
839
+ if (!root || (!this._removesRootTravel && !this._turns)) {
840
+ return group;
841
+ }
842
+ const channels = this._channels.get(root);
843
+ const parent = root.parent;
844
+ const removesTravel = this._removesRootTravel;
845
+ const range = Math.max(this._toFrame - this._fromFrame, 1e-6);
846
+ const start = this._positionInCharacter(root, this._fromFrame, new Vector3());
847
+ const reference = this._rotationInCharacter(root, this._fromFrame, new Quaternion());
848
+ reference.conjugateInPlace();
849
+ const motionMatrix = new Matrix();
850
+ const rootMatrix = new Matrix();
851
+ const parentMatrix = new Matrix();
852
+ const localMatrix = new Matrix();
853
+ const yawQuaternion = new Quaternion();
854
+ const scratchPosition = new Vector3();
855
+ const scratchRotation = new Quaternion();
856
+ const travel = new Vector3();
857
+ // The in-place local transform of the root at any frame, from the source keys.
858
+ const inPlaceAt = (frame, position, rotation) => {
859
+ this._matrixToCharacter(root, frame, rootMatrix);
860
+ this._matrixToCharacter(parent, frame, parentMatrix);
861
+ let yaw = 0;
862
+ if (this._turns) {
863
+ // Exact at this frame; the track only settles which whole turn the angle is on.
864
+ const wrapped = this._twist(this._rotationInCharacter(root, frame, scratchRotation), reference);
865
+ const tracked = this.getRotationAtFrame(frame);
866
+ yaw = wrapped + Math.round((tracked - wrapped) / (2 * Math.PI)) * 2 * Math.PI;
867
+ }
868
+ if (removesTravel) {
869
+ rootMatrix.getTranslationToRef(scratchPosition);
870
+ this._rootTravelAt(scratchPosition, start, yaw, this._turns, travel);
871
+ if (!this._turns) {
872
+ travel.addInPlace(this._lateralDrift.scale(Math.min(1, Math.max(0, (frame - this._fromFrame) / range))));
873
+ }
874
+ }
875
+ else if (this._pivots) {
876
+ this._rootTravelAt(start, start, yaw, true, travel);
877
+ }
878
+ else {
879
+ travel.setAll(0);
880
+ }
881
+ // The motion maps the in-place pose onto the clip's pose: turn, then travel.
882
+ Matrix.FromQuaternionToRef(Quaternion.RotationAxisToRef(this._upAxis, yaw, yawQuaternion), motionMatrix);
883
+ motionMatrix.setTranslation(travel);
884
+ motionMatrix.invertToRef(motionMatrix);
885
+ rootMatrix.multiplyToRef(motionMatrix, localMatrix);
886
+ parentMatrix.invertToRef(parentMatrix);
887
+ localMatrix.multiplyToRef(parentMatrix, localMatrix);
888
+ localMatrix.decompose(undefined, rotation, position);
889
+ };
890
+ const position = new Vector3();
891
+ const rotation = new Quaternion();
892
+ const before = { position: new Vector3(), rotation: new Quaternion() };
893
+ const after = { position: new Vector3(), rotation: new Quaternion() };
894
+ // The keys of a channel with the motion left out, at the frames of the source keys.
895
+ const inPlaceKeys = (sourceKeys, kind) => {
896
+ const keys = [];
897
+ let previousRotation = null;
898
+ let previousEuler = null;
899
+ for (const key of sourceKeys) {
900
+ inPlaceAt(key.frame, position, rotation);
901
+ let value;
902
+ if (kind === "position") {
903
+ value = position.clone();
904
+ }
905
+ else {
906
+ // Stay in the same hemisphere as the previous key, so interpolation does not take the long way round.
907
+ if (previousRotation && Quaternion.Dot(previousRotation, rotation) < 0) {
908
+ rotation.scaleInPlace(-1);
909
+ }
910
+ previousRotation = rotation.clone();
911
+ if (kind === "rotationQuaternion") {
912
+ value = previousRotation;
913
+ }
914
+ else {
915
+ // Each angle continues from the previous key, so interpolation does not swing the long way round
916
+ // where the conversion from a quaternion jumps between +PI and -PI.
917
+ const euler = previousRotation.toEulerAngles();
918
+ if (previousEuler) {
919
+ euler.x += Math.round((previousEuler.x - euler.x) / (2 * Math.PI)) * 2 * Math.PI;
920
+ euler.y += Math.round((previousEuler.y - euler.y) / (2 * Math.PI)) * 2 * Math.PI;
921
+ euler.z += Math.round((previousEuler.z - euler.z) / (2 * Math.PI)) * 2 * Math.PI;
922
+ }
923
+ previousEuler = euler;
924
+ value = euler;
925
+ }
926
+ }
927
+ // Cubic spline tangents follow the rewritten curve. Straight travel is a linear removal, so the key's own
928
+ // tangent is transformed exactly; a turn is not, so the tangents are measured from the curve either side.
929
+ const tangent = (original, direction) => {
930
+ if (!original) {
931
+ return original;
932
+ }
933
+ if (kind === "position" && !this._turns) {
934
+ this._matrixToCharacter(parent, key.frame, parentMatrix);
935
+ const inCharacter = Vector3.TransformNormal(original, parentMatrix);
936
+ const removed = removesTravel ? this._project(inCharacter.clone(), new Vector3()).addInPlace(this._lateralDrift.scale(1 / range)) : Vector3.Zero();
937
+ parentMatrix.invertToRef(parentMatrix);
938
+ return original.subtract(Vector3.TransformNormal(removed, parentMatrix));
939
+ }
940
+ inPlaceAt(key.frame - TangentDelta, before.position, before.rotation);
941
+ inPlaceAt(key.frame + TangentDelta, after.position, after.rotation);
942
+ const low = direction < 0 ? before : { position, rotation };
943
+ const high = direction < 0 ? { position, rotation } : after;
944
+ if (kind === "position") {
945
+ return high.position.subtract(low.position).scaleInPlace(1 / TangentDelta);
946
+ }
947
+ if (Quaternion.Dot(low.rotation, high.rotation) < 0) {
948
+ high.rotation.scaleInPlace(-1);
949
+ }
950
+ const rate = high.rotation.subtract(low.rotation).scaleInPlace(1 / TangentDelta);
951
+ return kind === "rotationQuaternion"
952
+ ? rate
953
+ : high.rotation
954
+ .toEulerAngles()
955
+ .subtract(low.rotation.toEulerAngles())
956
+ .scaleInPlace(1 / TangentDelta);
957
+ };
958
+ keys.push({
959
+ frame: key.frame,
960
+ value,
961
+ inTangent: tangent(key.inTangent, -1),
962
+ outTangent: tangent(key.outTangent, 1),
963
+ interpolation: key.interpolation,
964
+ lockedTangent: key.lockedTangent,
965
+ easingFunction: key.easingFunction,
966
+ });
967
+ }
968
+ return keys;
969
+ };
970
+ // A rewritten channel replaces the source's in the in-place group; the source animation is not touched.
971
+ const replace = (source, kind) => {
972
+ const animation = CloneAnimation(source);
973
+ animation.setKeys(inPlaceKeys(source.getKeys(), kind), true);
974
+ // By animation and target both: the same animation may drive other nodes earlier in the group.
975
+ const index = this._sourceGroup.targetedAnimations.findIndex((targetedAnimation) => targetedAnimation.animation === source && targetedAnimation.target === root);
976
+ group.targetedAnimations[index].animation = animation;
977
+ };
978
+ if (channels.position) {
979
+ replace(channels.position, "position");
980
+ }
981
+ else {
982
+ // A root that only turns gets a position channel of its own, holding it at its starting point while the
983
+ // character turns about that point. It is the clip's clock, the channel the mixer weighs every clip of the
984
+ // character on, and it keeps the root in place when another clip animates the position. Its keys are as
985
+ // dense as the analysis: an animated ancestor between the root and the character makes the position vary.
986
+ const rotationChannel = (channels.rotationQuaternion ?? channels.rotation);
987
+ const staticKeys = [];
988
+ for (let i = 0; i <= this._sampleCount; i++) {
989
+ staticKeys.push({ frame: this._frameAt(i), value: root.position });
990
+ }
991
+ const animation = new Animation(`${root.name} position`, "position", rotationChannel.framePerSecond, Animation.ANIMATIONTYPE_VECTOR3, rotationChannel.loopMode);
992
+ animation.enableBlending = rotationChannel.enableBlending;
993
+ animation.blendingSpeed = rotationChannel.blendingSpeed;
994
+ animation.setKeys(inPlaceKeys(staticKeys, "position"), true);
995
+ group.addTargetedAnimation(animation, root);
996
+ this._restoredPosition = root.position.clone();
997
+ this._clockProperty = "position";
998
+ }
999
+ if (this._turns) {
1000
+ if (channels.rotationQuaternion) {
1001
+ replace(channels.rotationQuaternion, "rotationQuaternion");
1002
+ }
1003
+ else if (channels.rotation) {
1004
+ replace(channels.rotation, "rotation");
1005
+ }
1006
+ }
1007
+ return group;
1008
+ }
1009
+ _findRootNode() {
1010
+ const nodes = Array.from(this._channels.keys());
1011
+ let best = null;
1012
+ let bestCount = -1;
1013
+ for (const [node, channels] of this._channels) {
1014
+ if (!channels.position) {
1015
+ continue;
1016
+ }
1017
+ const count = nodes.filter((other) => other !== node && other.isDescendantOf(node)).length;
1018
+ if (count > bestCount || (count === bestCount && best && best.isDescendantOf(node))) {
1019
+ best = node;
1020
+ bestCount = count;
1021
+ }
1022
+ }
1023
+ return best;
1024
+ }
1025
+ _measureHeight(base) {
1026
+ const position = new Vector3();
1027
+ let lowest = Number.POSITIVE_INFINITY;
1028
+ let highest = Number.NEGATIVE_INFINITY;
1029
+ for (const node of [base, ...base.getDescendants(false, IsJoint)]) {
1030
+ const height = Vector3.Dot(this._positionInCharacter(node, this._fromFrame, position), this._upAxis);
1031
+ lowest = Math.min(lowest, height);
1032
+ highest = Math.max(highest, height);
1033
+ }
1034
+ return highest - lowest;
1035
+ }
1036
+ /**
1037
+ * The track sample before a frame; the blend towards the next one is left in _sampleBlend.
1038
+ * @param frame defines the frame
1039
+ * @returns the sample index
1040
+ */
1041
+ _sampleAt(frame) {
1042
+ const range = this._toFrame - this._fromFrame;
1043
+ const samples = this._sampleCount;
1044
+ if (range <= 0 || (this._source === 0 /* RootMotionSource.None */ && !this._turns)) {
1045
+ this._sampleBlend = 0;
1046
+ return 0;
1047
+ }
1048
+ const exact = Math.min(samples, Math.max(0, ((frame - this._fromFrame) / range) * samples));
1049
+ const index = Math.min(samples - 1, Math.floor(exact));
1050
+ this._sampleBlend = exact - index;
1051
+ return index;
1052
+ }
1053
+ _frameAt(sample) {
1054
+ return this._fromFrame + ((this._toFrame - this._fromFrame) * sample) / this._sampleCount;
1055
+ }
1056
+ _horizontal(vector, result) {
1057
+ const up = this._upAxis;
1058
+ const height = Vector3.Dot(vector, up);
1059
+ return result.set(vector.x - up.x * height, vector.y - up.y * height, vector.z - up.z * height);
1060
+ }
1061
+ _project(vector, result) {
1062
+ this._horizontal(vector, result);
1063
+ if (!this._extractLateral) {
1064
+ this._travelDirection.scaleToRef(Vector3.Dot(result, this._travelDirection), result);
1065
+ }
1066
+ return result;
1067
+ }
1068
+ /**
1069
+ * Snaps the direction of travel onto the nearest horizontal character space axis within the snap angle.
1070
+ * @param defaultAngle defines the snap angle when none was given in the options
1071
+ */
1072
+ _snapTravelDirection(defaultAngle) {
1073
+ const angle = this._directionSnapAngle ?? defaultAngle;
1074
+ if (angle <= 0) {
1075
+ return;
1076
+ }
1077
+ const up = this._upAxis;
1078
+ const axis = new Vector3();
1079
+ let best = null;
1080
+ let bestDot = Math.cos(angle);
1081
+ for (const candidate of [Vector3.RightReadOnly, Vector3.UpReadOnly, Vector3.Forward(false)]) {
1082
+ if (Math.abs(Vector3.Dot(candidate, up)) > 0.5) {
1083
+ continue;
1084
+ }
1085
+ this._horizontal(candidate, axis).normalize();
1086
+ for (const sign of [1, -1]) {
1087
+ const dot = sign * Vector3.Dot(axis, this._travelDirection);
1088
+ if (dot >= bestDot) {
1089
+ bestDot = dot;
1090
+ best = axis.scale(sign);
1091
+ }
1092
+ }
1093
+ }
1094
+ if (best) {
1095
+ this._travelDirection.copyFrom(best);
1096
+ }
1097
+ }
1098
+ _rotateAboutUp(vector, angle, result) {
1099
+ if (angle === 0) {
1100
+ return result.copyFrom(vector);
1101
+ }
1102
+ Matrix.FromQuaternionToRef(Quaternion.RotationAxisToRef(this._upAxis, angle, this._yawQuaternion), this._yawMatrix);
1103
+ return Vector3.TransformNormalToRef(vector, this._yawMatrix, result);
1104
+ }
1105
+ /**
1106
+ * The turn about the up axis from a reference orientation to a rotation, both in character space: the angle of the
1107
+ * rotation about the up axis that best matches the change of orientation. Unlike the twist of a swing-twist split,
1108
+ * it stays well defined while the root pitches and rolls - a dancer's hips tilting through the vertical made the
1109
+ * twist jump by half turns.
1110
+ * @param rotation defines the rotation
1111
+ * @param referenceConjugate defines the conjugate of the reference rotation
1112
+ * @returns the angle in radians, between -PI and PI
1113
+ */
1114
+ _twist(rotation, referenceConjugate) {
1115
+ const delta = Matrix.FromQuaternionToRef(rotation.multiplyToRef(referenceConjugate, TmpVectors.Quaternion[1]), TmpVectors.Matrix[2]);
1116
+ const up = this._upAxis;
1117
+ // Two horizontal axes, right-handed with up the way +X, +Z are with +Y.
1118
+ const first = this._horizontal(Math.abs(up.x) < 0.9 ? Vector3.RightReadOnly : Vector3.Forward(false), TmpVectors.Vector3[5]).normalize();
1119
+ const second = Vector3.CrossToRef(first, up, TmpVectors.Vector3[6]);
1120
+ const turnedFirst = Vector3.TransformNormalToRef(first, delta, TmpVectors.Vector3[7]);
1121
+ const turnedSecond = Vector3.TransformNormalToRef(second, delta, TmpVectors.Vector3[8]);
1122
+ return WrapAngle(Math.atan2(Vector3.Dot(turnedSecond, first) - Vector3.Dot(turnedFirst, second), Vector3.Dot(turnedFirst, first) + Vector3.Dot(turnedSecond, second)));
1123
+ }
1124
+ _positionInCharacter(node, frame, result) {
1125
+ const matrix = this._matrixToCharacter(node, frame, TmpVectors.Matrix[1]);
1126
+ return result.set(matrix.m[12], matrix.m[13], matrix.m[14]);
1127
+ }
1128
+ _rotationInCharacter(node, frame, result) {
1129
+ this._matrixToCharacter(node, frame, TmpVectors.Matrix[1]).decompose(undefined, result);
1130
+ return result;
1131
+ }
1132
+ /**
1133
+ * Composes a node's transform into character space at a frame of the clip, from the evaluated keys of animated
1134
+ * nodes and the current transform of the others. Nothing is played or written.
1135
+ * @param node defines the node, or null for the character space itself
1136
+ * @param frame defines the frame to evaluate
1137
+ * @param result defines the matrix receiving the transform
1138
+ * @returns the result matrix
1139
+ */
1140
+ _matrixToCharacter(node, frame, result) {
1141
+ Matrix.IdentityToRef(result);
1142
+ const local = TmpVectors.Matrix[0];
1143
+ let current = node;
1144
+ while (current && current !== this._characterNode) {
1145
+ if (current instanceof TransformNode) {
1146
+ this._localMatrix(current, frame, local);
1147
+ result.multiplyToRef(local, result);
1148
+ }
1149
+ current = current.parent;
1150
+ }
1151
+ return result;
1152
+ }
1153
+ _localMatrix(node, frame, result) {
1154
+ const channels = this._channels.get(node);
1155
+ const scaling = channels?.scaling ? channels.scaling.evaluate(frame) : node.scaling;
1156
+ const position = channels?.position ? channels.position.evaluate(frame) : node.position;
1157
+ let rotation;
1158
+ if (channels?.rotationQuaternion) {
1159
+ rotation = channels.rotationQuaternion.evaluate(frame);
1160
+ }
1161
+ else if (channels?.rotation) {
1162
+ rotation = Quaternion.FromEulerVectorToRef(channels.rotation.evaluate(frame), TmpVectors.Quaternion[0]);
1163
+ }
1164
+ else {
1165
+ rotation = node.rotationQuaternion ?? Quaternion.FromEulerVectorToRef(node.rotation, TmpVectors.Quaternion[0]);
1166
+ }
1167
+ return Matrix.ComposeToRef(scaling, rotation, position, result);
1168
+ }
1169
+ _resolveNode(node) {
1170
+ if (node instanceof TransformNode) {
1171
+ return node;
1172
+ }
1173
+ const linked = node.getTransformNode();
1174
+ if (!linked) {
1175
+ throw new Error(`RootMotionClip: bone "${node.name}" has no linked transform node; pass the transform node the bone drives instead.`);
1176
+ }
1177
+ return linked;
1178
+ }
1179
+ _firstAnimatedNode() {
1180
+ for (const node of this._channels.keys()) {
1181
+ return node;
1182
+ }
1183
+ return null;
1184
+ }
1185
+ _topmostAncestor(node) {
1186
+ let top = node;
1187
+ let current = node.parent;
1188
+ while (current) {
1189
+ if (current instanceof TransformNode) {
1190
+ top = current;
1191
+ }
1192
+ current = current.parent;
1193
+ }
1194
+ return top;
1195
+ }
1196
+ }
1197
+ /**
1198
+ * Moves and turns a character node by the root motion of the clips playing on it, once per animation step - from the
1199
+ * scene's onAfterAnimationsObservable, so after animations are evaluated and before the world matrices are computed.
1200
+ *
1201
+ * The motion of each clip follows the playback of its in-place group's root animation: the progress of the pose it
1202
+ * evaluated, so pausing, speed ratio changes, looping in every loop mode, forwards and backwards, playing a range,
1203
+ * synchronizing with another animatable and running to the end all move the character exactly as far as the pose went.
1204
+ * Clips playing together are blended the way the animation mixer blends their root pose: weighted animation groups
1205
+ * contribute their share, normalized once their weights add up to more than one, additive groups add theirs on top,
1206
+ * an unweighted group contributes its whole pose only while no weighted group animates the root (among unweighted
1207
+ * groups the last to write wins), and a group blending in contributes as much as it is blended in, so the character
1208
+ * moves with the blended pose whatever the clips do. The turn is blended as a weighted sum of the clips' turns.
1209
+ *
1210
+ * ```ts
1211
+ * const controller = new RootMotionController(character, [walk, run]);
1212
+ * walk.animationGroup.start(true);
1213
+ * run.animationGroup.start(true);
1214
+ * walk.animationGroup.weight = 0.3;
1215
+ * run.animationGroup.weight = 0.7;
1216
+ * ```
1217
+ */
1218
+ export class RootMotionController {
1219
+ /**
1220
+ * The node the motion is applied to.
1221
+ */
1222
+ get characterNode() {
1223
+ return this._characterNode;
1224
+ }
1225
+ /**
1226
+ * The clips whose motion moves the character.
1227
+ */
1228
+ get clips() {
1229
+ return this._clips;
1230
+ }
1231
+ /**
1232
+ * The travel of the last animation step, in world space; applied to the character unless
1233
+ * {@link RootMotionController.applyToCharacter} is false.
1234
+ */
1235
+ get deltaPosition() {
1236
+ return this._deltaPosition;
1237
+ }
1238
+ /**
1239
+ * The turn of the last animation step about the up axis, in radians; applied to the character unless
1240
+ * {@link RootMotionController.applyToCharacter} is false.
1241
+ */
1242
+ get deltaRotation() {
1243
+ return this._deltaRotation;
1244
+ }
1245
+ /**
1246
+ * Creates a controller for a character node.
1247
+ * @param characterNode defines the node to move: the character node of the clips
1248
+ * @param clips defines the clips to add
1249
+ */
1250
+ constructor(characterNode, clips = []) {
1251
+ /**
1252
+ * Gets or sets whether the motion is applied to the character node every frame. Set it to false to consume
1253
+ * {@link RootMotionController.deltaPosition} and {@link RootMotionController.deltaRotation} yourself, for example
1254
+ * to drive a physics character controller.
1255
+ */
1256
+ this.applyToCharacter = true;
1257
+ /**
1258
+ * Notified every animation step the clips produce motion, after {@link RootMotionController.deltaPosition} and
1259
+ * {@link RootMotionController.deltaRotation} are updated.
1260
+ */
1261
+ this.onRootMotionObservable = new Observable();
1262
+ this._clips = [];
1263
+ this._upAxis = null;
1264
+ this._deltaPosition = Vector3.Zero();
1265
+ this._deltaRotation = 0;
1266
+ this._frameDelta = Vector3.Zero();
1267
+ this._frameYaw = 0;
1268
+ this._clipDelta = Vector3.Zero();
1269
+ this._characterNode = characterNode;
1270
+ this._sceneRootMotion = SceneRootMotion.Get(characterNode.getScene());
1271
+ this._sceneRootMotion.add(this);
1272
+ for (const clip of clips) {
1273
+ this.addClip(clip);
1274
+ }
1275
+ }
1276
+ /**
1277
+ * Adds a clip, so the character moves while its in-place group plays.
1278
+ * @param clip defines the clip; its character node must be the controller's
1279
+ * @throws when the clip belongs to another controller, moves another node, or has another up axis than the clips
1280
+ * already added
1281
+ */
1282
+ addClip(clip) {
1283
+ if (clip._controller === this) {
1284
+ return;
1285
+ }
1286
+ if (clip._controller) {
1287
+ throw new Error(`RootMotionController: clip "${clip.animationGroup.name}" already belongs to another controller.`);
1288
+ }
1289
+ if (clip.characterNode !== this._characterNode) {
1290
+ throw new Error(`RootMotionController: clip "${clip.animationGroup.name}" moves "${clip.characterNode.name}", not "${this._characterNode.name}". Pass the controller's node as the clip's characterNode.`);
1291
+ }
1292
+ if (this._upAxis && !this._upAxis.equalsWithEpsilon(clip.upAxis)) {
1293
+ throw new Error(`RootMotionController: clip "${clip.animationGroup.name}" has another up axis than the clips already added.`);
1294
+ }
1295
+ this._upAxis = this._upAxis ?? clip.upAxis.clone();
1296
+ clip._controller = this;
1297
+ clip._forgetPlayback();
1298
+ this._clips.push(clip);
1299
+ this._sceneRootMotion.refresh();
1300
+ }
1301
+ /**
1302
+ * Removes a clip. Its in-place group keeps playing, in place.
1303
+ * @param clip defines the clip
1304
+ */
1305
+ removeClip(clip) {
1306
+ const index = this._clips.indexOf(clip);
1307
+ if (index < 0) {
1308
+ return;
1309
+ }
1310
+ this._clips.splice(index, 1);
1311
+ clip._controller = null;
1312
+ clip._writers = null;
1313
+ clip._forgetPlayback();
1314
+ if (!this._clips.length) {
1315
+ this._upAxis = null;
1316
+ }
1317
+ this._sceneRootMotion.refresh();
1318
+ }
1319
+ /**
1320
+ * Forgets where the playbacks were last measured. Call after jumping a group with goToFrame or resetting it, so the
1321
+ * jump is not read as motion. Starting a group again needs no reset.
1322
+ */
1323
+ reset() {
1324
+ for (const clip of this._clips) {
1325
+ // Reset from an animation event, after the clock wrote the step: that evaluation predates the jump, and the
1326
+ // next one is the first to say where the playback carries on from.
1327
+ const runtime = clip._clockRuntime;
1328
+ clip._forgetPlayback();
1329
+ clip._staleRuntime = runtime;
1330
+ clip._staleProgress = runtime ? runtime._evaluatedProgress : null;
1331
+ }
1332
+ this._deltaPosition.setAll(0);
1333
+ this._deltaRotation = 0;
1334
+ }
1335
+ /**
1336
+ * Stops applying the motion and lets the clips go. The clips and their groups are not disposed.
1337
+ */
1338
+ dispose() {
1339
+ for (const clip of this._clips) {
1340
+ clip._controller = null;
1341
+ clip._writers = null;
1342
+ clip._forgetPlayback();
1343
+ }
1344
+ this._clips.length = 0;
1345
+ this._upAxis = null;
1346
+ this._sceneRootMotion.remove(this);
1347
+ this.onRootMotionObservable.clear();
1348
+ }
1349
+ /**
1350
+ * @internal
1351
+ * Applies the motion of this frame, once the mixer's writers of the clips' channels are gathered.
1352
+ * @param animated defines whether the scene animated this step at all; when it did not, nothing moved and nothing
1353
+ * is read into the clips' playbacks
1354
+ */
1355
+ _update(animated) {
1356
+ const delta = this._frameDelta.setAll(0);
1357
+ this._frameYaw = 0;
1358
+ let moved = false;
1359
+ for (const clip of animated ? this._clips : []) {
1360
+ const writers = clip._writers;
1361
+ const previous = clip._clockRuntime;
1362
+ const found = clip._findClock();
1363
+ if (found !== previous) {
1364
+ // A runtime animation belongs to one playback. The previous playback's last evaluation is still to be
1365
+ // consumed if it wrote this step - it ran to its end, or a callback stopped it after it wrote - weighed
1366
+ // among the writers of this step like any other. One that did not write this step is forgotten: its
1367
+ // last evaluation was consumed in the step it wrote.
1368
+ if (previous && writers && clip._lastProgress !== null && !clip._parked && writers.current.indexOf(previous) >= 0) {
1369
+ moved = this._accumulate(clip, previous, clip._lastProgress, previous._evaluatedProgress) || moved;
1370
+ }
1371
+ clip._clockRuntime = found;
1372
+ clip._clockAnimatable = found ? clip._foundAnimatable : null;
1373
+ clip._syncRuntime = null;
1374
+ clip._lastProgress = null;
1375
+ clip._parked = false;
1376
+ }
1377
+ if (!found || !writers) {
1378
+ continue;
1379
+ }
1380
+ const animatable = clip._clockAnimatable;
1381
+ if (writers.current.indexOf(found) < 0) {
1382
+ // Did not write this step. Paused, its clock stands still too, and carries on from here when it resumes.
1383
+ // Parked at a weight of zero, the scene skips it while its clock runs on: it starts again from wherever
1384
+ // it resumes. Passed over for any other reason - by the scene's loop after a callback removed the
1385
+ // animatable before it, or restarted after being passed over as paused - its next evaluation catches up,
1386
+ // and the character with it.
1387
+ if (!animatable.paused && animatable.weight === 0) {
1388
+ clip._parked = true;
1389
+ }
1390
+ continue;
1391
+ }
1392
+ if (clip._parked) {
1393
+ clip._parked = false;
1394
+ clip._lastProgress = null;
1395
+ }
1396
+ // The root the evaluation was actually clocked by, as it was made: a callback of this very step may have
1397
+ // synchronized the group afterwards, and this step's pose is still the one the old clock gave.
1398
+ const syncRoot = found._evaluatedSyncRoot;
1399
+ const syncRuntime = syncRoot ? (syncRoot.getAnimations()[0] ?? null) : null;
1400
+ if (syncRoot !== clip._syncRoot || syncRuntime !== clip._syncRuntime || found._evaluatedJump) {
1401
+ // Synchronized with another root, no longer synchronized at all and back on its own clock, or snapped
1402
+ // back by a root that cannot carry it to its end: the pose jumps, which is not travel.
1403
+ clip._syncRoot = syncRoot;
1404
+ clip._syncRuntime = syncRuntime;
1405
+ clip._lastProgress = null;
1406
+ }
1407
+ // The first evaluation of a playback only establishes where it began - unless the playback was reset since
1408
+ // that evaluation, by a callback in this step, in which case the next one does.
1409
+ const progress = found._evaluatedProgress;
1410
+ const lastProgress = clip._lastProgress;
1411
+ if (lastProgress === null && found === clip._staleRuntime && progress === clip._staleProgress) {
1412
+ continue;
1413
+ }
1414
+ clip._staleRuntime = null;
1415
+ clip._staleProgress = null;
1416
+ clip._lastProgress = progress;
1417
+ if (lastProgress !== null && progress !== lastProgress) {
1418
+ moved = this._accumulate(clip, found, lastProgress, progress) || moved;
1419
+ }
1420
+ }
1421
+ if (!moved) {
1422
+ this._deltaPosition.setAll(0);
1423
+ this._deltaRotation = 0;
1424
+ return;
1425
+ }
1426
+ const deltaYaw = this._frameYaw;
1427
+ this._deltaRotation = deltaYaw;
1428
+ const character = this._characterNode;
1429
+ const up = this._upAxis;
1430
+ // Into the character's parent space through its own local rotation and scaling, not its world matrix: world
1431
+ // matrices are cached per render, so with fixed animation steps every step after the first in a frame would read
1432
+ // the facing from before the previous step's turn.
1433
+ const rotation = character.rotationQuaternion ?? Quaternion.FromEulerVectorToRef(character.rotation, TmpVectors.Quaternion[2]);
1434
+ Matrix.ComposeToRef(character.scaling, rotation, Vector3.ZeroReadOnly, TmpVectors.Matrix[3]);
1435
+ const parentDelta = Vector3.TransformNormalToRef(delta, TmpVectors.Matrix[3], TmpVectors.Vector3[4]);
1436
+ const parent = character.parent;
1437
+ if (parent) {
1438
+ // Computed now, not read from the cache: with several animation steps in a render the parent may have moved.
1439
+ Vector3.TransformNormalToRef(parentDelta, parent.computeWorldMatrix(true), this._deltaPosition);
1440
+ }
1441
+ else {
1442
+ this._deltaPosition.copyFrom(parentDelta);
1443
+ }
1444
+ if (this.applyToCharacter) {
1445
+ // Assigned rather than changed in place, so the node is marked dirty and renders where it now is.
1446
+ character.position = character.position.addInPlace(parentDelta);
1447
+ if (deltaYaw !== 0) {
1448
+ // The turn happens in character space, before the character's own scaling. A mirroring scale (the
1449
+ // handedness flip on a glTF __root__) reverses the sense of a turn once it is past that scaling.
1450
+ const scaling = character.scaling;
1451
+ const mirrored = scaling.x * scaling.y * scaling.z * (up.x * up.x * scaling.x + up.y * up.y * scaling.y + up.z * up.z * scaling.z) < 0;
1452
+ if (!character.rotationQuaternion) {
1453
+ character.rotationQuaternion = Quaternion.FromEulerVector(character.rotation);
1454
+ }
1455
+ const turned = character.rotationQuaternion;
1456
+ turned.multiplyToRef(Quaternion.RotationAxisToRef(up, mirrored ? -deltaYaw : deltaYaw, TmpVectors.Quaternion[2]), turned);
1457
+ character.rotationQuaternion = turned;
1458
+ }
1459
+ }
1460
+ if (this.onRootMotionObservable.hasObservers()) {
1461
+ this.onRootMotionObservable.notifyObservers(this);
1462
+ }
1463
+ }
1464
+ /**
1465
+ * Adds a clip's motion between two progresses of a playback into this frame's motion, weighted the way the mixer
1466
+ * weighs the pose of the playback.
1467
+ * @param clip defines the clip
1468
+ * @param runtime defines the runtime animation of the clip's clock
1469
+ * @param lastProgress defines the progress consumed before
1470
+ * @param progress defines the progress to consume
1471
+ * @returns whether anything was added
1472
+ */
1473
+ _accumulate(clip, runtime, lastProgress, progress) {
1474
+ if ((clip.source === 0 /* RootMotionSource.None */ && !clip.extractsRotation) || !clip._writers) {
1475
+ return false;
1476
+ }
1477
+ const weight = this._effectiveWeight(clip._writers, runtime);
1478
+ if (weight === 0) {
1479
+ return false;
1480
+ }
1481
+ const yaw = clip._motionBetween(runtime._evaluatedFrom, runtime._evaluatedTo, lastProgress, progress, this._clipDelta);
1482
+ this._frameDelta.addInPlace(this._clipDelta.scaleInPlace(weight));
1483
+ this._frameYaw += yaw * weight;
1484
+ return true;
1485
+ }
1486
+ /**
1487
+ * The share of a playback in the pose the mixer wrote to its channel this step, following the late animation
1488
+ * bindings of the scene: an unweighted animatable writes directly and the last one wins, unless a weighted animatable
1489
+ * also animates the channel, in which case the weighted ones replace it - normalized once their weights add up to
1490
+ * more than one - and additive ones add their weight on top. A playback that ran to its end this step is among the
1491
+ * writers like any other, from its place in the order they wrote; one that did not write this step has no share;
1492
+ * one that wrote more than once - re-evaluated by an animation event, say - has the share of all its writes, as the
1493
+ * bindings add them up. A playback still blending in wrote that much of its pose, so the share follows the factor
1494
+ * its last write blended in with, taken from the record of that write rather than from the animation, whose own
1495
+ * factor a write made since the step may have moved on.
1496
+ * @param writers defines what the mixer wrote to the clip's channel this step
1497
+ * @param runtime defines the runtime animation of the clip's clock
1498
+ * @returns the share, between 0 and 1
1499
+ */
1500
+ _effectiveWeight(writers, runtime) {
1501
+ const runtimes = writers.current;
1502
+ let overrides = 0;
1503
+ let additives = 0;
1504
+ let direct = false;
1505
+ let weight = 0;
1506
+ let blending = 1;
1507
+ for (let i = 0; i < runtimes.length; i++) {
1508
+ if (runtimes[i] !== runtime) {
1509
+ continue;
1510
+ }
1511
+ // The bindings hold one entry per write, added up from the weights as written, but each entry is read with
1512
+ // the weight the runtime animation carries when the bindings are processed: that of its last write.
1513
+ weight = writers.currentWeights[i];
1514
+ blending = writers.currentBlending[i];
1515
+ if (weight < 0) {
1516
+ direct = true;
1517
+ }
1518
+ else if (writers.currentAdditive[i]) {
1519
+ additives++;
1520
+ }
1521
+ else {
1522
+ overrides++;
1523
+ }
1524
+ }
1525
+ let share = (overrides / Math.max(1, writers.total) + additives) * weight;
1526
+ if (direct && !writers.weighted && writers.lastDirect === runtime) {
1527
+ share += 1;
1528
+ }
1529
+ return share * blending;
1530
+ }
1531
+ }
1532
+ /**
1533
+ * The root motion controllers of a scene. After the scene's animations, one pass over the writes of the step - the
1534
+ * runtime animations that wrote, in that order, with the weights they wrote with, recorded as they did - gathers what
1535
+ * the mixer wrote to every channel a clip follows, then each controller applies its frame.
1536
+ */
1537
+ class SceneRootMotion {
1538
+ /**
1539
+ * Gets the root motion of a scene, creating it if needed.
1540
+ * @param scene defines the scene
1541
+ * @returns the root motion of the scene
1542
+ */
1543
+ static Get(scene) {
1544
+ let sceneRootMotion = SceneRootMotions.get(scene);
1545
+ if (!sceneRootMotion) {
1546
+ sceneRootMotion = new SceneRootMotion(scene);
1547
+ SceneRootMotions.set(scene, sceneRootMotion);
1548
+ }
1549
+ return sceneRootMotion;
1550
+ }
1551
+ constructor(scene) {
1552
+ this._controllers = [];
1553
+ this._writers = [];
1554
+ this._writersByNode = new Map();
1555
+ this._scene = scene;
1556
+ this._observer = scene.onAfterAnimationsObservable.add(() => this._update());
1557
+ }
1558
+ /**
1559
+ * Adds a controller, updated after those added before.
1560
+ * @param controller defines the controller
1561
+ */
1562
+ add(controller) {
1563
+ this._controllers.push(controller);
1564
+ this.refresh();
1565
+ }
1566
+ /**
1567
+ * Removes a controller. The scene's root motion goes with its last controller.
1568
+ * @param controller defines the controller
1569
+ */
1570
+ remove(controller) {
1571
+ const index = this._controllers.indexOf(controller);
1572
+ if (index >= 0) {
1573
+ this._controllers.splice(index, 1);
1574
+ }
1575
+ this.refresh();
1576
+ if (!this._controllers.length) {
1577
+ this._observer?.remove();
1578
+ this._observer = null;
1579
+ SceneRootMotions.delete(this._scene);
1580
+ }
1581
+ }
1582
+ /**
1583
+ * Gathers the channels the controllers' clips follow, once the clips of a controller change.
1584
+ */
1585
+ refresh() {
1586
+ this._writers.length = 0;
1587
+ this._writersByNode.clear();
1588
+ for (const controller of this._controllers) {
1589
+ for (const clip of controller.clips) {
1590
+ const node = clip._clockNode;
1591
+ if (!node) {
1592
+ clip._writers = null;
1593
+ continue;
1594
+ }
1595
+ let entries = this._writersByNode.get(node);
1596
+ if (!entries) {
1597
+ entries = [];
1598
+ this._writersByNode.set(node, entries);
1599
+ }
1600
+ let entry = entries.find((candidate) => candidate.property === clip._clockProperty);
1601
+ if (!entry) {
1602
+ entry = {
1603
+ property: clip._clockProperty,
1604
+ total: 0,
1605
+ weighted: false,
1606
+ lastDirect: null,
1607
+ current: [],
1608
+ currentWeights: [],
1609
+ currentAdditive: [],
1610
+ currentBlending: [],
1611
+ };
1612
+ entries.push(entry);
1613
+ this._writers.push(entry);
1614
+ }
1615
+ clip._writers = entry;
1616
+ }
1617
+ }
1618
+ }
1619
+ _update() {
1620
+ // A step the scene did not evaluate - its animations disabled when it began - wrote nothing and moved nothing,
1621
+ // and the clips' playbacks stand where they are: unlike a playback parked at a weight of zero, which an
1622
+ // evaluated step skips while its clock runs on. Whether the step evaluated is recorded by the step itself: a
1623
+ // callback may disable the animations after the step's writes, and the step still completes.
1624
+ const scene = this._scene;
1625
+ const animated = scene._animationStepEvaluated;
1626
+ const writers = this._writers;
1627
+ for (let i = 0; i < writers.length; i++) {
1628
+ const entry = writers[i];
1629
+ entry.total = 0;
1630
+ entry.weighted = false;
1631
+ entry.lastDirect = null;
1632
+ entry.current.length = 0;
1633
+ entry.currentWeights.length = 0;
1634
+ entry.currentAdditive.length = 0;
1635
+ entry.currentBlending.length = 0;
1636
+ }
1637
+ // What the mixer wrote this step: every write of a runtime animation to a target, in order, with the weight and
1638
+ // the mode it was made with, recorded as it was made rather than read back afterwards - one whose playback ran
1639
+ // to its end has left the active animatables, one stopped by a callback in the same step has lost its runtime
1640
+ // animations, one turned additive since was bound as it wrote, and an animation of several targets wrote each
1641
+ // of them. A paused animatable, one not started yet and one parked at a weight of zero wrote nothing.
1642
+ //
1643
+ // Only the writes the step's late bindings read: those of the step itself, up to the point the bindings were
1644
+ // processed. A write made after them - by an observer of this very notification, such as the one an animation
1645
+ // group started on a virtual timeline samples from, or by a callback between steps - reached no binding of this
1646
+ // step, so it says nothing about the pose the step blended. The scene holds such a write over to the front of
1647
+ // the next step's records, where it is read in its place: before that step's writes, which is where it stands
1648
+ // in the order the bindings resolve. Reading it here instead would make the frame's motion depend on whether
1649
+ // the controller was constructed before or after the observer that made it.
1650
+ const writes = scene._animationWrites;
1651
+ const count = animated ? scene._animationStepWriteCount : 0;
1652
+ for (let i = 0; i < count; i++) {
1653
+ const write = writes[i];
1654
+ const entries = this._writersByNode.get(write.target);
1655
+ if (!entries) {
1656
+ continue;
1657
+ }
1658
+ const runtime = write.runtimeAnimation;
1659
+ const weight = write.weight;
1660
+ for (let k = 0; k < entries.length; k++) {
1661
+ const entry = entries[k];
1662
+ if (entry.property !== runtime.targetPath) {
1663
+ continue;
1664
+ }
1665
+ entry.current.push(runtime);
1666
+ entry.currentWeights.push(weight);
1667
+ entry.currentAdditive.push(write.additive);
1668
+ entry.currentBlending.push(write.blendingFactor);
1669
+ if (weight < 0) {
1670
+ // Direct writers overwrite one another in order, so the last one is the pose.
1671
+ entry.lastDirect = runtime;
1672
+ }
1673
+ else {
1674
+ entry.weighted = true;
1675
+ if (!write.additive) {
1676
+ entry.total += weight;
1677
+ }
1678
+ }
1679
+ }
1680
+ }
1681
+ for (let i = 0; i < this._controllers.length; i++) {
1682
+ this._controllers[i]._update(animated);
1683
+ }
1684
+ }
1685
+ }
1686
+ /**
1687
+ * Clones an animation as {@link Animation.clone} does, keeping the easing function and events with it.
1688
+ * @param source defines the animation to clone
1689
+ * @param cloneKeys defines whether the keys and their values are cloned too, rather than shared until replaced
1690
+ * @returns the clone
1691
+ */
1692
+ function CloneAnimation(source, cloneKeys = false) {
1693
+ const animation = source.clone(cloneKeys);
1694
+ const easingFunction = source.getEasingFunction();
1695
+ if (easingFunction) {
1696
+ animation.setEasingFunction(easingFunction);
1697
+ }
1698
+ for (const event of source.getEvents()) {
1699
+ animation.addEvent(event);
1700
+ }
1701
+ return animation;
1702
+ }
1703
+ function IsJoint(node) {
1704
+ return node instanceof TransformNode && !(node instanceof AbstractMesh);
1705
+ }
1706
+ function WrapAngle(angle) {
1707
+ return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));
1708
+ }
1709
+ //# sourceMappingURL=rootMotion.js.map