@zephyr3d/scene 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/animation.js +4 -33
- package/dist/animation/animation.js.map +1 -1
- package/dist/animation/animationset.js +24 -11
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/animationtrack.js +1 -0
- package/dist/animation/animationtrack.js.map +1 -1
- package/dist/animation/eulerrotationtrack.js +0 -1
- package/dist/animation/eulerrotationtrack.js.map +1 -1
- package/dist/animation/ik/ccd_solver.js +372 -0
- package/dist/animation/ik/ccd_solver.js.map +1 -0
- package/dist/animation/ik/fabrik_solver.js +399 -0
- package/dist/animation/ik/fabrik_solver.js.map +1 -0
- package/dist/animation/ik/ik_angle_constraint.js +181 -0
- package/dist/animation/ik/ik_angle_constraint.js.map +1 -0
- package/dist/animation/ik/ik_chain.js +163 -0
- package/dist/animation/ik/ik_chain.js.map +1 -0
- package/dist/animation/ik/ik_chain_builder.js +68 -0
- package/dist/animation/ik/ik_chain_builder.js.map +1 -0
- package/dist/animation/ik/ik_constraint.js +25 -0
- package/dist/animation/ik/ik_constraint.js.map +1 -0
- package/dist/animation/ik/ik_pole_constraint.js +123 -0
- package/dist/animation/ik/ik_pole_constraint.js.map +1 -0
- package/dist/animation/ik/ik_solver.js +48 -0
- package/dist/animation/ik/ik_solver.js.map +1 -0
- package/dist/animation/ik/ik_track.js +96 -0
- package/dist/animation/ik/ik_track.js.map +1 -0
- package/dist/animation/ik/ik_utils.js +270 -0
- package/dist/animation/ik/ik_utils.js.map +1 -0
- package/dist/animation/ik/two_bone_ik_solver.js +332 -0
- package/dist/animation/ik/two_bone_ik_solver.js.map +1 -0
- package/dist/animation/ik_modifier.js +61 -0
- package/dist/animation/ik_modifier.js.map +1 -0
- package/dist/animation/ik_postprocessor.js +71 -0
- package/dist/animation/ik_postprocessor.js.map +1 -0
- package/dist/animation/manual_transform_processor.js +156 -0
- package/dist/animation/manual_transform_processor.js.map +1 -0
- package/dist/animation/morphtarget.js +7 -1
- package/dist/animation/morphtarget.js.map +1 -1
- package/dist/animation/morphtrack.js +3 -3
- package/dist/animation/morphtrack.js.map +1 -1
- package/dist/animation/proptrack.js +37 -41
- package/dist/animation/proptrack.js.map +1 -1
- package/dist/animation/rotationtrack.js +0 -1
- package/dist/animation/rotationtrack.js.map +1 -1
- package/dist/animation/scaletrack.js +0 -1
- package/dist/animation/scaletrack.js.map +1 -1
- package/dist/animation/skeleton.js +57 -60
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/skeleton_modifier.js +38 -0
- package/dist/animation/skeleton_modifier.js.map +1 -0
- package/dist/animation/skeleton_postprocessor.js +50 -0
- package/dist/animation/skeleton_postprocessor.js.map +1 -0
- package/dist/animation/spring/multi_chain_spring_system.js +503 -0
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -0
- package/dist/animation/spring/spring_chain.js +103 -0
- package/dist/animation/spring/spring_chain.js.map +1 -0
- package/dist/animation/spring/spring_collider.js +247 -0
- package/dist/animation/spring/spring_collider.js.map +1 -0
- package/dist/animation/spring/spring_constraint.js +21 -0
- package/dist/animation/spring/spring_constraint.js.map +1 -0
- package/dist/animation/spring/spring_particle.js +20 -0
- package/dist/animation/spring/spring_particle.js.map +1 -0
- package/dist/animation/spring/spring_system.js +526 -0
- package/dist/animation/spring/spring_system.js.map +1 -0
- package/dist/animation/spring_modifier.js +45 -0
- package/dist/animation/spring_modifier.js.map +1 -0
- package/dist/animation/spring_postprocessor.js +54 -0
- package/dist/animation/spring_postprocessor.js.map +1 -0
- package/dist/animation/translationtrack.js +0 -1
- package/dist/animation/translationtrack.js.map +1 -1
- package/dist/app/api.js +13 -4
- package/dist/app/api.js.map +1 -1
- package/dist/app/app.js +13 -1
- package/dist/app/app.js.map +1 -1
- package/dist/app/engine.js +33 -45
- package/dist/app/engine.js.map +1 -1
- package/dist/app/inputmgr.js.map +1 -1
- package/dist/app/runtimescript.js.map +1 -1
- package/dist/app/screen.js +318 -0
- package/dist/app/screen.js.map +1 -0
- package/dist/app/scriptingsystem.js +10 -6
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +11 -22
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +79 -58
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/builtin.js +5 -5
- package/dist/asset/builtin.js.map +1 -1
- package/dist/asset/loaders/dds/dds.js +6 -2
- package/dist/asset/loaders/dds/dds.js.map +1 -1
- package/dist/asset/loaders/dds/dds_loader.js +1 -1
- package/dist/asset/loaders/dds/dds_loader.js.map +1 -1
- package/dist/asset/loaders/gltf/gltf_loader.js +14 -6
- package/dist/asset/loaders/gltf/gltf_loader.js.map +1 -1
- package/dist/asset/loaders/gltf/helpers.js +6 -2
- package/dist/asset/loaders/gltf/helpers.js.map +1 -1
- package/dist/asset/loaders/hdr/hdr.js +22 -15
- package/dist/asset/loaders/hdr/hdr.js.map +1 -1
- package/dist/asset/loaders/image/tga_Loader.js +2 -1
- package/dist/asset/loaders/image/tga_Loader.js.map +1 -1
- package/dist/asset/loaders/image/webimage_loader.js.map +1 -1
- package/dist/asset/loaders/loader.js +2 -2
- package/dist/asset/loaders/loader.js.map +1 -1
- package/dist/asset/model.js +9 -5
- package/dist/asset/model.js.map +1 -1
- package/dist/blitter/bilateralblur.js.map +1 -1
- package/dist/blitter/blitter.js +9 -11
- package/dist/blitter/blitter.js.map +1 -1
- package/dist/blitter/box.js +0 -1
- package/dist/blitter/box.js.map +1 -1
- package/dist/blitter/copy.js.map +1 -1
- package/dist/blitter/gaussianblur.js.map +1 -1
- package/dist/camera/base.js +1 -3
- package/dist/camera/base.js.map +1 -1
- package/dist/camera/camera.js +121 -37
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/fps.js +19 -17
- package/dist/camera/fps.js.map +1 -1
- package/dist/camera/orbit.js +45 -43
- package/dist/camera/orbit.js.map +1 -1
- package/dist/camera/orthocamera.js +27 -21
- package/dist/camera/orthocamera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +28 -19
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +15802 -15577
- package/dist/index.js +33 -11
- package/dist/index.js.map +1 -1
- package/dist/material/blinn.js.map +1 -1
- package/dist/material/grassmaterial.js.map +1 -1
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +11 -5
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +10 -9
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/albedocolor.js.map +1 -1
- package/dist/material/mixins/foliage.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +66 -4
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +7 -0
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +3 -3
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/brdf.js.map +1 -1
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mixins/texture.js +3 -0
- package/dist/material/mixins/texture.js.map +1 -1
- package/dist/material/mixins/vertexcolor.js.map +1 -1
- package/dist/material/particle.js.map +1 -1
- package/dist/material/pbrblueprint.js +180 -22
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/pbrsg.js.map +1 -1
- package/dist/material/shader/helper.js +41 -56
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/sprite.js +301 -0
- package/dist/material/sprite.js.map +1 -0
- package/dist/material/sprite3d.js +301 -0
- package/dist/material/sprite3d.js.map +1 -0
- package/dist/material/sprite3d_std.js +116 -0
- package/dist/material/sprite3d_std.js.map +1 -0
- package/dist/material/sprite3dblueprint.js +235 -0
- package/dist/material/sprite3dblueprint.js.map +1 -0
- package/dist/material/sprite_std.js +116 -0
- package/dist/material/sprite_std.js.map +1 -0
- package/dist/material/spriteblueprint.js +235 -0
- package/dist/material/spriteblueprint.js.map +1 -0
- package/dist/material/terrain-cm.js +0 -1
- package/dist/material/terrain-cm.js.map +1 -1
- package/dist/material/unlit.js.map +1 -1
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/fxaa.js.map +1 -1
- package/dist/posteffect/grayscale.js.map +1 -1
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/ssr.js +7 -5
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +8 -6
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/clipmap.js +0 -10
- package/dist/render/clipmap.js.map +1 -1
- package/dist/render/cluster_light.js +4 -4
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/cull_visitor.js +15 -17
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/depthpass.js +3 -4
- package/dist/render/depthpass.js.map +1 -1
- package/dist/render/drawable.js +15 -0
- package/dist/render/drawable.js.map +1 -0
- package/dist/render/drawable_mixin.js +8 -4
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +3 -1
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/fft_wavegenerator.js +67 -64
- package/dist/render/fft_wavegenerator.js.map +1 -1
- package/dist/render/fullscreenquad.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +3 -1
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/globalbindgroup_allocator.js +3 -1
- package/dist/render/globalbindgroup_allocator.js.map +1 -1
- package/dist/render/hzb.js +1 -2
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +13 -13
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/objectcolorpass.js +4 -7
- package/dist/render/objectcolorpass.js.map +1 -1
- package/dist/render/primitive.js +4 -5
- package/dist/render/primitive.js.map +1 -1
- package/dist/render/render_queue.js +10 -5
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +16 -22
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/renderpass.js +27 -52
- package/dist/render/renderpass.js.map +1 -1
- package/dist/render/rendertarget.js +5 -0
- package/dist/render/rendertarget.js.map +1 -0
- package/dist/render/screenrendertarget.js +56 -0
- package/dist/render/screenrendertarget.js.map +1 -0
- package/dist/render/shadowmap_pass.js +4 -5
- package/dist/render/shadowmap_pass.js.map +1 -1
- package/dist/render/sky.js +16 -14
- package/dist/render/sky.js.map +1 -1
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +296 -0
- package/dist/scene/basesprite.js.map +1 -0
- package/dist/scene/batchgroup.js +4 -2
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +9 -10
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/graph_node.js.map +1 -1
- package/dist/scene/light.js +22 -4
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +96 -26
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/octree.js.map +1 -1
- package/dist/scene/particlesys.js +25 -22
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/raycast_visitor.js +0 -16
- package/dist/scene/raycast_visitor.js.map +1 -1
- package/dist/scene/scene.js +7 -4
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +20 -35
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/sprite.js +18 -0
- package/dist/scene/sprite.js.map +1 -0
- package/dist/scene/sprite3d.js +18 -0
- package/dist/scene/sprite3d.js.map +1 -0
- package/dist/scene/terrain-cm/grass.js +5 -4
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/grassmaterial.js +3 -1
- package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +65 -48
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/water.js +35 -30
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js +17 -29
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/fog.js.map +1 -1
- package/dist/shaders/misc.js.map +1 -1
- package/dist/shaders/noise.js.map +1 -1
- package/dist/shaders/pbr.js.map +1 -1
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/ssr.js.map +1 -1
- package/dist/shaders/temporal.js.map +1 -1
- package/dist/shaders/water.js.map +1 -1
- package/dist/shadow/esm.js +1 -1
- package/dist/shadow/esm.js.map +1 -1
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/shader.js +3 -1
- package/dist/shadow/shader.js.map +1 -1
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadowmapper.js +6 -18
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shadow/ssm.js.map +1 -1
- package/dist/shadow/vsm.js.map +1 -1
- package/dist/shapes/box.js +9 -3
- package/dist/shapes/box.js.map +1 -1
- package/dist/shapes/cylinder.js +2 -2
- package/dist/shapes/cylinder.js.map +1 -1
- package/dist/shapes/plane.js +2 -2
- package/dist/shapes/plane.js.map +1 -1
- package/dist/shapes/shape.js +2 -1
- package/dist/shapes/shape.js.map +1 -1
- package/dist/shapes/sphere.js +2 -2
- package/dist/shapes/sphere.js.map +1 -1
- package/dist/shapes/tetrahedron.js +5 -6
- package/dist/shapes/tetrahedron.js.map +1 -1
- package/dist/shapes/torus.js +2 -2
- package/dist/shapes/torus.js.map +1 -1
- package/dist/utility/aabbtree.js +1 -1
- package/dist/utility/aabbtree.js.map +1 -1
- package/dist/utility/blueprint/common/constants.js +578 -104
- package/dist/utility/blueprint/common/constants.js.map +1 -1
- package/dist/utility/blueprint/common/math.js +471 -9
- package/dist/utility/blueprint/common/math.js.map +1 -1
- package/dist/utility/blueprint/common.js +1 -1
- package/dist/utility/blueprint/common.js.map +1 -1
- package/dist/utility/blueprint/material/func.js +9 -5
- package/dist/utility/blueprint/material/func.js.map +1 -1
- package/dist/utility/blueprint/material/inputs.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +288 -80
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/pbr.js +92 -4
- package/dist/utility/blueprint/material/pbr.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +62 -45
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/blueprint/node.js +28 -1
- package/dist/utility/blueprint/node.js.map +1 -1
- package/dist/utility/bounding_volume.js.map +1 -1
- package/dist/utility/debug.js.map +1 -1
- package/dist/utility/draco/decoder.js.map +1 -1
- package/dist/utility/misc.js +1 -1
- package/dist/utility/misc.js.map +1 -1
- package/dist/utility/panorama.js.map +1 -1
- package/dist/utility/pmrem.js.map +1 -1
- package/dist/utility/rendermipmap.js.map +1 -1
- package/dist/utility/serialization/json.js +19 -15
- package/dist/utility/serialization/json.js.map +1 -1
- package/dist/utility/serialization/manager.js +89 -22
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +44 -41
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -3
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +97 -9
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/common.js +102 -28
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +14 -12
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +216 -26
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +71 -100
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/misc.js +3 -2
- package/dist/utility/serialization/scene/misc.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +42 -9
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +7 -5
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +18 -15
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +3 -2
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +164 -0
- package/dist/utility/serialization/scene/sprite.js.map +1 -0
- package/dist/utility/serialization/scene/terrain.js +8 -6
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +11 -9
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js +6 -0
- package/dist/utility/serialization/types.js.map +1 -0
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/utility/textures/ggxlut.js.map +1 -1
- package/dist/utility/textures/gradientnoise.js.map +1 -1
- package/dist/utility/textures/randomnoise.js.map +1 -1
- package/dist/values.js +14 -14
- package/dist/values.js.map +1 -1
- package/package.json +80 -80
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { Vector3, Quaternion } from '@zephyr3d/base';
|
|
2
|
+
import { IKSolver } from './ik_solver.js';
|
|
3
|
+
import { IKUtils } from './ik_utils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Two Bone IK solver for chains with exactly 3 joints (2 bones).
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* This solver uses an analytical solution specifically optimized for
|
|
10
|
+
* two-bone chains like arms (shoulder-elbow-wrist) or legs (hip-knee-ankle).
|
|
11
|
+
* It's faster and more stable than iterative methods like FABRIK for this case.
|
|
12
|
+
*
|
|
13
|
+
* The solver supports an optional pole vector to control the bending direction
|
|
14
|
+
* of the middle joint (elbow/knee).
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/ class TwoBoneIKSolver extends IKSolver {
|
|
18
|
+
/** Optional pole vector position in world space */ _poleVector;
|
|
19
|
+
/** Weight of the pole vector constraint (0-1) */ _poleWeight;
|
|
20
|
+
/** Twist constraints for each joint (indexed by joint index) */ _twistConstraints;
|
|
21
|
+
/**
|
|
22
|
+
* Create a Two Bone IK solver.
|
|
23
|
+
*
|
|
24
|
+
* @param chain - The IK chain to solve (must have exactly 3 joints)
|
|
25
|
+
* @param poleVector - Optional pole vector position in world space
|
|
26
|
+
* @param poleWeight - Weight of the pole vector constraint (0-1, default: 1)
|
|
27
|
+
*/ constructor(chain, poleVector = null, poleWeight = 1){
|
|
28
|
+
super(chain, 1, 0.001); // Two bone IK doesn't need iterations
|
|
29
|
+
if (chain.joints.length !== 3) {
|
|
30
|
+
throw new Error('Two Bone IK requires exactly 3 joints (2 bones)');
|
|
31
|
+
}
|
|
32
|
+
this._poleVector = poleVector ? poleVector.clone() : null;
|
|
33
|
+
this._poleWeight = Math.max(0, Math.min(1, poleWeight));
|
|
34
|
+
this._twistConstraints = new Map();
|
|
35
|
+
// Set default twist constraints
|
|
36
|
+
// Root joint (shoulder/hip) - moderate twist
|
|
37
|
+
this._twistConstraints.set(0, {
|
|
38
|
+
minTwist: -Math.PI * 0.25,
|
|
39
|
+
maxTwist: Math.PI * 0.25,
|
|
40
|
+
smoothFactor: 0.3
|
|
41
|
+
});
|
|
42
|
+
// Middle joint (elbow/knee) - very limited twist
|
|
43
|
+
this._twistConstraints.set(1, {
|
|
44
|
+
minTwist: -Math.PI * 0.15,
|
|
45
|
+
maxTwist: Math.PI * 0.15,
|
|
46
|
+
smoothFactor: 0.3
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Set twist constraint for a specific joint.
|
|
51
|
+
*
|
|
52
|
+
* @param jointIndex - Index of the joint (0 = root, 1 = middle)
|
|
53
|
+
* @param minTwist - Minimum twist angle in radians
|
|
54
|
+
* @param maxTwist - Maximum twist angle in radians
|
|
55
|
+
* @param smoothFactor - Smoothing factor [0-1] (default: 0.3)
|
|
56
|
+
*/ setTwistConstraint(jointIndex, minTwist, maxTwist, smoothFactor = 0.3) {
|
|
57
|
+
if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {
|
|
58
|
+
throw new Error(`Invalid joint index: ${jointIndex}`);
|
|
59
|
+
}
|
|
60
|
+
this._twistConstraints.set(jointIndex, {
|
|
61
|
+
minTwist,
|
|
62
|
+
maxTwist,
|
|
63
|
+
smoothFactor: Math.max(0, Math.min(1, smoothFactor))
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get twist constraint for a specific joint.
|
|
68
|
+
*
|
|
69
|
+
* @param jointIndex - Index of the joint
|
|
70
|
+
* @returns Twist constraint or undefined if not set
|
|
71
|
+
*/ getTwistConstraint(jointIndex) {
|
|
72
|
+
return this._twistConstraints.get(jointIndex);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Remove twist constraint for a specific joint.
|
|
76
|
+
*
|
|
77
|
+
* @param jointIndex - Index of the joint
|
|
78
|
+
* @returns True if a constraint was removed
|
|
79
|
+
*/ removeTwistConstraint(jointIndex) {
|
|
80
|
+
return this._twistConstraints.delete(jointIndex);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clear all twist constraints.
|
|
84
|
+
*/ clearTwistConstraints() {
|
|
85
|
+
this._twistConstraints.clear();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get the pole vector position.
|
|
89
|
+
*/ get poleVector() {
|
|
90
|
+
return this._poleVector;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set the pole vector position.
|
|
94
|
+
*/ set poleVector(value) {
|
|
95
|
+
if (value) {
|
|
96
|
+
if (!this._poleVector) {
|
|
97
|
+
this._poleVector = value.clone();
|
|
98
|
+
} else {
|
|
99
|
+
this._poleVector.set(value);
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
this._poleVector = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get the pole vector weight.
|
|
107
|
+
*/ get poleWeight() {
|
|
108
|
+
return this._poleWeight;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Set the pole vector weight (0-1).
|
|
112
|
+
*/ set poleWeight(value) {
|
|
113
|
+
this._poleWeight = Math.max(0, Math.min(1, value));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Solve the IK chain to reach the target position using Two Bone IK algorithm.
|
|
117
|
+
*
|
|
118
|
+
* @param target - Target position for the end effector
|
|
119
|
+
* @returns True if the target is reachable, false if stretched to maximum
|
|
120
|
+
*/ solve(target) {
|
|
121
|
+
const joints = this._chain.joints;
|
|
122
|
+
// Update joint positions from scene nodes before solving
|
|
123
|
+
this._chain.updateFromNodes();
|
|
124
|
+
// Store original positions
|
|
125
|
+
this._chain.storeOriginalPositions();
|
|
126
|
+
const root = joints[0];
|
|
127
|
+
const middle = joints[1];
|
|
128
|
+
const end = joints[2];
|
|
129
|
+
const rootPos = root.position;
|
|
130
|
+
const upperLength = root.boneLength; // Length from root to middle
|
|
131
|
+
const lowerLength = middle.boneLength; // Length from middle to end
|
|
132
|
+
const totalLength = upperLength + lowerLength;
|
|
133
|
+
// Calculate direction and distance from root to target
|
|
134
|
+
const rootToTarget = Vector3.sub(target, rootPos, new Vector3());
|
|
135
|
+
const targetDistance = rootToTarget.magnitude;
|
|
136
|
+
// Check if target is reachable
|
|
137
|
+
if (targetDistance < 0.000001) {
|
|
138
|
+
// Target is at root position, keep original pose
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
let reachable = true;
|
|
142
|
+
// If target is unreachable, clamp to maximum distance
|
|
143
|
+
let effectiveTarget = target;
|
|
144
|
+
if (targetDistance >= totalLength - 0.0001) {
|
|
145
|
+
// Stretch to maximum length
|
|
146
|
+
const direction = Vector3.scale(rootToTarget, 1 / targetDistance, new Vector3());
|
|
147
|
+
effectiveTarget = Vector3.add(rootPos, Vector3.scale(direction, totalLength - 0.0001, new Vector3()), new Vector3());
|
|
148
|
+
reachable = false;
|
|
149
|
+
}
|
|
150
|
+
// Calculate the distance from root to effective target
|
|
151
|
+
const rootToEffectiveTarget = Vector3.sub(effectiveTarget, rootPos, new Vector3());
|
|
152
|
+
const distance = rootToEffectiveTarget.magnitude;
|
|
153
|
+
// Use law of cosines to find the angle at the root joint
|
|
154
|
+
// cos(rootAngle) = (a² + c² - b²) / (2ac)
|
|
155
|
+
const cosRootAngle = (upperLength * upperLength + distance * distance - lowerLength * lowerLength) / (2 * upperLength * distance);
|
|
156
|
+
const clampedCosRootAngle = Math.max(-1, Math.min(1, cosRootAngle));
|
|
157
|
+
const rootAngle = Math.acos(clampedCosRootAngle);
|
|
158
|
+
// Determine the plane of bending
|
|
159
|
+
let bendNormal;
|
|
160
|
+
if (this._poleVector && this._poleWeight > 0.001) {
|
|
161
|
+
// Use pole vector to determine bend direction
|
|
162
|
+
const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());
|
|
163
|
+
const rootToPole = Vector3.sub(this._poleVector, rootPos, new Vector3());
|
|
164
|
+
// Project pole vector onto plane perpendicular to root-target direction
|
|
165
|
+
const projectionLength = Vector3.dot(rootToPole, rootToTargetDir);
|
|
166
|
+
const projection = Vector3.scale(rootToTargetDir, projectionLength, new Vector3());
|
|
167
|
+
const perpendicular = Vector3.sub(rootToPole, projection, new Vector3());
|
|
168
|
+
const perpLength = perpendicular.magnitude;
|
|
169
|
+
if (perpLength > 0.000001) {
|
|
170
|
+
// Bend normal is perpendicular to both root-target and pole direction
|
|
171
|
+
bendNormal = Vector3.cross(rootToTargetDir, perpendicular, new Vector3()).inplaceNormalize();
|
|
172
|
+
} else {
|
|
173
|
+
// Pole is on the line, use default bend direction
|
|
174
|
+
bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);
|
|
175
|
+
}
|
|
176
|
+
// Apply pole weight
|
|
177
|
+
if (this._poleWeight < 0.999) {
|
|
178
|
+
const defaultNormal = this._getDefaultBendNormal(rootToEffectiveTarget);
|
|
179
|
+
// Slerp between default and pole-based normal
|
|
180
|
+
const angle = Math.acos(Math.max(-1, Math.min(1, Vector3.dot(defaultNormal, bendNormal))));
|
|
181
|
+
if (angle > 0.001) {
|
|
182
|
+
const axis = Vector3.cross(defaultNormal, bendNormal, new Vector3()).inplaceNormalize();
|
|
183
|
+
const rotation = new Quaternion().fromAxisAngle(axis, angle * this._poleWeight);
|
|
184
|
+
bendNormal = rotation.transform(defaultNormal, new Vector3());
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
// No pole vector, use default bend direction
|
|
189
|
+
bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);
|
|
190
|
+
}
|
|
191
|
+
// Calculate middle joint position
|
|
192
|
+
const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());
|
|
193
|
+
// Rotate root-to-target direction by rootAngle around bendNormal
|
|
194
|
+
const rotationToMiddle = new Quaternion().fromAxisAngle(bendNormal, rootAngle);
|
|
195
|
+
const rootToMiddleDir = rotationToMiddle.transform(rootToTargetDir, new Vector3());
|
|
196
|
+
// Place middle joint
|
|
197
|
+
middle.position.set(Vector3.add(rootPos, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3()));
|
|
198
|
+
// Place end joint at target
|
|
199
|
+
end.position.set(effectiveTarget);
|
|
200
|
+
// Apply constraints after solving
|
|
201
|
+
// Note: Constraints may modify joint positions, which could affect bone lengths
|
|
202
|
+
// For Two Bone IK, we apply constraints and then restore bone lengths
|
|
203
|
+
this._applyConstraints();
|
|
204
|
+
return reachable;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Apply all constraints to the joint chain.
|
|
208
|
+
* After applying constraints, we need to restore bone lengths.
|
|
209
|
+
*/ _applyConstraints() {
|
|
210
|
+
const constraints = this._chain.constraints;
|
|
211
|
+
if (constraints.length === 0) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const joints = this._chain.joints;
|
|
215
|
+
// Apply each constraint
|
|
216
|
+
for (const constraint of constraints){
|
|
217
|
+
constraint.apply(joints);
|
|
218
|
+
}
|
|
219
|
+
// After constraints are applied, we need to restore bone lengths
|
|
220
|
+
// because constraints may have moved joints in ways that change bone lengths
|
|
221
|
+
// For Two Bone IK, we fix this by adjusting positions while maintaining the constraint
|
|
222
|
+
this._restoreBoneLengths();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Restore bone lengths after constraints have been applied.
|
|
226
|
+
* This ensures that the chain maintains correct bone lengths.
|
|
227
|
+
*/ _restoreBoneLengths() {
|
|
228
|
+
const joints = this._chain.joints;
|
|
229
|
+
const root = joints[0];
|
|
230
|
+
const middle = joints[1];
|
|
231
|
+
const end = joints[2];
|
|
232
|
+
const upperLength = root.boneLength;
|
|
233
|
+
const lowerLength = middle.boneLength;
|
|
234
|
+
// Fix middle joint position to maintain upper bone length
|
|
235
|
+
const rootToMiddle = Vector3.sub(middle.position, root.position, new Vector3());
|
|
236
|
+
const rootToMiddleDist = rootToMiddle.magnitude;
|
|
237
|
+
if (rootToMiddleDist > 0.000001 && Math.abs(rootToMiddleDist - upperLength) > 0.0001) {
|
|
238
|
+
const rootToMiddleDir = Vector3.scale(rootToMiddle, 1 / rootToMiddleDist, new Vector3());
|
|
239
|
+
middle.position.set(Vector3.add(root.position, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3()));
|
|
240
|
+
}
|
|
241
|
+
// Fix end joint position to maintain lower bone length
|
|
242
|
+
const middleToEnd = Vector3.sub(end.position, middle.position, new Vector3());
|
|
243
|
+
const middleToEndDist = middleToEnd.magnitude;
|
|
244
|
+
if (middleToEndDist > 0.000001 && Math.abs(middleToEndDist - lowerLength) > 0.0001) {
|
|
245
|
+
const middleToEndDir = Vector3.scale(middleToEnd, 1 / middleToEndDist, new Vector3());
|
|
246
|
+
end.position.set(Vector3.add(middle.position, Vector3.scale(middleToEndDir, lowerLength, new Vector3()), new Vector3()));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Apply the solved joint positions to scene nodes as rotations.
|
|
251
|
+
*
|
|
252
|
+
* @param weight - Blend weight (0 = original, 1 = full IK, default: 1)
|
|
253
|
+
*/ applyToNodes(weight = 1) {
|
|
254
|
+
const joints = this._chain.joints;
|
|
255
|
+
// Apply rotation for root and middle joints (end joint doesn't need rotation)
|
|
256
|
+
for(let i = 0; i < joints.length - 1; i++){
|
|
257
|
+
const joint = joints[i];
|
|
258
|
+
const nextJoint = joints[i + 1];
|
|
259
|
+
// Calculate direction from current joint to next joint in world space
|
|
260
|
+
const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());
|
|
261
|
+
const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());
|
|
262
|
+
const originalDirNorm = Vector3.normalize(originalDir, new Vector3());
|
|
263
|
+
const newDirNorm = Vector3.normalize(newDir, new Vector3());
|
|
264
|
+
// Calculate basic rotation
|
|
265
|
+
const deltaRotation = new Quaternion();
|
|
266
|
+
IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);
|
|
267
|
+
// Calculate new world rotation
|
|
268
|
+
let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());
|
|
269
|
+
// Apply swing-twist constraint to prevent over-rotation
|
|
270
|
+
// Decompose rotation around bone axis
|
|
271
|
+
const swing = new Quaternion();
|
|
272
|
+
const twist = new Quaternion();
|
|
273
|
+
IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);
|
|
274
|
+
// Get twist angle
|
|
275
|
+
let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);
|
|
276
|
+
// Get twist constraint for this joint
|
|
277
|
+
const constraint = this._twistConstraints.get(i);
|
|
278
|
+
if (constraint) {
|
|
279
|
+
// Clamp and smooth twist
|
|
280
|
+
twistAngle = IKUtils.clampAndSmoothTwist(twistAngle, joint.previousTwist, constraint.minTwist, constraint.maxTwist, constraint.smoothFactor);
|
|
281
|
+
}
|
|
282
|
+
// Store for next frame
|
|
283
|
+
joint.previousTwist = twistAngle;
|
|
284
|
+
// Reconstruct rotation from clamped twist: Q = Twist * Swing
|
|
285
|
+
const clampedTwist = new Quaternion();
|
|
286
|
+
IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);
|
|
287
|
+
worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
|
|
288
|
+
// Blend with original rotation based on weight
|
|
289
|
+
if (weight < 1) {
|
|
290
|
+
Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);
|
|
291
|
+
}
|
|
292
|
+
// Store this frame's world rotation for next frame's twist continuity
|
|
293
|
+
if (!joint.previousIKRotation) {
|
|
294
|
+
joint.previousIKRotation = worldRotation.clone();
|
|
295
|
+
} else {
|
|
296
|
+
joint.previousIKRotation.set(worldRotation);
|
|
297
|
+
}
|
|
298
|
+
// Convert world rotation to local rotation (relative to parent)
|
|
299
|
+
if (joint.node.parent) {
|
|
300
|
+
const parentWorldRotation = new Quaternion();
|
|
301
|
+
joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);
|
|
302
|
+
// localRotation = conjugate(parentWorldRotation) * worldRotation
|
|
303
|
+
const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());
|
|
304
|
+
const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());
|
|
305
|
+
joint.node.rotation = localRotation;
|
|
306
|
+
} else {
|
|
307
|
+
// Root node has no parent, world rotation is local rotation
|
|
308
|
+
joint.node.rotation = worldRotation;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Get a default bend normal when no pole vector is specified.
|
|
314
|
+
* This tries to find a reasonable perpendicular direction.
|
|
315
|
+
*
|
|
316
|
+
* @param rootToTarget - Direction from root to target
|
|
317
|
+
* @returns A normalized perpendicular vector
|
|
318
|
+
*/ _getDefaultBendNormal(rootToTarget) {
|
|
319
|
+
const rootToTargetDir = Vector3.normalize(rootToTarget, new Vector3());
|
|
320
|
+
// Try to use world up (Y axis) as reference
|
|
321
|
+
let bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPY(), new Vector3());
|
|
322
|
+
const lenSq = bendNormal.x * bendNormal.x + bendNormal.y * bendNormal.y + bendNormal.z * bendNormal.z;
|
|
323
|
+
// If root-to-target is parallel to Y axis, use X axis instead
|
|
324
|
+
if (lenSq < 0.000001) {
|
|
325
|
+
bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPX(), new Vector3());
|
|
326
|
+
}
|
|
327
|
+
return bendNormal.inplaceNormalize();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export { TwoBoneIKSolver };
|
|
332
|
+
//# sourceMappingURL=two_bone_ik_solver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"two_bone_ik_solver.js","sources":["../../../src/animation/ik/two_bone_ik_solver.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\nimport { IKSolver } from './ik_solver';\r\nimport type { IKChain } from './ik_chain';\r\nimport { IKUtils } from './ik_utils';\r\nimport type { TwistConstraint } from './ik_constraint';\r\n\r\n/**\r\n * Two Bone IK solver for chains with exactly 3 joints (2 bones).\r\n *\r\n * @remarks\r\n * This solver uses an analytical solution specifically optimized for\r\n * two-bone chains like arms (shoulder-elbow-wrist) or legs (hip-knee-ankle).\r\n * It's faster and more stable than iterative methods like FABRIK for this case.\r\n *\r\n * The solver supports an optional pole vector to control the bending direction\r\n * of the middle joint (elbow/knee).\r\n *\r\n * @public\r\n */\r\nexport class TwoBoneIKSolver extends IKSolver {\r\n /** Optional pole vector position in world space */\r\n private _poleVector: Vector3 | null;\r\n /** Weight of the pole vector constraint (0-1) */\r\n private _poleWeight: number;\r\n /** Twist constraints for each joint (indexed by joint index) */\r\n private _twistConstraints: Map<number, TwistConstraint>;\r\n\r\n /**\r\n * Create a Two Bone IK solver.\r\n *\r\n * @param chain - The IK chain to solve (must have exactly 3 joints)\r\n * @param poleVector - Optional pole vector position in world space\r\n * @param poleWeight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n constructor(chain: IKChain, poleVector: Vector3 | null = null, poleWeight = 1) {\r\n super(chain, 1, 0.001); // Two bone IK doesn't need iterations\r\n\r\n if (chain.joints.length !== 3) {\r\n throw new Error('Two Bone IK requires exactly 3 joints (2 bones)');\r\n }\r\n\r\n this._poleVector = poleVector ? poleVector.clone() : null;\r\n this._poleWeight = Math.max(0, Math.min(1, poleWeight));\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints\r\n // Root joint (shoulder/hip) - moderate twist\r\n this._twistConstraints.set(0, {\r\n minTwist: -Math.PI * 0.25, // -45 degrees\r\n maxTwist: Math.PI * 0.25, // +45 degrees\r\n smoothFactor: 0.3\r\n });\r\n\r\n // Middle joint (elbow/knee) - very limited twist\r\n this._twistConstraints.set(1, {\r\n minTwist: -Math.PI * 0.15, // -27 degrees\r\n maxTwist: Math.PI * 0.15, // +27 degrees\r\n smoothFactor: 0.3\r\n });\r\n }\r\n\r\n /**\r\n * Set twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint (0 = root, 1 = middle)\r\n * @param minTwist - Minimum twist angle in radians\r\n * @param maxTwist - Maximum twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)\r\n */\r\n setTwistConstraint(\r\n jointIndex: number,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.3\r\n ): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._twistConstraints.set(jointIndex, {\r\n minTwist,\r\n maxTwist,\r\n smoothFactor: Math.max(0, Math.min(1, smoothFactor))\r\n });\r\n }\r\n\r\n /**\r\n * Get twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Twist constraint or undefined if not set\r\n */\r\n getTwistConstraint(jointIndex: number): TwistConstraint | undefined {\r\n return this._twistConstraints.get(jointIndex);\r\n }\r\n\r\n /**\r\n * Remove twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if a constraint was removed\r\n */\r\n removeTwistConstraint(jointIndex: number): boolean {\r\n return this._twistConstraints.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all twist constraints.\r\n */\r\n clearTwistConstraints(): void {\r\n this._twistConstraints.clear();\r\n }\r\n\r\n /**\r\n * Get the pole vector position.\r\n */\r\n get poleVector(): Vector3 | null {\r\n return this._poleVector;\r\n }\r\n\r\n /**\r\n * Set the pole vector position.\r\n */\r\n set poleVector(value: Vector3 | null) {\r\n if (value) {\r\n if (!this._poleVector) {\r\n this._poleVector = value.clone();\r\n } else {\r\n this._poleVector.set(value);\r\n }\r\n } else {\r\n this._poleVector = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get the pole vector weight.\r\n */\r\n get poleWeight(): number {\r\n return this._poleWeight;\r\n }\r\n\r\n /**\r\n * Set the pole vector weight (0-1).\r\n */\r\n set poleWeight(value: number) {\r\n this._poleWeight = Math.max(0, Math.min(1, value));\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using Two Bone IK algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if the target is reachable, false if stretched to maximum\r\n */\r\n solve(target: Vector3): boolean {\r\n const joints = this._chain.joints;\r\n\r\n // Update joint positions from scene nodes before solving\r\n this._chain.updateFromNodes();\r\n\r\n // Store original positions\r\n this._chain.storeOriginalPositions();\r\n\r\n const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const rootPos = root.position;\r\n const upperLength = root.boneLength; // Length from root to middle\r\n const lowerLength = middle.boneLength; // Length from middle to end\r\n const totalLength = upperLength + lowerLength;\r\n\r\n // Calculate direction and distance from root to target\r\n const rootToTarget = Vector3.sub(target, rootPos, new Vector3());\r\n const targetDistance = rootToTarget.magnitude;\r\n\r\n // Check if target is reachable\r\n if (targetDistance < 0.000001) {\r\n // Target is at root position, keep original pose\r\n return true;\r\n }\r\n\r\n let reachable = true;\r\n\r\n // If target is unreachable, clamp to maximum distance\r\n let effectiveTarget = target;\r\n if (targetDistance >= totalLength - 0.0001) {\r\n // Stretch to maximum length\r\n const direction = Vector3.scale(rootToTarget, 1 / targetDistance, new Vector3());\r\n effectiveTarget = Vector3.add(\r\n rootPos,\r\n Vector3.scale(direction, totalLength - 0.0001, new Vector3()),\r\n new Vector3()\r\n );\r\n reachable = false;\r\n }\r\n\r\n // Calculate the distance from root to effective target\r\n const rootToEffectiveTarget = Vector3.sub(effectiveTarget, rootPos, new Vector3());\r\n const distance = rootToEffectiveTarget.magnitude;\r\n\r\n // Use law of cosines to find the angle at the root joint\r\n // cos(rootAngle) = (a² + c² - b²) / (2ac)\r\n const cosRootAngle =\r\n (upperLength * upperLength + distance * distance - lowerLength * lowerLength) /\r\n (2 * upperLength * distance);\r\n const clampedCosRootAngle = Math.max(-1, Math.min(1, cosRootAngle));\r\n const rootAngle = Math.acos(clampedCosRootAngle);\r\n\r\n // Determine the plane of bending\r\n let bendNormal: Vector3;\r\n\r\n if (this._poleVector && this._poleWeight > 0.001) {\r\n // Use pole vector to determine bend direction\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n const rootToPole = Vector3.sub(this._poleVector, rootPos, new Vector3());\r\n\r\n // Project pole vector onto plane perpendicular to root-target direction\r\n const projectionLength = Vector3.dot(rootToPole, rootToTargetDir);\r\n const projection = Vector3.scale(rootToTargetDir, projectionLength, new Vector3());\r\n const perpendicular = Vector3.sub(rootToPole, projection, new Vector3());\r\n\r\n const perpLength = perpendicular.magnitude;\r\n if (perpLength > 0.000001) {\r\n // Bend normal is perpendicular to both root-target and pole direction\r\n bendNormal = Vector3.cross(rootToTargetDir, perpendicular, new Vector3()).inplaceNormalize();\r\n } else {\r\n // Pole is on the line, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Apply pole weight\r\n if (this._poleWeight < 0.999) {\r\n const defaultNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n // Slerp between default and pole-based normal\r\n const angle = Math.acos(Math.max(-1, Math.min(1, Vector3.dot(defaultNormal, bendNormal))));\r\n if (angle > 0.001) {\r\n const axis = Vector3.cross(defaultNormal, bendNormal, new Vector3()).inplaceNormalize();\r\n const rotation = new Quaternion().fromAxisAngle(axis, angle * this._poleWeight);\r\n bendNormal = rotation.transform(defaultNormal, new Vector3());\r\n }\r\n }\r\n } else {\r\n // No pole vector, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Calculate middle joint position\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n\r\n // Rotate root-to-target direction by rootAngle around bendNormal\r\n const rotationToMiddle = new Quaternion().fromAxisAngle(bendNormal, rootAngle);\r\n const rootToMiddleDir = rotationToMiddle.transform(rootToTargetDir, new Vector3());\r\n\r\n // Place middle joint\r\n middle.position.set(\r\n Vector3.add(rootPos, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n\r\n // Place end joint at target\r\n end.position.set(effectiveTarget);\r\n\r\n // Apply constraints after solving\r\n // Note: Constraints may modify joint positions, which could affect bone lengths\r\n // For Two Bone IK, we apply constraints and then restore bone lengths\r\n this._applyConstraints();\r\n\r\n return reachable;\r\n }\r\n\r\n /**\r\n * Apply all constraints to the joint chain.\r\n * After applying constraints, we need to restore bone lengths.\r\n */\r\n private _applyConstraints(): void {\r\n const constraints = this._chain.constraints;\r\n if (constraints.length === 0) {\r\n return;\r\n }\r\n\r\n const joints = this._chain.joints;\r\n\r\n // Apply each constraint\r\n for (const constraint of constraints) {\r\n constraint.apply(joints);\r\n }\r\n\r\n // After constraints are applied, we need to restore bone lengths\r\n // because constraints may have moved joints in ways that change bone lengths\r\n // For Two Bone IK, we fix this by adjusting positions while maintaining the constraint\r\n this._restoreBoneLengths();\r\n }\r\n\r\n /**\r\n * Restore bone lengths after constraints have been applied.\r\n * This ensures that the chain maintains correct bone lengths.\r\n */\r\n private _restoreBoneLengths(): void {\r\n const joints = this._chain.joints;\r\n const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const upperLength = root.boneLength;\r\n const lowerLength = middle.boneLength;\r\n\r\n // Fix middle joint position to maintain upper bone length\r\n const rootToMiddle = Vector3.sub(middle.position, root.position, new Vector3());\r\n const rootToMiddleDist = rootToMiddle.magnitude;\r\n\r\n if (rootToMiddleDist > 0.000001 && Math.abs(rootToMiddleDist - upperLength) > 0.0001) {\r\n const rootToMiddleDir = Vector3.scale(rootToMiddle, 1 / rootToMiddleDist, new Vector3());\r\n middle.position.set(\r\n Vector3.add(root.position, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n }\r\n\r\n // Fix end joint position to maintain lower bone length\r\n const middleToEnd = Vector3.sub(end.position, middle.position, new Vector3());\r\n const middleToEndDist = middleToEnd.magnitude;\r\n\r\n if (middleToEndDist > 0.000001 && Math.abs(middleToEndDist - lowerLength) > 0.0001) {\r\n const middleToEndDir = Vector3.scale(middleToEnd, 1 / middleToEndDist, new Vector3());\r\n end.position.set(\r\n Vector3.add(middle.position, Vector3.scale(middleToEndDir, lowerLength, new Vector3()), new Vector3())\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Apply the solved joint positions to scene nodes as rotations.\r\n *\r\n * @param weight - Blend weight (0 = original, 1 = full IK, default: 1)\r\n */\r\n applyToNodes(weight = 1): void {\r\n const joints = this._chain.joints;\r\n\r\n // Apply rotation for root and middle joints (end joint doesn't need rotation)\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const nextJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to next joint in world space\r\n const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());\r\n const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());\r\n\r\n const originalDirNorm = Vector3.normalize(originalDir, new Vector3());\r\n const newDirNorm = Vector3.normalize(newDir, new Vector3());\r\n\r\n // Calculate basic rotation\r\n const deltaRotation = new Quaternion();\r\n IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);\r\n\r\n // Calculate new world rotation\r\n let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());\r\n\r\n // Apply swing-twist constraint to prevent over-rotation\r\n // Decompose rotation around bone axis\r\n const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);\r\n\r\n // Get twist constraint for this joint\r\n const constraint = this._twistConstraints.get(i);\r\n if (constraint) {\r\n // Clamp and smooth twist\r\n twistAngle = IKUtils.clampAndSmoothTwist(\r\n twistAngle,\r\n joint.previousTwist,\r\n constraint.minTwist,\r\n constraint.maxTwist,\r\n constraint.smoothFactor\r\n );\r\n }\r\n\r\n // Store for next frame\r\n joint.previousTwist = twistAngle;\r\n\r\n // Reconstruct rotation from clamped twist: Q = Twist * Swing\r\n const clampedTwist = new Quaternion();\r\n IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);\r\n worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);\r\n\r\n // Blend with original rotation based on weight\r\n if (weight < 1) {\r\n Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);\r\n }\r\n\r\n // Store this frame's world rotation for next frame's twist continuity\r\n if (!joint.previousIKRotation) {\r\n joint.previousIKRotation = worldRotation.clone();\r\n } else {\r\n joint.previousIKRotation.set(worldRotation);\r\n }\r\n\r\n // Convert world rotation to local rotation (relative to parent)\r\n if (joint.node.parent) {\r\n const parentWorldRotation = new Quaternion();\r\n joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);\r\n\r\n // localRotation = conjugate(parentWorldRotation) * worldRotation\r\n const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());\r\n const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());\r\n\r\n joint.node.rotation = localRotation;\r\n } else {\r\n // Root node has no parent, world rotation is local rotation\r\n joint.node.rotation = worldRotation;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get a default bend normal when no pole vector is specified.\r\n * This tries to find a reasonable perpendicular direction.\r\n *\r\n * @param rootToTarget - Direction from root to target\r\n * @returns A normalized perpendicular vector\r\n */\r\n private _getDefaultBendNormal(rootToTarget: Vector3): Vector3 {\r\n const rootToTargetDir = Vector3.normalize(rootToTarget, new Vector3());\r\n\r\n // Try to use world up (Y axis) as reference\r\n let bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPY(), new Vector3());\r\n const lenSq = bendNormal.x * bendNormal.x + bendNormal.y * bendNormal.y + bendNormal.z * bendNormal.z;\r\n\r\n // If root-to-target is parallel to Y axis, use X axis instead\r\n if (lenSq < 0.000001) {\r\n bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPX(), new Vector3());\r\n }\r\n\r\n return bendNormal.inplaceNormalize();\r\n }\r\n}\r\n"],"names":["TwoBoneIKSolver","IKSolver","chain","poleVector","poleWeight","joints","length","Error","_poleVector","clone","_poleWeight","Math","max","min","_twistConstraints","Map","set","minTwist","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","value","solve","target","updateFromNodes","storeOriginalPositions","root","middle","end","rootPos","position","upperLength","boneLength","lowerLength","totalLength","rootToTarget","Vector3","sub","targetDistance","magnitude","reachable","effectiveTarget","direction","scale","add","rootToEffectiveTarget","distance","cosRootAngle","clampedCosRootAngle","rootAngle","acos","bendNormal","rootToTargetDir","normalize","rootToPole","projectionLength","dot","projection","perpendicular","perpLength","cross","inplaceNormalize","_getDefaultBendNormal","defaultNormal","angle","axis","rotation","Quaternion","fromAxisAngle","transform","rotationToMiddle","rootToMiddleDir","_applyConstraints","constraints","constraint","apply","_restoreBoneLengths","rootToMiddle","rootToMiddleDist","abs","middleToEnd","middleToEndDist","middleToEndDir","applyToNodes","weight","i","joint","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","newDirNorm","deltaRotation","IKUtils","fromToRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","createTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","axisPY","lenSq","x","y","z","axisPX"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { SkeletonModifier } from './skeleton_modifier.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Skeleton modifier for IK solvers.
|
|
5
|
+
*
|
|
6
|
+
* Integrates IK solving into the skeleton post-processing pipeline.
|
|
7
|
+
* The IK solver is executed each frame and results are blended with the base animation.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/ class IKModifier extends SkeletonModifier {
|
|
11
|
+
_solver;
|
|
12
|
+
_target;
|
|
13
|
+
/**
|
|
14
|
+
* Create an IK post-processor.
|
|
15
|
+
*
|
|
16
|
+
* @param solver - The IK solver to integrate
|
|
17
|
+
* @param target - Target position for the end effector
|
|
18
|
+
* @param weight - Blend weight [0-1] (default: 1.0)
|
|
19
|
+
*/ constructor(solver, target, weight = 1.0){
|
|
20
|
+
super(weight);
|
|
21
|
+
this._solver = solver;
|
|
22
|
+
this._target = target.clone();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the IK solver.
|
|
26
|
+
*/ get solver() {
|
|
27
|
+
return this._solver;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the current target position.
|
|
31
|
+
*/ get target() {
|
|
32
|
+
return this._target.clone();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Set the target position for the end effector.
|
|
36
|
+
*
|
|
37
|
+
* @param target - New target position (will be cloned)
|
|
38
|
+
*/ setTarget(target) {
|
|
39
|
+
this._target.set(target);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Apply IK solving to skeleton joints.
|
|
43
|
+
*/ apply(_skeleton, _deltaTime) {
|
|
44
|
+
if (!this._enabled || this._weight <= 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Solve IK
|
|
48
|
+
this._solver.solve(this._target);
|
|
49
|
+
// Apply to nodes with blending
|
|
50
|
+
this._solver.applyToNodes(this._weight);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Reset the IK solver to initial state.
|
|
54
|
+
*/ reset() {
|
|
55
|
+
// IK solvers typically don't need explicit reset
|
|
56
|
+
// as they solve based on current joint positions
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { IKModifier };
|
|
61
|
+
//# sourceMappingURL=ik_modifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik_modifier.js","sources":["../../src/animation/ik_modifier.ts"],"sourcesContent":["import { SkeletonModifier } from './skeleton_modifier';\r\nimport type { Skeleton } from './skeleton';\r\nimport type { IKSolver } from './ik/ik_solver';\r\nimport type { Vector3 } from '@zephyr3d/base';\r\n\r\n/**\r\n * Skeleton modifier for IK solvers.\r\n *\r\n * Integrates IK solving into the skeleton post-processing pipeline.\r\n * The IK solver is executed each frame and results are blended with the base animation.\r\n *\r\n * @public\r\n */\r\nexport class IKModifier<Solver extends IKSolver = IKSolver> extends SkeletonModifier {\r\n private _solver: Solver;\r\n private _target: Vector3;\r\n\r\n /**\r\n * Create an IK post-processor.\r\n *\r\n * @param solver - The IK solver to integrate\r\n * @param target - Target position for the end effector\r\n * @param weight - Blend weight [0-1] (default: 1.0)\r\n */\r\n constructor(solver: Solver, target: Vector3, weight: number = 1.0) {\r\n super(weight);\r\n this._solver = solver;\r\n this._target = target.clone();\r\n }\r\n\r\n /**\r\n * Get the IK solver.\r\n */\r\n get solver(): Solver {\r\n return this._solver;\r\n }\r\n\r\n /**\r\n * Get the current target position.\r\n */\r\n get target(): Vector3 {\r\n return this._target.clone();\r\n }\r\n\r\n /**\r\n * Set the target position for the end effector.\r\n *\r\n * @param target - New target position (will be cloned)\r\n */\r\n setTarget(target: Vector3): void {\r\n this._target.set(target);\r\n }\r\n\r\n /**\r\n * Apply IK solving to skeleton joints.\r\n */\r\n apply(_skeleton: Skeleton, _deltaTime: number): void {\r\n if (!this._enabled || this._weight <= 0) {\r\n return;\r\n }\r\n\r\n // Solve IK\r\n this._solver.solve(this._target);\r\n\r\n // Apply to nodes with blending\r\n this._solver.applyToNodes(this._weight);\r\n }\r\n\r\n /**\r\n * Reset the IK solver to initial state.\r\n */\r\n reset(): void {\r\n // IK solvers typically don't need explicit reset\r\n // as they solve based on current joint positions\r\n }\r\n}\r\n"],"names":["IKModifier","SkeletonModifier","_solver","_target","solver","target","weight","clone","setTarget","set","apply","_skeleton","_deltaTime","_enabled","_weight","solve","applyToNodes","reset"],"mappings":";;AAKA;;;;;;;IAQO,MAAMA,UAAuDC,SAAAA,gBAAAA,CAAAA;IAC1DC,OAAgB;IAChBC,OAAiB;AAEzB;;;;;;AAMC,MACD,YAAYC,MAAc,EAAEC,MAAe,EAAEC,MAAAA,GAAiB,GAAG,CAAE;AACjE,QAAA,KAAK,CAACA,MAAAA,CAAAA;QACN,IAAI,CAACJ,OAAO,GAAGE,MAAAA;AACf,QAAA,IAAI,CAACD,OAAO,GAAGE,MAAAA,CAAOE,KAAK,EAAA;AAC7B;AAEA;;AAEC,MACD,IAAIH,MAAiB,GAAA;QACnB,OAAO,IAAI,CAACF,OAAO;AACrB;AAEA;;AAEC,MACD,IAAIG,MAAkB,GAAA;AACpB,QAAA,OAAO,IAAI,CAACF,OAAO,CAACI,KAAK,EAAA;AAC3B;AAEA;;;;MAKAC,SAAAA,CAAUH,MAAe,EAAQ;AAC/B,QAAA,IAAI,CAACF,OAAO,CAACM,GAAG,CAACJ,MAAAA,CAAAA;AACnB;AAEA;;AAEC,MACDK,KAAMC,CAAAA,SAAmB,EAAEC,UAAkB,EAAQ;QACnD,IAAI,CAAC,IAAI,CAACC,QAAQ,IAAI,IAAI,CAACC,OAAO,IAAI,CAAG,EAAA;AACvC,YAAA;AACF;;AAGA,QAAA,IAAI,CAACZ,OAAO,CAACa,KAAK,CAAC,IAAI,CAACZ,OAAO,CAAA;;AAG/B,QAAA,IAAI,CAACD,OAAO,CAACc,YAAY,CAAC,IAAI,CAACF,OAAO,CAAA;AACxC;AAEA;;AAEC,MACDG,KAAc,GAAA;;;AAGd;AACF;;;;"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { SkeletonPostProcessor } from './skeleton_postprocessor.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-processor wrapper for IK solvers.
|
|
5
|
+
*
|
|
6
|
+
* Integrates IK solving into the skeleton post-processing pipeline.
|
|
7
|
+
* The IK solver is executed each frame and results are blended with the base animation.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const ikChain = new IKChain([joint1, joint2, joint3]);
|
|
12
|
+
* const ikSolver = new FABRIKSolver(ikChain);
|
|
13
|
+
* const targetPos = new Vector3(1, 2, 3);
|
|
14
|
+
* const processor = new IKPostProcessor(ikSolver, targetPos, 1.0);
|
|
15
|
+
* skeleton.addPostProcessor(processor);
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/ class IKPostProcessor extends SkeletonPostProcessor {
|
|
20
|
+
_solver;
|
|
21
|
+
_target;
|
|
22
|
+
/**
|
|
23
|
+
* Create an IK post-processor.
|
|
24
|
+
*
|
|
25
|
+
* @param solver - The IK solver to integrate
|
|
26
|
+
* @param target - Target position for the end effector
|
|
27
|
+
* @param weight - Blend weight [0-1] (default: 1.0)
|
|
28
|
+
* @param priority - Priority for ordering (default: 50)
|
|
29
|
+
*/ constructor(solver, target, weight = 1.0, priority = 50){
|
|
30
|
+
super(weight, priority);
|
|
31
|
+
this._solver = solver;
|
|
32
|
+
this._target = target.clone();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the IK solver.
|
|
36
|
+
*/ get solver() {
|
|
37
|
+
return this._solver;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the current target position.
|
|
41
|
+
*/ get target() {
|
|
42
|
+
return this._target.clone();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Set the target position for the end effector.
|
|
46
|
+
*
|
|
47
|
+
* @param target - New target position (will be cloned)
|
|
48
|
+
*/ setTarget(target) {
|
|
49
|
+
this._target.set(target);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Apply IK solving to skeleton joints.
|
|
53
|
+
*/ apply(_skeleton, _deltaTime) {
|
|
54
|
+
if (!this._enabled || this._weight <= 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Solve IK
|
|
58
|
+
this._solver.solve(this._target);
|
|
59
|
+
// Apply to nodes with blending
|
|
60
|
+
this._solver.applyToNodes(this._weight);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reset the IK solver to initial state.
|
|
64
|
+
*/ reset() {
|
|
65
|
+
// IK solvers typically don't need explicit reset
|
|
66
|
+
// as they solve based on current joint positions
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { IKPostProcessor };
|
|
71
|
+
//# sourceMappingURL=ik_postprocessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik_postprocessor.js","sources":["../../src/animation/ik_postprocessor.ts"],"sourcesContent":["import { SkeletonPostProcessor } from './skeleton_postprocessor';\r\nimport type { Skeleton } from './skeleton';\r\nimport type { IKSolver } from './ik/ik_solver';\r\nimport type { Vector3 } from '@zephyr3d/base';\r\n\r\n/**\r\n * Post-processor wrapper for IK solvers.\r\n *\r\n * Integrates IK solving into the skeleton post-processing pipeline.\r\n * The IK solver is executed each frame and results are blended with the base animation.\r\n *\r\n * @example\r\n * ```typescript\r\n * const ikChain = new IKChain([joint1, joint2, joint3]);\r\n * const ikSolver = new FABRIKSolver(ikChain);\r\n * const targetPos = new Vector3(1, 2, 3);\r\n * const processor = new IKPostProcessor(ikSolver, targetPos, 1.0);\r\n * skeleton.addPostProcessor(processor);\r\n * ```\r\n *\r\n * @public\r\n */\r\nexport class IKPostProcessor<Solver extends IKSolver = IKSolver> extends SkeletonPostProcessor {\r\n private _solver: Solver;\r\n private _target: Vector3;\r\n\r\n /**\r\n * Create an IK post-processor.\r\n *\r\n * @param solver - The IK solver to integrate\r\n * @param target - Target position for the end effector\r\n * @param weight - Blend weight [0-1] (default: 1.0)\r\n * @param priority - Priority for ordering (default: 50)\r\n */\r\n constructor(solver: Solver, target: Vector3, weight: number = 1.0, priority: number = 50) {\r\n super(weight, priority);\r\n this._solver = solver;\r\n this._target = target.clone();\r\n }\r\n\r\n /**\r\n * Get the IK solver.\r\n */\r\n get solver(): Solver {\r\n return this._solver;\r\n }\r\n\r\n /**\r\n * Get the current target position.\r\n */\r\n get target(): Vector3 {\r\n return this._target.clone();\r\n }\r\n\r\n /**\r\n * Set the target position for the end effector.\r\n *\r\n * @param target - New target position (will be cloned)\r\n */\r\n setTarget(target: Vector3): void {\r\n this._target.set(target);\r\n }\r\n\r\n /**\r\n * Apply IK solving to skeleton joints.\r\n */\r\n apply(_skeleton: Skeleton, _deltaTime: number): void {\r\n if (!this._enabled || this._weight <= 0) {\r\n return;\r\n }\r\n\r\n // Solve IK\r\n this._solver.solve(this._target);\r\n\r\n // Apply to nodes with blending\r\n this._solver.applyToNodes(this._weight);\r\n }\r\n\r\n /**\r\n * Reset the IK solver to initial state.\r\n */\r\n reset(): void {\r\n // IK solvers typically don't need explicit reset\r\n // as they solve based on current joint positions\r\n }\r\n}\r\n"],"names":["IKPostProcessor","SkeletonPostProcessor","_solver","_target","solver","target","weight","priority","clone","setTarget","set","apply","_skeleton","_deltaTime","_enabled","_weight","solve","applyToNodes","reset"],"mappings":";;AAKA;;;;;;;;;;;;;;;;IAiBO,MAAMA,eAA4DC,SAAAA,qBAAAA,CAAAA;IAC/DC,OAAgB;IAChBC,OAAiB;AAEzB;;;;;;;MAQA,WAAA,CAAYC,MAAc,EAAEC,MAAe,EAAEC,SAAiB,GAAG,EAAEC,QAAmB,GAAA,EAAE,CAAE;AACxF,QAAA,KAAK,CAACD,MAAQC,EAAAA,QAAAA,CAAAA;QACd,IAAI,CAACL,OAAO,GAAGE,MAAAA;AACf,QAAA,IAAI,CAACD,OAAO,GAAGE,MAAAA,CAAOG,KAAK,EAAA;AAC7B;AAEA;;AAEC,MACD,IAAIJ,MAAiB,GAAA;QACnB,OAAO,IAAI,CAACF,OAAO;AACrB;AAEA;;AAEC,MACD,IAAIG,MAAkB,GAAA;AACpB,QAAA,OAAO,IAAI,CAACF,OAAO,CAACK,KAAK,EAAA;AAC3B;AAEA;;;;MAKAC,SAAAA,CAAUJ,MAAe,EAAQ;AAC/B,QAAA,IAAI,CAACF,OAAO,CAACO,GAAG,CAACL,MAAAA,CAAAA;AACnB;AAEA;;AAEC,MACDM,KAAMC,CAAAA,SAAmB,EAAEC,UAAkB,EAAQ;QACnD,IAAI,CAAC,IAAI,CAACC,QAAQ,IAAI,IAAI,CAACC,OAAO,IAAI,CAAG,EAAA;AACvC,YAAA;AACF;;AAGA,QAAA,IAAI,CAACb,OAAO,CAACc,KAAK,CAAC,IAAI,CAACb,OAAO,CAAA;;AAG/B,QAAA,IAAI,CAACD,OAAO,CAACe,YAAY,CAAC,IAAI,CAACF,OAAO,CAAA;AACxC;AAEA;;AAEC,MACDG,KAAc,GAAA;;;AAGd;AACF;;;;"}
|