@zephyr3d/scene 0.9.22 → 0.9.23

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 (234) hide show
  1. package/dist/animation/joint_dynamics/collision.js +1 -7
  2. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  3. package/dist/animation/joint_dynamics/constraints.js +2 -17
  4. package/dist/animation/joint_dynamics/constraints.js.map +1 -1
  5. package/dist/animation/joint_dynamics/controller.js +2 -20
  6. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  7. package/dist/animation/joint_dynamics/joint_dynamics_system.js +1 -3
  8. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  9. package/dist/animation/joint_dynamics/solver.js +14 -60
  10. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  11. package/dist/animation/joint_dynamics/types.js +3 -3
  12. package/dist/animation/joint_dynamics/types.js.map +1 -1
  13. package/dist/app/app.js +23 -0
  14. package/dist/app/app.js.map +1 -1
  15. package/dist/app/scriptregistry.js +16 -53
  16. package/dist/app/scriptregistry.js.map +1 -1
  17. package/dist/asset/assetmanager.js +2 -0
  18. package/dist/asset/assetmanager.js.map +1 -1
  19. package/dist/asset/model.js +22 -0
  20. package/dist/asset/model.js.map +1 -1
  21. package/dist/blitter/bilateralblur.js +3 -1
  22. package/dist/blitter/bilateralblur.js.map +1 -1
  23. package/dist/blitter/blitter.js +3 -3
  24. package/dist/blitter/blitter.js.map +1 -1
  25. package/dist/camera/camera.js +398 -45
  26. package/dist/camera/camera.js.map +1 -1
  27. package/dist/camera/perspectivecamera.js +69 -2
  28. package/dist/camera/perspectivecamera.js.map +1 -1
  29. package/dist/index.d.ts +9113 -8734
  30. package/dist/index.js +9 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/material/blinn.js +1 -1
  33. package/dist/material/blinn.js.map +1 -1
  34. package/dist/material/lambert.js +3 -3
  35. package/dist/material/lambert.js.map +1 -1
  36. package/dist/material/material.js +8 -5
  37. package/dist/material/material.js.map +1 -1
  38. package/dist/material/meshmaterial.js +17 -10
  39. package/dist/material/meshmaterial.js.map +1 -1
  40. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  41. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  42. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  43. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  44. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +21 -6
  45. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  46. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +1 -1
  47. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  48. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +1 -1
  49. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  50. package/dist/material/mixins/lit.js +33 -11
  51. package/dist/material/mixins/lit.js.map +1 -1
  52. package/dist/material/mixins/pbr/brdf.js +44 -12
  53. package/dist/material/mixins/pbr/brdf.js.map +1 -1
  54. package/dist/material/mixins/pbr/common.js +149 -14
  55. package/dist/material/mixins/pbr/common.js.map +1 -1
  56. package/dist/material/mtoon.js +7 -4
  57. package/dist/material/mtoon.js.map +1 -1
  58. package/dist/material/pbrblueprint.js +5 -1
  59. package/dist/material/pbrblueprint.js.map +1 -1
  60. package/dist/material/pbrmr.js +1 -1
  61. package/dist/material/pbrmr.js.map +1 -1
  62. package/dist/material/pbrsg.js +1 -1
  63. package/dist/material/pbrsg.js.map +1 -1
  64. package/dist/material/shader/helper.js +186 -11
  65. package/dist/material/shader/helper.js.map +1 -1
  66. package/dist/material/skin.js +2 -2
  67. package/dist/material/skin.js.map +1 -1
  68. package/dist/material/terrain-cm.js +5 -5
  69. package/dist/material/terrain-cm.js.map +1 -1
  70. package/dist/material/water.js +6 -4
  71. package/dist/material/water.js.map +1 -1
  72. package/dist/posteffect/bloom.js +54 -4
  73. package/dist/posteffect/bloom.js.map +1 -1
  74. package/dist/posteffect/compositor.js +41 -0
  75. package/dist/posteffect/compositor.js.map +1 -1
  76. package/dist/posteffect/posteffect.js +35 -0
  77. package/dist/posteffect/posteffect.js.map +1 -1
  78. package/dist/posteffect/sao.js +7 -6
  79. package/dist/posteffect/sao.js.map +1 -1
  80. package/dist/posteffect/skinsss.js +3 -3
  81. package/dist/posteffect/skinsss.js.map +1 -1
  82. package/dist/posteffect/ssgi.js +988 -436
  83. package/dist/posteffect/ssgi.js.map +1 -1
  84. package/dist/posteffect/ssr.js +83 -45
  85. package/dist/posteffect/ssr.js.map +1 -1
  86. package/dist/posteffect/sss.js +18 -15
  87. package/dist/posteffect/sss.js.map +1 -1
  88. package/dist/posteffect/taa.js +5 -4
  89. package/dist/posteffect/taa.js.map +1 -1
  90. package/dist/posteffect/tonemap.js +15 -3
  91. package/dist/posteffect/tonemap.js.map +1 -1
  92. package/dist/render/abuffer_oit.js +2 -2
  93. package/dist/render/abuffer_oit.js.map +1 -1
  94. package/dist/render/cluster_light.js +12 -6
  95. package/dist/render/cluster_light.js.map +1 -1
  96. package/dist/render/drawable_mixin.js +8 -5
  97. package/dist/render/drawable_mixin.js.map +1 -1
  98. package/dist/render/dualdepthpeeling_oit.js +10 -5
  99. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  100. package/dist/render/envlight.js +298 -5
  101. package/dist/render/envlight.js.map +1 -1
  102. package/dist/render/gpu_picking.js +7 -5
  103. package/dist/render/gpu_picking.js.map +1 -1
  104. package/dist/render/hzb.js +28 -19
  105. package/dist/render/hzb.js.map +1 -1
  106. package/dist/render/lightpass.js +18 -4
  107. package/dist/render/lightpass.js.map +1 -1
  108. package/dist/render/render_queue.js +37 -4
  109. package/dist/render/render_queue.js.map +1 -1
  110. package/dist/render/renderer.js +8 -3
  111. package/dist/render/renderer.js.map +1 -1
  112. package/dist/render/rendergraph/blackboard.js +20 -48
  113. package/dist/render/rendergraph/blackboard.js.map +1 -1
  114. package/dist/render/rendergraph/device_pool_allocator.js +18 -58
  115. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  116. package/dist/render/rendergraph/executor.js +89 -115
  117. package/dist/render/rendergraph/executor.js.map +1 -1
  118. package/dist/render/rendergraph/forward_plus_builder.js +1003 -715
  119. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  120. package/dist/render/rendergraph/frame_graph_context.js +1 -1
  121. package/dist/render/rendergraph/frame_graph_context.js.map +1 -1
  122. package/dist/render/rendergraph/frame_resource_requirements.js +14 -0
  123. package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -0
  124. package/dist/render/rendergraph/history_resource_manager.js +74 -140
  125. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  126. package/dist/render/rendergraph/history_resources.js +7 -5
  127. package/dist/render/rendergraph/history_resources.js.map +1 -1
  128. package/dist/render/rendergraph/render_context.js +19 -0
  129. package/dist/render/rendergraph/render_context.js.map +1 -0
  130. package/dist/render/rendergraph/render_pipeline.js +315 -0
  131. package/dist/render/rendergraph/render_pipeline.js.map +1 -0
  132. package/dist/render/rendergraph/rendergraph.js +158 -141
  133. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  134. package/dist/render/rendergraph/scene_render_context.js +267 -0
  135. package/dist/render/rendergraph/scene_render_context.js.map +1 -0
  136. package/dist/render/rendergraph/texture_affinity_cache.js +19 -0
  137. package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -0
  138. package/dist/render/rendergraph/types.js +19 -31
  139. package/dist/render/rendergraph/types.js.map +1 -1
  140. package/dist/render/renderpass.js +3 -3
  141. package/dist/render/renderpass.js.map +1 -1
  142. package/dist/render/shadow_mask_pass.js +7 -6
  143. package/dist/render/shadow_mask_pass.js.map +1 -1
  144. package/dist/render/sky.js +197 -35
  145. package/dist/render/sky.js.map +1 -1
  146. package/dist/render/weightedblended_oit.js +4 -3
  147. package/dist/render/weightedblended_oit.js.map +1 -1
  148. package/dist/scene/basesprite.js +2 -0
  149. package/dist/scene/basesprite.js.map +1 -1
  150. package/dist/scene/batchgroup.js +10 -0
  151. package/dist/scene/batchgroup.js.map +1 -1
  152. package/dist/scene/environment.js +61 -2
  153. package/dist/scene/environment.js.map +1 -1
  154. package/dist/scene/light.js +178 -10
  155. package/dist/scene/light.js.map +1 -1
  156. package/dist/scene/meshdrawable.js +89 -2
  157. package/dist/scene/meshdrawable.js.map +1 -1
  158. package/dist/scene/msdftext.js +2 -0
  159. package/dist/scene/msdftext.js.map +1 -1
  160. package/dist/scene/msdftextsprite.js +2 -0
  161. package/dist/scene/msdftextsprite.js.map +1 -1
  162. package/dist/scene/particlesys.js +2 -0
  163. package/dist/scene/particlesys.js.map +1 -1
  164. package/dist/scene/scene.js +34 -1
  165. package/dist/scene/scene.js.map +1 -1
  166. package/dist/scene/terrain-cm/grass.js +2 -1
  167. package/dist/scene/terrain-cm/grass.js.map +1 -1
  168. package/dist/scene/terrain-cm/terrain-cm.js +2 -0
  169. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  170. package/dist/scene/water.js +2 -0
  171. package/dist/scene/water.js.map +1 -1
  172. package/dist/shaders/atmosphere.js +5 -4
  173. package/dist/shaders/atmosphere.js.map +1 -1
  174. package/dist/shaders/fog.js +10 -3
  175. package/dist/shaders/fog.js.map +1 -1
  176. package/dist/shaders/shadow.js +96 -29
  177. package/dist/shaders/shadow.js.map +1 -1
  178. package/dist/shaders/ssgi_reprojection.js +118 -0
  179. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  180. package/dist/shaders/ssr.js +322 -154
  181. package/dist/shaders/ssr.js.map +1 -1
  182. package/dist/shadow/esm.js +10 -7
  183. package/dist/shadow/esm.js.map +1 -1
  184. package/dist/shadow/pcf_opt.js +12 -12
  185. package/dist/shadow/pcf_opt.js.map +1 -1
  186. package/dist/shadow/pcf_pd.js +12 -12
  187. package/dist/shadow/pcf_pd.js.map +1 -1
  188. package/dist/shadow/pcss.js +15 -11
  189. package/dist/shadow/pcss.js.map +1 -1
  190. package/dist/shadow/shadow_impl.js +20 -2
  191. package/dist/shadow/shadow_impl.js.map +1 -1
  192. package/dist/shadow/shadowmapper.js +5 -2
  193. package/dist/shadow/shadowmapper.js.map +1 -1
  194. package/dist/shadow/ssm.js +13 -13
  195. package/dist/shadow/ssm.js.map +1 -1
  196. package/dist/shadow/vsm.js +7 -7
  197. package/dist/shadow/vsm.js.map +1 -1
  198. package/dist/utility/physical.js +74 -0
  199. package/dist/utility/physical.js.map +1 -0
  200. package/dist/utility/rendermipmap.js +2 -2
  201. package/dist/utility/rendermipmap.js.map +1 -1
  202. package/dist/utility/serialization/manager.js +3 -1
  203. package/dist/utility/serialization/manager.js.map +1 -1
  204. package/dist/utility/serialization/scene/animation.js +3 -1
  205. package/dist/utility/serialization/scene/animation.js.map +1 -1
  206. package/dist/utility/serialization/scene/batch.js +3 -1
  207. package/dist/utility/serialization/scene/batch.js.map +1 -1
  208. package/dist/utility/serialization/scene/camera.js +598 -2
  209. package/dist/utility/serialization/scene/camera.js.map +1 -1
  210. package/dist/utility/serialization/scene/light.js +180 -9
  211. package/dist/utility/serialization/scene/light.js.map +1 -1
  212. package/dist/utility/serialization/scene/material.js +43 -3
  213. package/dist/utility/serialization/scene/material.js.map +1 -1
  214. package/dist/utility/serialization/scene/mesh.js +3 -1
  215. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  216. package/dist/utility/serialization/scene/node.js +3 -1
  217. package/dist/utility/serialization/scene/node.js.map +1 -1
  218. package/dist/utility/serialization/scene/particle.js +3 -1
  219. package/dist/utility/serialization/scene/particle.js.map +1 -1
  220. package/dist/utility/serialization/scene/primitive.js +2 -0
  221. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  222. package/dist/utility/serialization/scene/scene.js +70 -0
  223. package/dist/utility/serialization/scene/scene.js.map +1 -1
  224. package/dist/utility/serialization/scene/sprite.js +3 -1
  225. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  226. package/dist/utility/serialization/scene/terrain.js +3 -1
  227. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  228. package/dist/utility/serialization/scene/text.js +3 -0
  229. package/dist/utility/serialization/scene/text.js.map +1 -1
  230. package/dist/utility/serialization/scene/water.js +3 -1
  231. package/dist/utility/serialization/scene/water.js.map +1 -1
  232. package/dist/values.js +2 -3
  233. package/dist/values.js.map +1 -1
  234. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"joint_dynamics_system.js","sources":["../../../src/animation/joint_dynamics/joint_dynamics_system.ts"],"sourcesContent":["import type { DeepPartial } from '@zephyr3d/base';\r\nimport { InterpolatorScalar, Vector3 } from '@zephyr3d/base';\r\nimport { Quaternion } from '@zephyr3d/base';\r\nimport { SceneNode } from '../../scene/scene_node';\r\nimport type {\r\n ControllerConfig,\r\n JointDynamicsColliderSnapshot,\r\n JointDynamicsColliderHandle,\r\n JointDynamicsFlatPlaneSnapshot,\r\n JointDynamicsFlatPlaneHandle,\r\n JointDynamicsGrabberSnapshot,\r\n JointDynamicsGrabberHandle\r\n} from './controller';\r\nimport { JointDynamicsSystemController } from './controller';\r\nimport { ColliderForce, type BoneNode, type ColliderR, type GrabberR, type TransformAccess } from './types';\r\nimport type { SkeletonBindPose } from '../skeleton';\r\n\r\nconst _quat = new Quaternion();\r\n\r\nconst _defaultTA = createTransformAccess(new SceneNode(null), false);\r\n\r\n/**\r\n * Create a transform adapter that lets the joint dynamics solver read from and write to a SceneNode.\r\n *\r\n * @param obj - Scene node to expose through the TransformAccess interface.\r\n * @returns A TransformAccess wrapper backed by the supplied scene node.\r\n *\r\n * @public\r\n */\r\nexport function createTransformAccess(obj: SceneNode, exposeNode = true): TransformAccess {\r\n return {\r\n ...(exposeNode ? { node: obj } : {}),\r\n getWorldPosition(): Vector3 {\r\n return obj.getWorldPosition();\r\n },\r\n getWorldRotation(): Quaternion {\r\n const q = new Quaternion();\r\n obj.worldMatrix.decompose(null, q, null);\r\n return q;\r\n },\r\n getWorldScale(): Vector3 {\r\n const s = new Vector3();\r\n obj.worldMatrix.decompose(s, null, null);\r\n return s;\r\n },\r\n getLocalPosition(): Vector3 {\r\n return obj.position.clone();\r\n },\r\n getLocalRotation(): Quaternion {\r\n return obj.rotation.clone();\r\n },\r\n getLocalScale(): Vector3 {\r\n return obj.scale.clone();\r\n },\r\n setWorldPosition(p: Vector3): void {\r\n if (obj.parent) {\r\n obj.position = obj.parent.invWorldMatrix.transformPointAffine(p);\r\n } else {\r\n obj.position.set(p);\r\n }\r\n },\r\n setWorldRotation(q: Quaternion): void {\r\n // Convert world rotation to local: localRot = inverse(parentWorldRot) * worldRot\r\n if (obj.parent) {\r\n obj.parent.worldMatrix.decompose(null, _quat, null);\r\n Quaternion.multiply(Quaternion.inverse(_quat), q, obj.rotation);\r\n } else {\r\n obj.rotation.set(q);\r\n }\r\n },\r\n setLocalPosition(p: Vector3): void {\r\n obj.position.set(p);\r\n },\r\n setLocalRotation(q: Quaternion): void {\r\n obj.rotation.set(q);\r\n },\r\n setLocalScale(s: Vector3): void {\r\n obj.scale.set(s);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Describes the bone chains simulated by a JointDynamicsSystem.\r\n *\r\n * Each chain is defined by an inclusive start and end node. The end node must be\r\n * a descendant of the start node.\r\n *\r\n * @public\r\n */\r\nexport type JointChainConfig = {\r\n /** Root transform used for root motion compensation. */\r\n systemRoot: SceneNode;\r\n /** Bone chains to simulate. */\r\n chains: { start: SceneNode; end: SceneNode }[];\r\n};\r\n\r\n/**\r\n * Configuration used to construct a JointDynamicsSystem.\r\n *\r\n * @public\r\n */\r\nexport type JointDynamicSystemConfig = {\r\n /** Bone chain topology and root transform. */\r\n chainConfig: JointChainConfig;\r\n /** Optional controller configuration overrides. */\r\n controllerConfig?: DeepPartial<ControllerConfig, 2>;\r\n};\r\n\r\n/**\r\n * Physics system for spring-like joint dynamics on scene node bone chains.\r\n *\r\n * The system builds particles and constraints from one or more bone chains,\r\n * advances them with Verlet integration, solves constraints and collisions, and\r\n * writes the resulting positions and rotations back to the scene graph.\r\n *\r\n * @public\r\n */\r\nexport class JointDynamicsSystem {\r\n private _controller: JointDynamicsSystemController;\r\n private _chainConfig: JointChainConfig;\r\n private _bindPose: WeakMap<SceneNode, SkeletonBindPose>;\r\n /**\r\n * Create a joint dynamics system for one or more bone chains.\r\n *\r\n * @param config - Bone chain topology and controller configuration.\r\n * @param colliders - Optional colliders to register during initialization.\r\n * @param grabbers - Optional grabbers to register during initialization.\r\n * @param flatPlanes - Optional world-space planes that dynamic points cannot cross.\r\n */\r\n constructor(\r\n config: JointDynamicSystemConfig,\r\n colliders: { r: ColliderR; transform: TransformAccess }[] = [],\r\n grabbers: {\r\n r: GrabberR;\r\n transform: TransformAccess;\r\n enabled: boolean;\r\n }[] = [],\r\n flatPlanes: { up: Vector3; position: Vector3 }[] = []\r\n ) {\r\n this._chainConfig = {\r\n systemRoot: config.chainConfig.systemRoot,\r\n chains: config.chainConfig.chains.map((chain) => ({ start: chain.start, end: chain.end }))\r\n };\r\n this._bindPose = new WeakMap();\r\n const rootPoints: BoneNode[] = [];\r\n const boneNodes: BoneNode[] = [];\r\n const boneToNode = new Map<BoneNode, SceneNode>();\r\n const pointTransforms: TransformAccess[] = [];\r\n const nodeToBone = new Map<SceneNode, BoneNode>();\r\n const nodeToDepth = new Map<SceneNode, number>();\r\n for (const chain of config.chainConfig.chains) {\r\n const chainNodes = this.collectChainNodes(chain.start, chain.end);\r\n let previous: BoneNode | null = null;\r\n for (let i = 0; i < chainNodes.length; i++) {\r\n const node = chainNodes[i];\r\n let boneNode = nodeToBone.get(node);\r\n if (!boneNode) {\r\n this._bindPose.set(node, {\r\n position: node.position.clone(),\r\n rotation: node.rotation.clone(),\r\n scale: node.scale.clone()\r\n });\r\n boneNode = {\r\n index: boneNodes.length,\r\n position: node.getWorldPosition(),\r\n children: [],\r\n isFixed: i === 0,\r\n depth: i\r\n };\r\n nodeToBone.set(node, boneNode);\r\n nodeToDepth.set(node, i);\r\n boneNodes.push(boneNode);\r\n boneToNode.set(boneNode, node);\r\n } else {\r\n const depth = nodeToDepth.get(node) ?? boneNode.depth;\r\n if (i < depth) {\r\n boneNode.depth = i;\r\n nodeToDepth.set(node, i);\r\n }\r\n boneNode.isFixed = boneNode.isFixed || i === 0;\r\n }\r\n if (previous && !previous.children.includes(boneNode)) {\r\n previous.children.push(boneNode);\r\n const rootIndex = rootPoints.indexOf(boneNode);\r\n if (rootIndex !== -1) {\r\n rootPoints.splice(rootIndex, 1);\r\n }\r\n } else if (!previous && !rootPoints.includes(boneNode)) {\r\n rootPoints.push(boneNode);\r\n }\r\n previous = boneNode;\r\n }\r\n }\r\n const orderedBoneNodes: BoneNode[] = [];\r\n const visitedBoneNodes = new Set<BoneNode>();\r\n const orderBoneNode = (boneNode: BoneNode) => {\r\n if (visitedBoneNodes.has(boneNode)) {\r\n return;\r\n }\r\n visitedBoneNodes.add(boneNode);\r\n boneNode.index = orderedBoneNodes.length;\r\n orderedBoneNodes.push(boneNode);\r\n for (const child of boneNode.children) {\r\n orderBoneNode(child);\r\n }\r\n };\r\n for (const root of rootPoints) {\r\n orderBoneNode(root);\r\n }\r\n boneNodes.length = 0;\r\n boneNodes.push(...orderedBoneNodes);\r\n pointTransforms.push(...boneNodes.map((boneNode) => createTransformAccess(boneToNode.get(boneNode)!)));\r\n const systemRoot = createTransformAccess(config.chainConfig.systemRoot);\r\n const defaultConfig = this.getDefaultControllerConfig();\r\n const controllerConfig: ControllerConfig = {\r\n ...defaultConfig,\r\n ...config?.controllerConfig,\r\n angleLimitConfig: { ...defaultConfig.angleLimitConfig, ...config?.controllerConfig?.angleLimitConfig },\r\n curves: { ...defaultConfig.curves, ...config?.controllerConfig?.curves },\r\n constraintOptions: {\r\n ...defaultConfig.constraintOptions,\r\n ...config?.controllerConfig?.constraintOptions\r\n }\r\n };\r\n this._controller = new JointDynamicsSystemController(controllerConfig);\r\n this._controller.initialize(systemRoot, rootPoints, pointTransforms, colliders, grabbers, flatPlanes);\r\n }\r\n\r\n /**\r\n * Get the low-level controller that owns simulation state and advanced runtime controls.\r\n *\r\n * Most callers should prefer the convenience methods on JointDynamicsSystem.\r\n *\r\n * @returns The underlying joint dynamics controller.\r\n */\r\n get controller(): JointDynamicsSystemController {\r\n return this._controller;\r\n }\r\n\r\n /**\r\n * Get the node chain topology used to construct this system.\r\n */\r\n get chainConfig(): JointChainConfig {\r\n return {\r\n systemRoot: this._chainConfig.systemRoot,\r\n chains: this._chainConfig.chains.map((chain) => ({ start: chain.start, end: chain.end }))\r\n };\r\n }\r\n\r\n /**\r\n * Returns detached collider snapshots for serialization.\r\n */\r\n getColliderSnapshots(): JointDynamicsColliderSnapshot[] {\r\n return this._controller.getColliderSnapshots();\r\n }\r\n\r\n /**\r\n * Returns detached flat-plane snapshots for serialization.\r\n */\r\n getFlatPlaneSnapshots(): JointDynamicsFlatPlaneSnapshot[] {\r\n return this._controller.getFlatPlaneSnapshots();\r\n }\r\n\r\n /**\r\n * Returns detached grabber snapshots for serialization.\r\n */\r\n getGrabberSnapshots(): JointDynamicsGrabberSnapshot[] {\r\n return this._controller.getGrabberSnapshots();\r\n }\r\n\r\n /**\r\n * Reset chain nodes to bind pose\r\n */\r\n resetChains() {\r\n for (const chain of this._chainConfig.chains) {\r\n const chainNodes = this.collectChainNodes(chain.start, chain.end);\r\n for (const node of chainNodes) {\r\n const bindPose = this._bindPose.get(node);\r\n if (bindPose) {\r\n node.position = bindPose.position;\r\n node.rotation = bindPose.rotation;\r\n node.scale = bindPose.scale;\r\n }\r\n }\r\n }\r\n }\r\n /**\r\n * Add a fully configured collider at runtime.\r\n *\r\n * The collider transform is read from the supplied scene node every simula ; ion step.\r\n * If no transform is supplied, the collider is created at the identity transform.\r\n *\r\n * @param r - Read-only collider parameters.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addCollider(r: ColliderR, transform?: SceneNode): JointDynamicsColliderHandle {\r\n return this._controller.addCollider(r, transform ? createTransformAccess(transform) : _defaultTA);\r\n }\r\n\r\n /**\r\n * Add a spherical collider at runtime.\r\n *\r\n * The collider transform is read from the supplied scene node every simulation step.\r\n * If no transform is supplied, the collider is created at the identity transform.\r\n *\r\n * @param radius - Sphere radius in world units before transform scaling.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @param friction - Contact friction coefficient applied by this collider. Defaults to 0.\r\n * @param inversed - If true, points are constrained inside the sphere instead of pushed out.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addSphereCollider(\r\n radius: number,\r\n transform?: SceneNode,\r\n friction?: number,\r\n inversed?: boolean\r\n ): JointDynamicsColliderHandle {\r\n return this.addCollider(\r\n {\r\n forceType: ColliderForce.Off,\r\n friction: friction ?? 0,\r\n height: 0,\r\n isInverseCollider: inversed ?? false,\r\n radius,\r\n radiusTailScale: 1\r\n },\r\n transform\r\n );\r\n }\r\n\r\n /**\r\n * Add a capsule collider at runtime.\r\n *\r\n * The capsule is aligned to the collider transform's local Y axis. Its head radius is\r\n * `radius`, its tail radius is `radius * radiusTailScale`, and `height` defines the\r\n * distance between the capsule ends before transform scaling.\r\n *\r\n * @param radius - Capsule head radius in world units before transform scaling.\r\n * @param height - Capsule length in world units before transform scaling.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @param radiusTailScale - Tail radius multiplier relative to the head radius. Defaults to 1.\r\n * @param friction - Contact friction coefficient applied by this collider. Defaults to 0.\r\n * @param inversed - If true, points are constrained inside the capsule instead of pushed out.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addCapsuleCollider(\r\n radius: number,\r\n height: number,\r\n transform?: SceneNode,\r\n radiusTailScale?: number,\r\n friction?: number,\r\n inversed?: boolean\r\n ): JointDynamicsColliderHandle {\r\n return this.addCollider(\r\n {\r\n forceType: ColliderForce.Off,\r\n friction: friction ?? 0,\r\n height,\r\n isInverseCollider: inversed ?? false,\r\n radius,\r\n radiusTailScale: radiusTailScale ?? 1\r\n },\r\n transform\r\n );\r\n }\r\n\r\n /**\r\n * Enable or disable a collider by stable handle.\r\n *\r\n * Disabled colliders remain registered but are ignored by simulation until re-enabled.\r\n *\r\n * @param handle - Collider handle returned by addCollider, addSphereCollider, or addCapsuleCollider.\r\n * @param enabled - Whether the collider should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setColliderEnabled(handle: JointDynamicsColliderHandle, enabled: boolean): boolean {\r\n return this._controller.setColliderEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a collider by stable handle.\r\n *\r\n * @param handle - Collider handle returned by addCollider, addSphereCollider, or addCapsuleCollider.\r\n * @returns true if the collider existed and was removed.\r\n */\r\n removeCollider(handle: JointDynamicsColliderHandle): boolean {\r\n return this._controller.removeCollider(handle);\r\n }\r\n\r\n /**\r\n * Remove a collider by current array index.\r\n *\r\n * Prefer removeCollider(handle) for runtime-owned colliders.\r\n *\r\n * @param index - Current collider array index.\r\n * @returns true if the collider existed and was removed.\r\n */\r\n removeColliderAt(index: number): boolean {\r\n return this._controller.removeColliderAt(index);\r\n }\r\n\r\n /**\r\n * Add a flat plane collider at runtime.\r\n *\r\n * Flat planes are infinite world-space planes. The normal points toward the allowed side,\r\n * and dynamic points are pushed back when they move behind the plane.\r\n *\r\n * @param up - Plane normal in world space.\r\n * @param position - A point on the plane in world space.\r\n * @returns A stable handle that remains valid until this flat plane is removed.\r\n */\r\n addFlatPlane(up: Vector3, position: Vector3): JointDynamicsFlatPlaneHandle {\r\n return this._controller.addFlatPlane(up, position);\r\n }\r\n\r\n /**\r\n * Enable or disable a flat plane by stable handle.\r\n *\r\n * Disabled flat planes remain registered but are ignored by simulation until re-enabled.\r\n *\r\n * @param handle - Flat plane handle returned by addFlatPlane.\r\n * @param enabled - Whether the flat plane should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setFlatPlaneEnabled(handle: JointDynamicsFlatPlaneHandle, enabled: boolean): boolean {\r\n return this._controller.setFlatPlaneEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a flat plane by stable handle.\r\n *\r\n * @param handle - Flat plane handle returned by addFlatPlane.\r\n * @returns true if the flat plane existed and was removed.\r\n */\r\n removeFlatPlane(handle: JointDynamicsFlatPlaneHandle): boolean {\r\n return this._controller.removeFlatPlane(handle);\r\n }\r\n\r\n /**\r\n * Remove a flat plane by current array index.\r\n * Prefer removeFlatPlane(handle) for runtime-owned flat planes.\r\n *\r\n * @param index - Current flat plane array index.\r\n * @returns true if the flat plane existed and was removed.\r\n */\r\n removeFlatPlaneAt(index: number): boolean {\r\n return this._controller.removeFlatPlaneAt(index);\r\n }\r\n\r\n /**\r\n * Add a grabber at runtime.\r\n *\r\n * The grabber transform is read from the supplied scene node every simulation step.\r\n * If no transform is supplied, the grabber is created at the identity transform.\r\n *\r\n * @param r - Read-only grabber parameters.\r\n * @param transform - Optional scene node that drives the grabber transform.\r\n * @returns A stable handle that remains valid until this grabber is removed.\r\n */\r\n addGrabber(r: GrabberR, transform?: SceneNode): JointDynamicsGrabberHandle {\r\n return this._controller.addGrabber(r, transform ? createTransformAccess(transform) : _defaultTA, false);\r\n }\r\n\r\n /**\r\n * Enable or disable a grabber by stable handle.\r\n *\r\n * Disabling a grabber also releases any points currently held by it.\r\n *\r\n * @param handle - Grabber handle returned by addGrabber.\r\n * @param enabled - Whether the grabber should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setGrabberEnabled(handle: JointDynamicsGrabberHandle, enabled: boolean): boolean {\r\n return this._controller.setGrabberEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a grabber by stable handle.\r\n *\r\n * @param handle - Grabber handle returned by addGrabber.\r\n * @returns true if the grabber existed and was removed.\r\n */\r\n removeGrabber(handle: JointDynamicsGrabberHandle): boolean {\r\n return this._controller.removeGrabber(handle);\r\n }\r\n\r\n /**\r\n * Remove a grabber by current array index.\r\n *\r\n * Prefer removeGrabber(handle) for runtime-owned grabbers.\r\n *\r\n * @param index - Current grabber array index.\r\n * @returns true if the grabber existed and was removed.\r\n */\r\n removeGrabberAt(index: number): boolean {\r\n return this._controller.removeGrabberAt(index);\r\n }\r\n\r\n private collectChainNodes(start: SceneNode, end: SceneNode): SceneNode[] {\r\n if (!start.isParentOf(end)) {\r\n throw new Error('Invalid chain: end node must be a descendant of start node');\r\n }\r\n const nodes: SceneNode[] = [];\r\n let current: SceneNode = end;\r\n for (;;) {\r\n nodes.unshift(current);\r\n if (current === start) {\r\n break;\r\n }\r\n current = current.parent!;\r\n }\r\n return nodes;\r\n }\r\n /**\r\n * Advance the physics simulation and write the resulting transforms back to the chain nodes.\r\n *\r\n * @param deltaTime - Frame time step in seconds. Values larger than 0.033 are clamped for stability.\r\n */\r\n update(deltaTime: number): void {\r\n // Clamp deltaTime to prevent instability\r\n const dt = Math.min(deltaTime, 0.033); // Max 30 FPS\r\n // simulation\r\n this._controller.step(dt);\r\n }\r\n /** @internal */\r\n private getDefaultControllerConfig(): ControllerConfig {\r\n return {\r\n gravity: new Vector3(0, -9.8, 0),\r\n relaxation: 3,\r\n subSteps: 3,\r\n enableSurfaceCollision: false,\r\n windForce: Vector3.zero(),\r\n rootSlideLimit: -1,\r\n rootRotateLimit: -1,\r\n constraintShrinkLimit: 1,\r\n blendRatio: 0,\r\n stabilizationFrameRate: 60,\r\n isFakeWave: false,\r\n fakeWaveSpeed: 0,\r\n fakeWavePower: 0,\r\n angleLimitConfig: { angleLimit: -1, limitFromRoot: false },\r\n enableBroadPhase: false,\r\n preserveTwist: true,\r\n curves: {\r\n gravityScale: InterpolatorScalar.constant(1),\r\n windForceScale: InterpolatorScalar.constant(1),\r\n massScale: InterpolatorScalar.constant(1),\r\n resistance: InterpolatorScalar.constant(0.95),\r\n hardness: InterpolatorScalar.constant(0.001),\r\n friction: InterpolatorScalar.constant(0.5),\r\n pointRadius: InterpolatorScalar.constant(0.05),\r\n sliderJointLength: InterpolatorScalar.constant(0),\r\n allShrinkScale: InterpolatorScalar.constant(1),\r\n allStretchScale: InterpolatorScalar.constant(1),\r\n structuralShrinkVertical: InterpolatorScalar.constant(1),\r\n structuralStretchVertical: InterpolatorScalar.constant(1),\r\n structuralShrinkHorizontal: InterpolatorScalar.constant(0.5),\r\n structuralStretchHorizontal: InterpolatorScalar.constant(0.5),\r\n shearShrink: InterpolatorScalar.constant(0.5),\r\n shearStretch: InterpolatorScalar.constant(0.5),\r\n bendingShrinkVertical: InterpolatorScalar.constant(0.5),\r\n bendingStretchVertical: InterpolatorScalar.constant(0.5),\r\n bendingShrinkHorizontal: InterpolatorScalar.constant(0.5),\r\n bendingStretchHorizontal: InterpolatorScalar.constant(0.5),\r\n fakeWavePower: InterpolatorScalar.constant(0),\r\n fakeWaveFreq: InterpolatorScalar.constant(0)\r\n },\r\n constraintOptions: {\r\n structuralVertical: false,\r\n structuralHorizontal: false,\r\n shear: false,\r\n bendingVertical: false,\r\n bendingHorizontal: false,\r\n isLoop: false,\r\n collideStructuralVertical: false,\r\n collideStructuralHorizontal: false,\r\n collideShear: false,\r\n enableSurfaceCollision: false\r\n }\r\n };\r\n }\r\n}\r\n"],"names":["_quat","Quaternion","_defaultTA","createTransformAccess","SceneNode","obj","exposeNode","node","getWorldPosition","getWorldRotation","q","worldMatrix","decompose","getWorldScale","s","Vector3","getLocalPosition","position","clone","getLocalRotation","rotation","getLocalScale","scale","setWorldPosition","p","parent","invWorldMatrix","transformPointAffine","set","setWorldRotation","multiply","inverse","setLocalPosition","setLocalRotation","setLocalScale","JointDynamicsSystem","_controller","_chainConfig","_bindPose","config","colliders","grabbers","flatPlanes","systemRoot","chainConfig","chains","map","chain","start","end","WeakMap","rootPoints","boneNodes","boneToNode","Map","pointTransforms","nodeToBone","nodeToDepth","chainNodes","collectChainNodes","previous","i","length","boneNode","get","index","children","isFixed","depth","push","includes","rootIndex","indexOf","splice","orderedBoneNodes","visitedBoneNodes","Set","orderBoneNode","has","add","child","root","defaultConfig","getDefaultControllerConfig","controllerConfig","angleLimitConfig","curves","constraintOptions","JointDynamicsSystemController","initialize","controller","getColliderSnapshots","getFlatPlaneSnapshots","getGrabberSnapshots","resetChains","bindPose","addCollider","r","transform","addSphereCollider","radius","friction","inversed","forceType","ColliderForce","Off","height","isInverseCollider","radiusTailScale","addCapsuleCollider","setColliderEnabled","handle","enabled","removeCollider","removeColliderAt","addFlatPlane","up","setFlatPlaneEnabled","removeFlatPlane","removeFlatPlaneAt","addGrabber","setGrabberEnabled","removeGrabber","removeGrabberAt","isParentOf","Error","nodes","current","unshift","update","deltaTime","dt","Math","min","step","gravity","relaxation","subSteps","enableSurfaceCollision","windForce","zero","rootSlideLimit","rootRotateLimit","constraintShrinkLimit","blendRatio","stabilizationFrameRate","isFakeWave","fakeWaveSpeed","fakeWavePower","angleLimit","limitFromRoot","enableBroadPhase","preserveTwist","gravityScale","InterpolatorScalar","constant","windForceScale","massScale","resistance","hardness","pointRadius","sliderJointLength","allShrinkScale","allStretchScale","structuralShrinkVertical","structuralStretchVertical","structuralShrinkHorizontal","structuralStretchHorizontal","shearShrink","shearStretch","bendingShrinkVertical","bendingStretchVertical","bendingShrinkHorizontal","bendingStretchHorizontal","fakeWaveFreq","structuralVertical","structuralHorizontal","shear","bendingVertical","bendingHorizontal","isLoop","collideStructuralVertical","collideStructuralHorizontal","collideShear"],"mappings":"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"}
1
+ {"version":3,"file":"joint_dynamics_system.js","sources":["../../../src/animation/joint_dynamics/joint_dynamics_system.ts"],"sourcesContent":["import type { DeepPartial } from '@zephyr3d/base';\r\nimport { InterpolatorScalar, Vector3 } from '@zephyr3d/base';\r\nimport { Quaternion } from '@zephyr3d/base';\r\nimport { SceneNode } from '../../scene/scene_node';\r\nimport type {\r\n ControllerConfig,\r\n JointDynamicsColliderSnapshot,\r\n JointDynamicsColliderHandle,\r\n JointDynamicsFlatPlaneSnapshot,\r\n JointDynamicsFlatPlaneHandle,\r\n JointDynamicsGrabberSnapshot,\r\n JointDynamicsGrabberHandle\r\n} from './controller';\r\nimport { JointDynamicsSystemController } from './controller';\r\nimport { ColliderForce, type BoneNode, type ColliderR, type GrabberR, type TransformAccess } from './types';\r\nimport type { SkeletonBindPose } from '../skeleton';\r\n\r\nconst _quat = new Quaternion();\r\n\r\nconst _defaultTA = createTransformAccess(new SceneNode(null), false);\r\n\r\n/**\r\n * Create a transform adapter that lets the joint dynamics solver read from and write to a SceneNode.\r\n *\r\n * @param obj - Scene node to expose through the TransformAccess interface.\r\n * @returns A TransformAccess wrapper backed by the supplied scene node.\r\n *\r\n * @public\r\n */\r\nexport function createTransformAccess(obj: SceneNode, exposeNode = true): TransformAccess {\r\n return {\r\n ...(exposeNode ? { node: obj } : {}),\r\n getWorldPosition(): Vector3 {\r\n return obj.getWorldPosition();\r\n },\r\n getWorldRotation(): Quaternion {\r\n const q = new Quaternion();\r\n obj.worldMatrix.decompose(null, q, null);\r\n return q;\r\n },\r\n getWorldScale(): Vector3 {\r\n const s = new Vector3();\r\n obj.worldMatrix.decompose(s, null, null);\r\n return s;\r\n },\r\n getLocalPosition(): Vector3 {\r\n return obj.position.clone();\r\n },\r\n getLocalRotation(): Quaternion {\r\n return obj.rotation.clone();\r\n },\r\n getLocalScale(): Vector3 {\r\n return obj.scale.clone();\r\n },\r\n setWorldPosition(p: Vector3): void {\r\n if (obj.parent) {\r\n obj.position = obj.parent.invWorldMatrix.transformPointAffine(p);\r\n } else {\r\n obj.position.set(p);\r\n }\r\n },\r\n setWorldRotation(q: Quaternion): void {\r\n // Convert world rotation to local space.\r\n if (obj.parent) {\r\n obj.parent.worldMatrix.decompose(null, _quat, null);\r\n Quaternion.multiply(Quaternion.inverse(_quat), q, obj.rotation);\r\n } else {\r\n obj.rotation.set(q);\r\n }\r\n },\r\n setLocalPosition(p: Vector3): void {\r\n obj.position.set(p);\r\n },\r\n setLocalRotation(q: Quaternion): void {\r\n obj.rotation.set(q);\r\n },\r\n setLocalScale(s: Vector3): void {\r\n obj.scale.set(s);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Describes the bone chains simulated by a JointDynamicsSystem.\r\n *\r\n * Each chain is defined by an inclusive start and end node. The end node must be\r\n * a descendant of the start node.\r\n *\r\n * @public\r\n */\r\nexport type JointChainConfig = {\r\n /** Root transform used for root motion compensation. */\r\n systemRoot: SceneNode;\r\n /** Bone chains to simulate. */\r\n chains: { start: SceneNode; end: SceneNode }[];\r\n};\r\n\r\n/**\r\n * Configuration used to construct a JointDynamicsSystem.\r\n *\r\n * @public\r\n */\r\nexport type JointDynamicSystemConfig = {\r\n /** Bone chain topology and root transform. */\r\n chainConfig: JointChainConfig;\r\n /** Optional controller configuration overrides. */\r\n controllerConfig?: DeepPartial<ControllerConfig, 2>;\r\n};\r\n\r\n/**\r\n * Physics system for spring-like joint dynamics on scene node bone chains.\r\n *\r\n * The system builds particles and constraints from one or more bone chains,\r\n * advances them with Verlet integration, solves constraints and collisions, and\r\n * writes the resulting positions and rotations back to the scene graph.\r\n *\r\n * @public\r\n */\r\nexport class JointDynamicsSystem {\r\n private _controller: JointDynamicsSystemController;\r\n private _chainConfig: JointChainConfig;\r\n private _bindPose: WeakMap<SceneNode, SkeletonBindPose>;\r\n /**\r\n * Create a joint dynamics system for one or more bone chains.\r\n *\r\n * @param config - Bone chain topology and controller configuration.\r\n * @param colliders - Optional colliders to register during initialization.\r\n * @param grabbers - Optional grabbers to register during initialization.\r\n * @param flatPlanes - Optional world-space planes that dynamic points cannot cross.\r\n */\r\n constructor(\r\n config: JointDynamicSystemConfig,\r\n colliders: { r: ColliderR; transform: TransformAccess }[] = [],\r\n grabbers: {\r\n r: GrabberR;\r\n transform: TransformAccess;\r\n enabled: boolean;\r\n }[] = [],\r\n flatPlanes: { up: Vector3; position: Vector3 }[] = []\r\n ) {\r\n this._chainConfig = {\r\n systemRoot: config.chainConfig.systemRoot,\r\n chains: config.chainConfig.chains.map((chain) => ({ start: chain.start, end: chain.end }))\r\n };\r\n this._bindPose = new WeakMap();\r\n const rootPoints: BoneNode[] = [];\r\n const boneNodes: BoneNode[] = [];\r\n const boneToNode = new Map<BoneNode, SceneNode>();\r\n const pointTransforms: TransformAccess[] = [];\r\n const nodeToBone = new Map<SceneNode, BoneNode>();\r\n const nodeToDepth = new Map<SceneNode, number>();\r\n for (const chain of config.chainConfig.chains) {\r\n const chainNodes = this.collectChainNodes(chain.start, chain.end);\r\n let previous: BoneNode | null = null;\r\n for (let i = 0; i < chainNodes.length; i++) {\r\n const node = chainNodes[i];\r\n let boneNode = nodeToBone.get(node);\r\n if (!boneNode) {\r\n this._bindPose.set(node, {\r\n position: node.position.clone(),\r\n rotation: node.rotation.clone(),\r\n scale: node.scale.clone()\r\n });\r\n boneNode = {\r\n index: boneNodes.length,\r\n position: node.getWorldPosition(),\r\n children: [],\r\n isFixed: i === 0,\r\n depth: i\r\n };\r\n nodeToBone.set(node, boneNode);\r\n nodeToDepth.set(node, i);\r\n boneNodes.push(boneNode);\r\n boneToNode.set(boneNode, node);\r\n } else {\r\n const depth = nodeToDepth.get(node) ?? boneNode.depth;\r\n if (i < depth) {\r\n boneNode.depth = i;\r\n nodeToDepth.set(node, i);\r\n }\r\n boneNode.isFixed = boneNode.isFixed || i === 0;\r\n }\r\n if (previous && !previous.children.includes(boneNode)) {\r\n previous.children.push(boneNode);\r\n const rootIndex = rootPoints.indexOf(boneNode);\r\n if (rootIndex !== -1) {\r\n rootPoints.splice(rootIndex, 1);\r\n }\r\n } else if (!previous && !rootPoints.includes(boneNode)) {\r\n rootPoints.push(boneNode);\r\n }\r\n previous = boneNode;\r\n }\r\n }\r\n const orderedBoneNodes: BoneNode[] = [];\r\n const visitedBoneNodes = new Set<BoneNode>();\r\n const orderBoneNode = (boneNode: BoneNode) => {\r\n if (visitedBoneNodes.has(boneNode)) {\r\n return;\r\n }\r\n visitedBoneNodes.add(boneNode);\r\n boneNode.index = orderedBoneNodes.length;\r\n orderedBoneNodes.push(boneNode);\r\n for (const child of boneNode.children) {\r\n orderBoneNode(child);\r\n }\r\n };\r\n for (const root of rootPoints) {\r\n orderBoneNode(root);\r\n }\r\n boneNodes.length = 0;\r\n boneNodes.push(...orderedBoneNodes);\r\n pointTransforms.push(...boneNodes.map((boneNode) => createTransformAccess(boneToNode.get(boneNode)!)));\r\n const systemRoot = createTransformAccess(config.chainConfig.systemRoot);\r\n const defaultConfig = this.getDefaultControllerConfig();\r\n const controllerConfig: ControllerConfig = {\r\n ...defaultConfig,\r\n ...config?.controllerConfig,\r\n angleLimitConfig: { ...defaultConfig.angleLimitConfig, ...config?.controllerConfig?.angleLimitConfig },\r\n curves: { ...defaultConfig.curves, ...config?.controllerConfig?.curves },\r\n constraintOptions: {\r\n ...defaultConfig.constraintOptions,\r\n ...config?.controllerConfig?.constraintOptions\r\n }\r\n };\r\n this._controller = new JointDynamicsSystemController(controllerConfig);\r\n this._controller.initialize(systemRoot, rootPoints, pointTransforms, colliders, grabbers, flatPlanes);\r\n }\r\n\r\n /**\r\n * Get the low-level controller that owns simulation state and advanced runtime controls.\r\n *\r\n * Most callers should prefer the convenience methods on JointDynamicsSystem.\r\n *\r\n * @returns The underlying joint dynamics controller.\r\n */\r\n get controller(): JointDynamicsSystemController {\r\n return this._controller;\r\n }\r\n\r\n /**\r\n * Get the node chain topology used to construct this system.\r\n */\r\n get chainConfig(): JointChainConfig {\r\n return {\r\n systemRoot: this._chainConfig.systemRoot,\r\n chains: this._chainConfig.chains.map((chain) => ({ start: chain.start, end: chain.end }))\r\n };\r\n }\r\n\r\n /**\r\n * Returns detached collider snapshots for serialization.\r\n */\r\n getColliderSnapshots(): JointDynamicsColliderSnapshot[] {\r\n return this._controller.getColliderSnapshots();\r\n }\r\n\r\n /**\r\n * Returns detached flat-plane snapshots for serialization.\r\n */\r\n getFlatPlaneSnapshots(): JointDynamicsFlatPlaneSnapshot[] {\r\n return this._controller.getFlatPlaneSnapshots();\r\n }\r\n\r\n /**\r\n * Returns detached grabber snapshots for serialization.\r\n */\r\n getGrabberSnapshots(): JointDynamicsGrabberSnapshot[] {\r\n return this._controller.getGrabberSnapshots();\r\n }\r\n\r\n /**\r\n * Reset chain nodes to bind pose\r\n */\r\n resetChains() {\r\n for (const chain of this._chainConfig.chains) {\r\n const chainNodes = this.collectChainNodes(chain.start, chain.end);\r\n for (const node of chainNodes) {\r\n const bindPose = this._bindPose.get(node);\r\n if (bindPose) {\r\n node.position = bindPose.position;\r\n node.rotation = bindPose.rotation;\r\n node.scale = bindPose.scale;\r\n }\r\n }\r\n }\r\n }\r\n /**\r\n * Add a fully configured collider at runtime.\r\n *\r\n * The collider transform is read from the supplied scene node every simula ; ion step.\r\n * If no transform is supplied, the collider is created at the identity transform.\r\n *\r\n * @param r - Read-only collider parameters.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addCollider(r: ColliderR, transform?: SceneNode): JointDynamicsColliderHandle {\r\n return this._controller.addCollider(r, transform ? createTransformAccess(transform) : _defaultTA);\r\n }\r\n\r\n /**\r\n * Add a spherical collider at runtime.\r\n *\r\n * The collider transform is read from the supplied scene node every simulation step.\r\n * If no transform is supplied, the collider is created at the identity transform.\r\n *\r\n * @param radius - Sphere radius in world units before transform scaling.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @param friction - Contact friction coefficient applied by this collider. Defaults to 0.\r\n * @param inversed - If true, points are constrained inside the sphere instead of pushed out.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addSphereCollider(\r\n radius: number,\r\n transform?: SceneNode,\r\n friction?: number,\r\n inversed?: boolean\r\n ): JointDynamicsColliderHandle {\r\n return this.addCollider(\r\n {\r\n forceType: ColliderForce.Off,\r\n friction: friction ?? 0,\r\n height: 0,\r\n isInverseCollider: inversed ?? false,\r\n radius,\r\n radiusTailScale: 1\r\n },\r\n transform\r\n );\r\n }\r\n\r\n /**\r\n * Add a capsule collider at runtime.\r\n *\r\n * The capsule is aligned to the collider transform's local Y axis. Its head radius is\r\n * `radius`, its tail radius is `radius * radiusTailScale`, and `height` defines the\r\n * distance between the capsule ends before transform scaling.\r\n *\r\n * @param radius - Capsule head radius in world units before transform scaling.\r\n * @param height - Capsule length in world units before transform scaling.\r\n * @param transform - Optional scene node that drives the collider transform.\r\n * @param radiusTailScale - Tail radius multiplier relative to the head radius. Defaults to 1.\r\n * @param friction - Contact friction coefficient applied by this collider. Defaults to 0.\r\n * @param inversed - If true, points are constrained inside the capsule instead of pushed out.\r\n * @returns A stable handle that remains valid until this collider is removed.\r\n */\r\n addCapsuleCollider(\r\n radius: number,\r\n height: number,\r\n transform?: SceneNode,\r\n radiusTailScale?: number,\r\n friction?: number,\r\n inversed?: boolean\r\n ): JointDynamicsColliderHandle {\r\n return this.addCollider(\r\n {\r\n forceType: ColliderForce.Off,\r\n friction: friction ?? 0,\r\n height,\r\n isInverseCollider: inversed ?? false,\r\n radius,\r\n radiusTailScale: radiusTailScale ?? 1\r\n },\r\n transform\r\n );\r\n }\r\n\r\n /**\r\n * Enable or disable a collider by stable handle.\r\n *\r\n * Disabled colliders remain registered but are ignored by simulation until re-enabled.\r\n *\r\n * @param handle - Collider handle returned by addCollider, addSphereCollider, or addCapsuleCollider.\r\n * @param enabled - Whether the collider should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setColliderEnabled(handle: JointDynamicsColliderHandle, enabled: boolean): boolean {\r\n return this._controller.setColliderEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a collider by stable handle.\r\n *\r\n * @param handle - Collider handle returned by addCollider, addSphereCollider, or addCapsuleCollider.\r\n * @returns true if the collider existed and was removed.\r\n */\r\n removeCollider(handle: JointDynamicsColliderHandle): boolean {\r\n return this._controller.removeCollider(handle);\r\n }\r\n\r\n /**\r\n * Remove a collider by current array index.\r\n *\r\n * Prefer removeCollider(handle) for runtime-owned colliders.\r\n *\r\n * @param index - Current collider array index.\r\n * @returns true if the collider existed and was removed.\r\n */\r\n removeColliderAt(index: number): boolean {\r\n return this._controller.removeColliderAt(index);\r\n }\r\n\r\n /**\r\n * Add a flat plane collider at runtime.\r\n *\r\n * Flat planes are infinite world-space planes. The normal points toward the allowed side,\r\n * and dynamic points are pushed back when they move behind the plane.\r\n *\r\n * @param up - Plane normal in world space.\r\n * @param position - A point on the plane in world space.\r\n * @returns A stable handle that remains valid until this flat plane is removed.\r\n */\r\n addFlatPlane(up: Vector3, position: Vector3): JointDynamicsFlatPlaneHandle {\r\n return this._controller.addFlatPlane(up, position);\r\n }\r\n\r\n /**\r\n * Enable or disable a flat plane by stable handle.\r\n *\r\n * Disabled flat planes remain registered but are ignored by simulation until re-enabled.\r\n *\r\n * @param handle - Flat plane handle returned by addFlatPlane.\r\n * @param enabled - Whether the flat plane should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setFlatPlaneEnabled(handle: JointDynamicsFlatPlaneHandle, enabled: boolean): boolean {\r\n return this._controller.setFlatPlaneEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a flat plane by stable handle.\r\n *\r\n * @param handle - Flat plane handle returned by addFlatPlane.\r\n * @returns true if the flat plane existed and was removed.\r\n */\r\n removeFlatPlane(handle: JointDynamicsFlatPlaneHandle): boolean {\r\n return this._controller.removeFlatPlane(handle);\r\n }\r\n\r\n /**\r\n * Remove a flat plane by current array index.\r\n * Prefer removeFlatPlane(handle) for runtime-owned flat planes.\r\n *\r\n * @param index - Current flat plane array index.\r\n * @returns true if the flat plane existed and was removed.\r\n */\r\n removeFlatPlaneAt(index: number): boolean {\r\n return this._controller.removeFlatPlaneAt(index);\r\n }\r\n\r\n /**\r\n * Add a grabber at runtime.\r\n *\r\n * The grabber transform is read from the supplied scene node every simulation step.\r\n * If no transform is supplied, the grabber is created at the identity transform.\r\n *\r\n * @param r - Read-only grabber parameters.\r\n * @param transform - Optional scene node that drives the grabber transform.\r\n * @returns A stable handle that remains valid until this grabber is removed.\r\n */\r\n addGrabber(r: GrabberR, transform?: SceneNode): JointDynamicsGrabberHandle {\r\n return this._controller.addGrabber(r, transform ? createTransformAccess(transform) : _defaultTA, false);\r\n }\r\n\r\n /**\r\n * Enable or disable a grabber by stable handle.\r\n *\r\n * Disabling a grabber also releases any points currently held by it.\r\n *\r\n * @param handle - Grabber handle returned by addGrabber.\r\n * @param enabled - Whether the grabber should participate in simulation.\r\n * @returns true if the handle is valid and the enabled state was updated.\r\n */\r\n setGrabberEnabled(handle: JointDynamicsGrabberHandle, enabled: boolean): boolean {\r\n return this._controller.setGrabberEnabled(handle, enabled);\r\n }\r\n\r\n /**\r\n * Remove a grabber by stable handle.\r\n *\r\n * @param handle - Grabber handle returned by addGrabber.\r\n * @returns true if the grabber existed and was removed.\r\n */\r\n removeGrabber(handle: JointDynamicsGrabberHandle): boolean {\r\n return this._controller.removeGrabber(handle);\r\n }\r\n\r\n /**\r\n * Remove a grabber by current array index.\r\n *\r\n * Prefer removeGrabber(handle) for runtime-owned grabbers.\r\n *\r\n * @param index - Current grabber array index.\r\n * @returns true if the grabber existed and was removed.\r\n */\r\n removeGrabberAt(index: number): boolean {\r\n return this._controller.removeGrabberAt(index);\r\n }\r\n\r\n private collectChainNodes(start: SceneNode, end: SceneNode): SceneNode[] {\r\n if (!start.isParentOf(end)) {\r\n throw new Error('Invalid chain: end node must be a descendant of start node');\r\n }\r\n const nodes: SceneNode[] = [];\r\n let current: SceneNode = end;\r\n for (;;) {\r\n nodes.unshift(current);\r\n if (current === start) {\r\n break;\r\n }\r\n current = current.parent!;\r\n }\r\n return nodes;\r\n }\r\n /**\r\n * Advance the physics simulation and write the resulting transforms back to the chain nodes.\r\n *\r\n * @param deltaTime - Frame time step in seconds. Values larger than 0.033 are clamped for stability.\r\n */\r\n update(deltaTime: number): void {\r\n const dt = Math.min(deltaTime, 0.033); // Max 30 FPS\r\n this._controller.step(dt);\r\n }\r\n /** @internal */\r\n private getDefaultControllerConfig(): ControllerConfig {\r\n return {\r\n gravity: new Vector3(0, -9.8, 0),\r\n relaxation: 3,\r\n subSteps: 3,\r\n enableSurfaceCollision: false,\r\n windForce: Vector3.zero(),\r\n rootSlideLimit: -1,\r\n rootRotateLimit: -1,\r\n constraintShrinkLimit: 1,\r\n blendRatio: 0,\r\n stabilizationFrameRate: 60,\r\n isFakeWave: false,\r\n fakeWaveSpeed: 0,\r\n fakeWavePower: 0,\r\n angleLimitConfig: { angleLimit: -1, limitFromRoot: false },\r\n enableBroadPhase: false,\r\n preserveTwist: true,\r\n curves: {\r\n gravityScale: InterpolatorScalar.constant(1),\r\n windForceScale: InterpolatorScalar.constant(1),\r\n massScale: InterpolatorScalar.constant(1),\r\n resistance: InterpolatorScalar.constant(0.95),\r\n hardness: InterpolatorScalar.constant(0.001),\r\n friction: InterpolatorScalar.constant(0.5),\r\n pointRadius: InterpolatorScalar.constant(0.05),\r\n sliderJointLength: InterpolatorScalar.constant(0),\r\n allShrinkScale: InterpolatorScalar.constant(1),\r\n allStretchScale: InterpolatorScalar.constant(1),\r\n structuralShrinkVertical: InterpolatorScalar.constant(1),\r\n structuralStretchVertical: InterpolatorScalar.constant(1),\r\n structuralShrinkHorizontal: InterpolatorScalar.constant(0.5),\r\n structuralStretchHorizontal: InterpolatorScalar.constant(0.5),\r\n shearShrink: InterpolatorScalar.constant(0.5),\r\n shearStretch: InterpolatorScalar.constant(0.5),\r\n bendingShrinkVertical: InterpolatorScalar.constant(0.5),\r\n bendingStretchVertical: InterpolatorScalar.constant(0.5),\r\n bendingShrinkHorizontal: InterpolatorScalar.constant(0.5),\r\n bendingStretchHorizontal: InterpolatorScalar.constant(0.5),\r\n fakeWavePower: InterpolatorScalar.constant(0),\r\n fakeWaveFreq: InterpolatorScalar.constant(0)\r\n },\r\n constraintOptions: {\r\n structuralVertical: false,\r\n structuralHorizontal: false,\r\n shear: false,\r\n bendingVertical: false,\r\n bendingHorizontal: false,\r\n isLoop: false,\r\n collideStructuralVertical: false,\r\n collideStructuralHorizontal: false,\r\n collideShear: false,\r\n enableSurfaceCollision: false\r\n }\r\n };\r\n }\r\n}\r\n"],"names":["_quat","Quaternion","_defaultTA","createTransformAccess","SceneNode","obj","exposeNode","node","getWorldPosition","getWorldRotation","q","worldMatrix","decompose","getWorldScale","s","Vector3","getLocalPosition","position","clone","getLocalRotation","rotation","getLocalScale","scale","setWorldPosition","p","parent","invWorldMatrix","transformPointAffine","set","setWorldRotation","multiply","inverse","setLocalPosition","setLocalRotation","setLocalScale","JointDynamicsSystem","_controller","_chainConfig","_bindPose","config","colliders","grabbers","flatPlanes","systemRoot","chainConfig","chains","map","chain","start","end","WeakMap","rootPoints","boneNodes","boneToNode","Map","pointTransforms","nodeToBone","nodeToDepth","chainNodes","collectChainNodes","previous","i","length","boneNode","get","index","children","isFixed","depth","push","includes","rootIndex","indexOf","splice","orderedBoneNodes","visitedBoneNodes","Set","orderBoneNode","has","add","child","root","defaultConfig","getDefaultControllerConfig","controllerConfig","angleLimitConfig","curves","constraintOptions","JointDynamicsSystemController","initialize","controller","getColliderSnapshots","getFlatPlaneSnapshots","getGrabberSnapshots","resetChains","bindPose","addCollider","r","transform","addSphereCollider","radius","friction","inversed","forceType","ColliderForce","Off","height","isInverseCollider","radiusTailScale","addCapsuleCollider","setColliderEnabled","handle","enabled","removeCollider","removeColliderAt","addFlatPlane","up","setFlatPlaneEnabled","removeFlatPlane","removeFlatPlaneAt","addGrabber","setGrabberEnabled","removeGrabber","removeGrabberAt","isParentOf","Error","nodes","current","unshift","update","deltaTime","dt","Math","min","step","gravity","relaxation","subSteps","enableSurfaceCollision","windForce","zero","rootSlideLimit","rootRotateLimit","constraintShrinkLimit","blendRatio","stabilizationFrameRate","isFakeWave","fakeWaveSpeed","fakeWavePower","angleLimit","limitFromRoot","enableBroadPhase","preserveTwist","gravityScale","InterpolatorScalar","constant","windForceScale","massScale","resistance","hardness","pointRadius","sliderJointLength","allShrinkScale","allStretchScale","structuralShrinkVertical","structuralStretchVertical","structuralShrinkHorizontal","structuralStretchHorizontal","shearShrink","shearStretch","bendingShrinkVertical","bendingStretchVertical","bendingShrinkHorizontal","bendingStretchHorizontal","fakeWaveFreq","structuralVertical","structuralHorizontal","shear","bendingVertical","bendingHorizontal","isLoop","collideStructuralVertical","collideStructuralHorizontal","collideShear"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { Vector3, Quaternion, degree2radian, clamp01, smoothStep, Matrix4x4, rad
2
2
  import { EPSILON, ConstraintType } from './types.js';
3
3
  import { pushoutFromSphere, pushoutFromCapsule, checkSurfaceCollision, pushInFromCapsule, pushInFromSphere, collisionDetection } from './collision.js';
4
4
 
5
- // Core physics simulation - direct port of JobExecuteSimulation from SPCRJointDynamicsJob.cs
5
+ // Core simulation ported from JobExecuteSimulation in SPCRJointDynamicsJob.cs.
6
6
  const AXIS_Y = new Vector3(0, 1, 0);
7
7
  const VEC3_ONE = new Vector3(1, 1, 1);
8
8
  const _computeCapsuleAxis = new Vector3();
@@ -26,14 +26,12 @@ const _broadPhaseDelta = new Vector3();
26
26
  subSteps = 1;
27
27
  }
28
28
  let fakeWaveFreq = params.fakeWaveCounter;
29
- // Root slide offset
30
29
  let rootSlideOffset = Vector3.zero();
31
30
  const rootDeltaSlide = Vector3.sub(params.rootPosition, params.previousRootPosition);
32
31
  const rootDeltaSlideLen = rootDeltaSlide.magnitude;
33
32
  if (params.rootSlideLimit >= 0 && rootDeltaSlideLen > params.rootSlideLimit) {
34
33
  rootSlideOffset = Vector3.scale(rootDeltaSlide, (1.0 - params.rootSlideLimit / rootDeltaSlideLen) / subSteps);
35
34
  }
36
- // Root rotation offset
37
35
  let rootRotationOffset = Quaternion.identity();
38
36
  const rootDeltaRot = Quaternion.multiply(params.rootRotation, Quaternion.inverse(params.previousRootRotation));
39
37
  let rotateAngle = Math.acos(Math.max(-1, Math.min(1, rootDeltaRot.w))) * 2.0 * (180 / Math.PI);
@@ -41,7 +39,7 @@ const _broadPhaseDelta = new Vector3();
41
39
  rotateAngle -= 360;
42
40
  }
43
41
  if (params.rootRotateLimit >= 0 && Math.abs(rotateAngle) > params.rootRotateLimit) {
44
- // Extract the rotation axis from the delta quaternion
42
+ // Extract the rotation axis from the delta quaternion.
45
43
  const sinHalf = Math.sqrt(Math.max(0, 1 - rootDeltaRot.w * rootDeltaRot.w));
46
44
  let rotateAxis;
47
45
  if (sinHalf > 0.0001) {
@@ -68,24 +66,12 @@ const _broadPhaseDelta = new Vector3();
68
66
  if (params.enableSurfaceCollision) {
69
67
  surfaceCollision(pointsRW, collidersR, collidersRW, params.surfaceConstraints);
70
68
  }
71
- // Push fixed points out of colliders before constraint solving.
72
- // Fixed points follow animation and cannot be moved by the solver, but if
73
- // their animated position is inside a collider, the distance constraint will
74
- // pull free children inward through the surface �?causing the characteristic
75
- // "hair flipping outward" artifact at the back of the head.
76
- // By temporarily clamping fixed-point positionCurrent to the collider surface
77
- // before each substep's constraint pass, we ensure constraints operate from
78
- // a geometrically valid anchor. The original animated position is restored
79
- // at the start of the next substep via positionCurrentTransform.
69
+ // Clamp animated fixed points before solving to avoid pulling children through colliders.
80
70
  fixedPointColliderPushout(pointsR, pointsRW, collidersR, collidersRW);
81
71
  for(let iRelax = params.relaxation - 1; iRelax >= 0; --iRelax){
82
72
  constraintUpdate(pointsR, pointsRW, constraints, collidersR, collidersRW, params.constraintShrinkLimit, params.enableBroadPhase);
83
73
  }
84
- // After all constraint/collision iterations are done, cancel any residual
85
- // normal velocity that would push points back into colliders next frame.
86
- // We compare the final positionCurrent (guaranteed outside all colliders)
87
- // against positionPrevious (the Verlet integration start point) and zero
88
- // out the component pointing into each collider.
74
+ // Remove inward normal velocity left by collision resolution.
89
75
  postCollisionVelocityFix(pointsR, pointsRW, collidersR, collidersRW);
90
76
  }
91
77
  pointUpdatePass2(pointsR, pointsRW, positionsToTransform, stepDelta, fakeWaveFreq, params.blendRatio, params.isFakeWave, params.fakeWavePower);
@@ -110,8 +96,7 @@ function colliderUpdate(collidersR, collidersRW, stepDelta) {
110
96
  for(let i = 0; i < collidersR.length; i++){
111
97
  const colR = collidersR[i];
112
98
  const colRW = collidersRW[i];
113
- // Scale radius by the uniform world scale of the collider node.
114
- // Use the average of x/y/z components to handle non-uniform scale gracefully.
99
+ // Approximate non-uniform scale with its component average.
115
100
  const ws = colRW.worldScale;
116
101
  const worldScaleUniform = (ws.x + ws.y + ws.z) / 3;
117
102
  colRW.radius = colR.radius * worldScaleUniform;
@@ -127,7 +112,6 @@ function colliderUpdate(collidersR, collidersRW, stepDelta) {
127
112
  colRW.boundsCenter.set(colRW.positionCurrent);
128
113
  colRW.boundsRadius = colRW.radius;
129
114
  }
130
- // Update local bounds
131
115
  Vector3.scale(VEC3_ONE, colR.radius, corner);
132
116
  colRW.worldToLocal.transformPointAffine(colRW.positionCurrent, center);
133
117
  Vector3.sub(center, corner, colRW.localBoundsMin);
@@ -164,7 +148,6 @@ function segmentMayCollideBroadPhase(point1, point2, colRW) {
164
148
  const delta = Vector3.sub(colRW.boundsCenter, closestPoint, _broadPhaseDelta);
165
149
  return delta.magnitudeSq <= colRW.boundsRadius * colRW.boundsRadius;
166
150
  }
167
- // Core physics simulation - direct port of JobExecuteSimulation from SPCRJointDynamicsJob.cs
168
151
  function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSlideOffset, rootRotationOffset, rootPosition, windForce, isPaused, grabbersR, grabbersRW, movableLimitTargets, flatPlanes, collidersR, collidersRW) {
169
152
  const currentTransformPos = new Vector3();
170
153
  const moveDir = new Vector3();
@@ -190,10 +173,7 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
190
173
  Vector3.scale(windForce, ptR.windForceScale / ptR.mass, extForce);
191
174
  Vector3.add(ptR.gravity, extForce, extForce);
192
175
  Vector3.scale(extForce, stepTime_x2_half, extForce);
193
- // Clamp the per-step force displacement to half the bone's rest length.
194
- // Without this, large gravity values (e.g. -50 in world space) produce a
195
- // per-step displacement comparable to the bone spacing, which exceeds what
196
- // the constraint relaxation can correct in one pass and causes surface jitter.
176
+ // Limit force displacement to keep constraint relaxation stable.
197
177
  if (ptR.parentLength > EPSILON) {
198
178
  const maxForceDisp = ptR.parentLength * 0.5;
199
179
  const forceDispSq = extForce.magnitudeSq;
@@ -201,16 +181,10 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
201
181
  Vector3.scale(extForce, maxForceDisp / Math.sqrt(forceDispSq), extForce);
202
182
  }
203
183
  }
204
- // Apply resistance (damping) only to the velocity term, not to external forces.
205
- // Applying resistance to gravity would incorrectly attenuate acceleration each frame,
206
- // causing energy errors and instability under high gravity.
184
+ // Damping applies to velocity, not external forces.
207
185
  Vector3.scale(moveDir, ptR.resistance, moveDir);
208
186
  Vector3.scale(moveDir, 1.0 - clamp01(ptRW.friction * ptR.frictionScale), moveDir);
209
- // Clamp per-step velocity to a multiple of bone rest length.
210
- // During fast root rotations the Verlet velocity can become very large,
211
- // overwhelming the constraint solver and causing the hair to lose shape.
212
- // Limiting velocity keeps the simulation stable regardless of how fast
213
- // the root moves, while still allowing natural large-amplitude swings.
187
+ // Limit velocity so fast root motion cannot destabilize constraints.
214
188
  if (ptR.parentLength > EPSILON) {
215
189
  const maxVelDisp = ptR.parentLength * 2.0;
216
190
  const velDispSq = moveDir.magnitudeSq;
@@ -224,19 +198,15 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
224
198
  Vector3.add(ptRW.positionCurrent, displacement, ptRW.positionCurrent);
225
199
  ptRW.friction = 0;
226
200
  if (!isPaused) {
227
- // Hardness restore
228
201
  if (ptR.hardness > 0) {
229
202
  Vector3.sub(currentTransformPos, ptRW.positionCurrent, restore);
230
203
  Vector3.scale(restore, ptR.hardness, restore);
231
204
  Vector3.add(ptRW.positionCurrent, restore, ptRW.positionCurrent);
232
205
  }
233
- // Force fade ratio
234
206
  if (ptR.forceFadeRatio > 0) {
235
207
  Vector3.lerp(ptRW.positionCurrent, currentTransformPos, ptR.forceFadeRatio, ptRW.positionCurrent);
236
208
  }
237
- // Push out of colliders immediately after hardness/fade pulls the point
238
- // toward the animated position (which may be inside a collider).
239
- // This prevents the hardness↔collision tug-of-war that causes jitter.
209
+ // Reapply collision after hardness/fade to avoid interpenetration jitter.
240
210
  for(let ci = 0; ci < collidersR.length; ci++){
241
211
  const colRci = collidersR[ci];
242
212
  const colRWci = collidersRW[ci];
@@ -248,7 +218,6 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
248
218
  ptRW.positionCurrent.set(hRes.point);
249
219
  }
250
220
  }
251
- // Grabber
252
221
  if (ptRW.grabberIndex !== -1) {
253
222
  const grR = grabbersR[ptRW.grabberIndex];
254
223
  const grRW = grabbersRW[ptRW.grabberIndex];
@@ -281,7 +250,6 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
281
250
  ptRW.grabberDistance = Math.sqrt(sqrNearRange) / 2.0;
282
251
  }
283
252
  }
284
- // Movable limit
285
253
  if (ptR.movableLimitIndex !== -1) {
286
254
  const target = movableLimitTargets[ptR.movableLimitIndex];
287
255
  const move = Vector3.sub(ptRW.positionCurrent, target, tempVec0);
@@ -292,7 +260,6 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
292
260
  }
293
261
  }
294
262
  }
295
- // Flat plane collision
296
263
  for(let i = 0; i < flatPlanes.length; i++){
297
264
  const fp = flatPlanes[i];
298
265
  const dist = Vector3.dot(fp.normal, ptRW.positionCurrent) + fp.distance;
@@ -305,7 +272,6 @@ function pointUpdatePass1(pointsR, pointsRW, stepDelta, stepTime_x2_half, rootSl
305
272
  }
306
273
  }
307
274
  }
308
- // Core physics simulation - direct port of JobExecuteSimulation from SPCRJointDynamicsJob.cs
309
275
  function surfaceCollision(pointsRW, collidersR, collidersRW, surfaceConstraints) {
310
276
  const surfaceResult = {
311
277
  hit: false,
@@ -536,7 +502,6 @@ function constraintUpdate(pointsR, pointsRW, constraints, collidersR, collidersR
536
502
  Vector3.scale(disp, weightB / wAB, scaledDisp);
537
503
  Vector3.sub(rwB.positionCurrent, scaledDisp, rwB.positionCurrent);
538
504
  }
539
- // Per-constraint collision
540
505
  if (c.isCollision !== 0) {
541
506
  let friction = 0;
542
507
  for(let i = 0; i < collidersR.length; i++){
@@ -616,7 +581,6 @@ function constraintUpdate(pointsR, pointsRW, constraints, collidersR, collidersR
616
581
  }
617
582
  }
618
583
  }
619
- // Line segment collision
620
584
  if (!colR.isInverseCollider && canLine) {
621
585
  const lineRes = collisionDetection(colR, colRW, rwA.positionCurrent, rwB.positionCurrent, lineResult);
622
586
  if (lineRes.hit) {
@@ -661,7 +625,6 @@ function pointUpdatePass2(pointsR, pointsRW, positionsToTransform, stepDelta, fa
661
625
  const A = pointsRW[ptR.parent].positionToTransform;
662
626
  const B = ptRW.positionToTransform;
663
627
  const mAxis = Matrix4x4.lookAt(A, B, AXIS_Y);
664
- // Column 1 = up axis of the look-at matrix
665
628
  const col1 = mAxis.getCol(1).xyz();
666
629
  Vector3.lerp(ptRW.fakeWindDirection, col1, 0.5, ptRW.fakeWindDirection);
667
630
  freq += ptR.fakeWaveFreq;
@@ -726,8 +689,7 @@ function getPointParentWorldRotation(index, ptR, results, transformRotations, tr
726
689
  * Computes transform outputs from the simulated point positions.
727
690
  *
728
691
  * @public
729
- */ function applyResult(pointsR, pointsRW, positionsToTransform, blendRatio, // Current transform rotations (world and local) read from engine
730
- transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations) {
692
+ */ function applyResult(pointsR, pointsRW, positionsToTransform, blendRatio, transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations) {
731
693
  const results = new Array(pointsR.length);
732
694
  for(let index = 0; index < pointsR.length; index++){
733
695
  const ptR = pointsR[index];
@@ -735,7 +697,6 @@ transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations
735
697
  let worldRot = transformRotations[index];
736
698
  let localRot = transformLocalRotations[index];
737
699
  if (ptR.weight >= EPSILON) {
738
- // Dynamic point
739
700
  if (ptR.parent !== -1) {
740
701
  const direction = Vector3.sub(ptRW.positionToTransform, positionsToTransform[ptR.parent]);
741
702
  const realLen = direction.magnitude;
@@ -746,16 +707,11 @@ transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations
746
707
  }
747
708
  }
748
709
  const pos = ptRW.positionToTransform;
749
- // SetRotation with blendRatio=0 for dynamic points
750
- // Step 1: Reset localRotation to initialLocalRotation (blendRatio = 0 means fully initial)
751
710
  localRot = ptR.initialLocalRotation.clone();
752
- // Step 2: Recompute worldRot from the new localRot
753
- // In C#, setting localRotation immediately updates the world rotation.
754
- // worldRot = parentWorldRot * localRot
755
- // We approximate: the parent's current world rotation is in transformRotations[ptR.parent]
711
+ // Recompute world rotation from the parent and initial local rotation.
756
712
  const parentRot = getPointParentWorldRotation(index, ptR, results, transformRotations, transformLocalRotations, sceneParentRotations);
757
713
  worldRot = Quaternion.multiply(parentRot, localRot);
758
- // Step 3: Aim toward child (simple shortest-arc, no twist correction here)
714
+ // Aim toward the child with a shortest-arc rotation.
759
715
  if (ptR.child !== -1) {
760
716
  const childDir = Vector3.sub(positionsToTransform[ptR.child], ptRW.positionToTransform);
761
717
  if (childDir.magnitudeSq > EPSILON) {
@@ -773,12 +729,10 @@ transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations
773
729
  } else {
774
730
  const childBlend = ptR.child !== -1 ? Math.max(pointsR[ptR.child].forceFadeRatio, blendRatio) : blendRatio;
775
731
  // Use the caller-provided local rotation as the fixed-joint baseline.
776
- // The controller sanitizes this value when the transform still contains
777
- // the previous physics output instead of a fresh animation pose.
778
732
  const parentRot = getPointParentWorldRotation(index, ptR, results, transformRotations, transformLocalRotations, sceneParentRotations);
779
733
  localRot = transformLocalRotations[index].clone();
780
734
  worldRot = Quaternion.multiply(parentRot, localRot);
781
- // Aim toward simulated child position, blended back toward the animated direction.
735
+ // Aim toward the simulated child, blended toward the animated direction.
782
736
  if (ptR.child !== -1) {
783
737
  const childDir = Vector3.sub(positionsToTransform[ptR.child], ptRW.positionToTransform);
784
738
  if (childDir.magnitudeSq > EPSILON) {
@@ -795,7 +749,7 @@ transformRotations, transformLocalRotations, preserveTwist, sceneParentRotations
795
749
  };
796
750
  }
797
751
  }
798
- // Post-process: twist correction pass (parent �?child order).
752
+ // Post-process twist correction in parent-to-child order.
799
753
  if (preserveTwist) {
800
754
  for(let index = 0; index < pointsR.length; index++){
801
755
  const ptR = pointsR[index];