@zephyr3d/scene 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/animation.js +0 -18
- package/dist/animation/animation.js.map +1 -1
- package/dist/animation/animationset.js +200 -3
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/ik/ccd_solver.js +371 -0
- package/dist/animation/ik/ccd_solver.js.map +1 -0
- package/dist/animation/ik/fabrik_solver.js +398 -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_constraint.js +25 -0
- package/dist/animation/ik/ik_constraint.js.map +1 -0
- package/dist/animation/ik/ik_pole_constraint.js +128 -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 +191 -0
- package/dist/animation/ik/ik_utils.js.map +1 -0
- package/dist/animation/ik/two_bone_ik_solver.js +331 -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/skeleton.js +55 -51
- 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_bone.js +240 -0
- package/dist/animation/spring/spring_bone.js.map +1 -0
- package/dist/animation/spring/spring_bone_collider.js +198 -0
- package/dist/animation/spring/spring_bone_collider.js.map +1 -0
- package/dist/animation/spring/spring_bone_constraint.js +170 -0
- package/dist/animation/spring/spring_bone_constraint.js.map +1 -0
- package/dist/animation/spring/spring_bone_system.js +328 -0
- package/dist/animation/spring/spring_bone_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/app/screen.js +1 -1
- package/dist/app/screen.js.map +1 -1
- package/dist/asset/model.js +10 -6
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/perspectivecamera.js +3 -3
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +1400 -4
- package/dist/index.js +16 -0
- package/dist/index.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/pbr/common.js +20 -17
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/shader/helper.js +5 -3
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/render/gpu_picking.js +100 -0
- package/dist/render/gpu_picking.js.map +1 -0
- package/dist/render/rendergraph/device_pool_allocator.js +41 -0
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -0
- package/dist/render/rendergraph/executor.js +146 -0
- package/dist/render/rendergraph/executor.js.map +1 -0
- package/dist/render/rendergraph/forward_plus_builder.js +414 -0
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -0
- package/dist/render/rendergraph/rendergraph.js +306 -0
- package/dist/render/rendergraph/rendergraph.js.map +1 -0
- package/dist/render/rendergraph/types.js +57 -0
- package/dist/render/rendergraph/types.js.map +1 -0
- package/dist/render/sky_motion_vector.js +85 -0
- package/dist/render/sky_motion_vector.js.map +1 -0
- package/dist/scene/mesh.js +15 -23
- package/dist/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +24 -23
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +62 -0
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +1 -1
- package/package.json +3 -3
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimemgr.js +0 -38
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimemgr.js.map +0 -1
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimescript.js +0 -10
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimescript.js.map +0 -1
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptingsystem.js +0 -127
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptingsystem.js.map +0 -1
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptregistry.js +0 -263
- package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptregistry.js.map +0 -1
- package/dist/src/animation/animation.js +0 -127
- package/dist/src/animation/animation.js.map +0 -1
- package/dist/src/animation/animationset.js +0 -255
- package/dist/src/animation/animationset.js.map +0 -1
- package/dist/src/animation/animationtrack.js +0 -34
- package/dist/src/animation/animationtrack.js.map +0 -1
- package/dist/src/animation/eulerrotationtrack.js +0 -52
- package/dist/src/animation/eulerrotationtrack.js.map +0 -1
- package/dist/src/animation/morphtarget.js +0 -93
- package/dist/src/animation/morphtarget.js.map +0 -1
- package/dist/src/animation/morphtrack.js +0 -70
- package/dist/src/animation/morphtrack.js.map +0 -1
- package/dist/src/animation/proptrack.js +0 -161
- package/dist/src/animation/proptrack.js.map +0 -1
- package/dist/src/animation/rotationtrack.js +0 -51
- package/dist/src/animation/rotationtrack.js.map +0 -1
- package/dist/src/animation/scaletrack.js +0 -50
- package/dist/src/animation/scaletrack.js.map +0 -1
- package/dist/src/animation/skeleton.js +0 -204
- package/dist/src/animation/skeleton.js.map +0 -1
- package/dist/src/animation/translationtrack.js +0 -50
- package/dist/src/animation/translationtrack.js.map +0 -1
- package/dist/src/app/app.js +0 -129
- package/dist/src/app/app.js.map +0 -1
- package/dist/src/app/inputmgr.js +0 -267
- package/dist/src/app/inputmgr.js.map +0 -1
- package/dist/src/asset/assetmanager.js +0 -404
- package/dist/src/asset/assetmanager.js.map +0 -1
- package/dist/src/asset/builtin.js +0 -337
- package/dist/src/asset/builtin.js.map +0 -1
- package/dist/src/asset/loaders/dds/dds.js +0 -470
- package/dist/src/asset/loaders/dds/dds.js.map +0 -1
- package/dist/src/asset/loaders/dds/dds_loader.js +0 -28
- package/dist/src/asset/loaders/dds/dds_loader.js.map +0 -1
- package/dist/src/asset/loaders/gltf/gltf_loader.js +0 -1265
- package/dist/src/asset/loaders/gltf/gltf_loader.js.map +0 -1
- package/dist/src/asset/loaders/gltf/helpers.js +0 -327
- package/dist/src/asset/loaders/gltf/helpers.js.map +0 -1
- package/dist/src/asset/loaders/hdr/hdr.js +0 -180
- package/dist/src/asset/loaders/hdr/hdr.js.map +0 -1
- package/dist/src/asset/loaders/image/tga_Loader.js +0 -116
- package/dist/src/asset/loaders/image/tga_Loader.js.map +0 -1
- package/dist/src/asset/loaders/image/webimage_loader.js +0 -63
- package/dist/src/asset/loaders/image/webimage_loader.js.map +0 -1
- package/dist/src/asset/loaders/loader.js +0 -45
- package/dist/src/asset/loaders/loader.js.map +0 -1
- package/dist/src/asset/model.js +0 -414
- package/dist/src/asset/model.js.map +0 -1
- package/dist/src/blitter/bilateralblur.js +0 -221
- package/dist/src/blitter/bilateralblur.js.map +0 -1
- package/dist/src/blitter/blitter.js +0 -390
- package/dist/src/blitter/blitter.js.map +0 -1
- package/dist/src/blitter/box.js +0 -118
- package/dist/src/blitter/box.js.map +0 -1
- package/dist/src/blitter/copy.js +0 -22
- package/dist/src/blitter/copy.js.map +0 -1
- package/dist/src/blitter/gaussianblur.js +0 -228
- package/dist/src/blitter/gaussianblur.js.map +0 -1
- package/dist/src/camera/base.js +0 -92
- package/dist/src/camera/base.js.map +0 -1
- package/dist/src/camera/camera.js +0 -1005
- package/dist/src/camera/camera.js.map +0 -1
- package/dist/src/camera/fps.js +0 -238
- package/dist/src/camera/fps.js.map +0 -1
- package/dist/src/camera/orbit.js +0 -245
- package/dist/src/camera/orbit.js.map +0 -1
- package/dist/src/camera/orthocamera.js +0 -167
- package/dist/src/camera/orthocamera.js.map +0 -1
- package/dist/src/camera/perspectivecamera.js +0 -141
- package/dist/src/camera/perspectivecamera.js.map +0 -1
- package/dist/src/index.js +0 -120
- package/dist/src/index.js.map +0 -1
- package/dist/src/material/blinn.js +0 -81
- package/dist/src/material/blinn.js.map +0 -1
- package/dist/src/material/grassmaterial.js +0 -113
- package/dist/src/material/grassmaterial.js.map +0 -1
- package/dist/src/material/lambert.js +0 -92
- package/dist/src/material/lambert.js.map +0 -1
- package/dist/src/material/material.js +0 -301
- package/dist/src/material/material.js.map +0 -1
- package/dist/src/material/meshmaterial.js +0 -704
- package/dist/src/material/meshmaterial.js.map +0 -1
- package/dist/src/material/mixins/albedocolor.js +0 -76
- package/dist/src/material/mixins/albedocolor.js.map +0 -1
- package/dist/src/material/mixins/foliage.js +0 -47
- package/dist/src/material/mixins/foliage.js.map +0 -1
- package/dist/src/material/mixins/lightmodel/blinnphong.js +0 -112
- package/dist/src/material/mixins/lightmodel/blinnphong.js.map +0 -1
- package/dist/src/material/mixins/lightmodel/lambert.js +0 -58
- package/dist/src/material/mixins/lightmodel/lambert.js.map +0 -1
- package/dist/src/material/mixins/lightmodel/pbrmetallicroughness.js +0 -178
- package/dist/src/material/mixins/lightmodel/pbrmetallicroughness.js.map +0 -1
- package/dist/src/material/mixins/lightmodel/pbrspecularglossness.js +0 -139
- package/dist/src/material/mixins/lightmodel/pbrspecularglossness.js.map +0 -1
- package/dist/src/material/mixins/lit.js +0 -476
- package/dist/src/material/mixins/lit.js.map +0 -1
- package/dist/src/material/mixins/pbr/common.js +0 -918
- package/dist/src/material/mixins/pbr/common.js.map +0 -1
- package/dist/src/material/mixins/texture.js +0 -172
- package/dist/src/material/mixins/texture.js.map +0 -1
- package/dist/src/material/mixins/vertexcolor.js +0 -56
- package/dist/src/material/mixins/vertexcolor.js.map +0 -1
- package/dist/src/material/particle.js +0 -178
- package/dist/src/material/particle.js.map +0 -1
- package/dist/src/material/pbrmr.js +0 -97
- package/dist/src/material/pbrmr.js.map +0 -1
- package/dist/src/material/pbrsg.js +0 -97
- package/dist/src/material/pbrsg.js.map +0 -1
- package/dist/src/material/shader/helper.js +0 -1209
- package/dist/src/material/shader/helper.js.map +0 -1
- package/dist/src/material/terrain-cm.js +0 -606
- package/dist/src/material/terrain-cm.js.map +0 -1
- package/dist/src/material/terrainmaterial.js +0 -375
- package/dist/src/material/terrainmaterial.js.map +0 -1
- package/dist/src/material/unlit.js +0 -41
- package/dist/src/material/unlit.js.map +0 -1
- package/dist/src/material/water.js +0 -417
- package/dist/src/material/water.js.map +0 -1
- package/dist/src/posteffect/bloom.js +0 -361
- package/dist/src/posteffect/bloom.js.map +0 -1
- package/dist/src/posteffect/compositor.js +0 -226
- package/dist/src/posteffect/compositor.js.map +0 -1
- package/dist/src/posteffect/fxaa.js +0 -273
- package/dist/src/posteffect/fxaa.js.map +0 -1
- package/dist/src/posteffect/grayscale.js +0 -69
- package/dist/src/posteffect/grayscale.js.map +0 -1
- package/dist/src/posteffect/motionblur.js +0 -96
- package/dist/src/posteffect/motionblur.js.map +0 -1
- package/dist/src/posteffect/posteffect.js +0 -126
- package/dist/src/posteffect/posteffect.js.map +0 -1
- package/dist/src/posteffect/sao.js +0 -324
- package/dist/src/posteffect/sao.js.map +0 -1
- package/dist/src/posteffect/ssr.js +0 -489
- package/dist/src/posteffect/ssr.js.map +0 -1
- package/dist/src/posteffect/taa.js +0 -172
- package/dist/src/posteffect/taa.js.map +0 -1
- package/dist/src/posteffect/tonemap.js +0 -94
- package/dist/src/posteffect/tonemap.js.map +0 -1
- package/dist/src/render/abuffer_oit.js +0 -361
- package/dist/src/render/abuffer_oit.js.map +0 -1
- package/dist/src/render/clipmap.js +0 -851
- package/dist/src/render/clipmap.js.map +0 -1
- package/dist/src/render/cluster_light.js +0 -333
- package/dist/src/render/cluster_light.js.map +0 -1
- package/dist/src/render/cull_visitor.js +0 -187
- package/dist/src/render/cull_visitor.js.map +0 -1
- package/dist/src/render/depthpass.js +0 -68
- package/dist/src/render/depthpass.js.map +0 -1
- package/dist/src/render/drawable_mixin.js +0 -227
- package/dist/src/render/drawable_mixin.js.map +0 -1
- package/dist/src/render/envlight.js +0 -463
- package/dist/src/render/envlight.js.map +0 -1
- package/dist/src/render/fbm_wavegenerator.js +0 -251
- package/dist/src/render/fbm_wavegenerator.js.map +0 -1
- package/dist/src/render/fft_wavegenerator.js +0 -1006
- package/dist/src/render/fft_wavegenerator.js.map +0 -1
- package/dist/src/render/fullscreenquad.js +0 -38
- package/dist/src/render/fullscreenquad.js.map +0 -1
- package/dist/src/render/gerstner_wavegenerator.js +0 -314
- package/dist/src/render/gerstner_wavegenerator.js.map +0 -1
- package/dist/src/render/globalbindgroup_allocator.js +0 -60
- package/dist/src/render/globalbindgroup_allocator.js.map +0 -1
- package/dist/src/render/hzb.js +0 -273
- package/dist/src/render/hzb.js.map +0 -1
- package/dist/src/render/lightpass.js +0 -172
- package/dist/src/render/lightpass.js.map +0 -1
- package/dist/src/render/objectcolorpass.js +0 -51
- package/dist/src/render/objectcolorpass.js.map +0 -1
- package/dist/src/render/primitive.js +0 -364
- package/dist/src/render/primitive.js.map +0 -1
- package/dist/src/render/render_queue.js +0 -467
- package/dist/src/render/render_queue.js.map +0 -1
- package/dist/src/render/renderbundle_wrapper.js +0 -152
- package/dist/src/render/renderbundle_wrapper.js.map +0 -1
- package/dist/src/render/renderer.js +0 -455
- package/dist/src/render/renderer.js.map +0 -1
- package/dist/src/render/renderpass.js +0 -200
- package/dist/src/render/renderpass.js.map +0 -1
- package/dist/src/render/shadowmap_pass.js +0 -56
- package/dist/src/render/shadowmap_pass.js.map +0 -1
- package/dist/src/render/sky.js +0 -1103
- package/dist/src/render/sky.js.map +0 -1
- package/dist/src/render/weightedblended_oit.js +0 -168
- package/dist/src/render/weightedblended_oit.js.map +0 -1
- package/dist/src/scene/batchgroup.js +0 -162
- package/dist/src/scene/batchgroup.js.map +0 -1
- package/dist/src/scene/environment.js +0 -209
- package/dist/src/scene/environment.js.map +0 -1
- package/dist/src/scene/graph_node.js +0 -72
- package/dist/src/scene/graph_node.js.map +0 -1
- package/dist/src/scene/light.js +0 -416
- package/dist/src/scene/light.js.map +0 -1
- package/dist/src/scene/mesh.js +0 -341
- package/dist/src/scene/mesh.js.map +0 -1
- package/dist/src/scene/octree.js +0 -649
- package/dist/src/scene/octree.js.map +0 -1
- package/dist/src/scene/particlesys.js +0 -738
- package/dist/src/scene/particlesys.js.map +0 -1
- package/dist/src/scene/raycast_visitor.js +0 -103
- package/dist/src/scene/raycast_visitor.js.map +0 -1
- package/dist/src/scene/scene.js +0 -284
- package/dist/src/scene/scene.js.map +0 -1
- package/dist/src/scene/scene_node.js +0 -732
- package/dist/src/scene/scene_node.js.map +0 -1
- package/dist/src/scene/terrain/grass.js +0 -278
- package/dist/src/scene/terrain/grass.js.map +0 -1
- package/dist/src/scene/terrain/heightfield.js +0 -475
- package/dist/src/scene/terrain/heightfield.js.map +0 -1
- package/dist/src/scene/terrain/patch.js +0 -530
- package/dist/src/scene/terrain/patch.js.map +0 -1
- package/dist/src/scene/terrain/quadtree.js +0 -461
- package/dist/src/scene/terrain/quadtree.js.map +0 -1
- package/dist/src/scene/terrain/terrain.js +0 -246
- package/dist/src/scene/terrain/terrain.js.map +0 -1
- package/dist/src/scene/terrain-cm/grass.js +0 -594
- package/dist/src/scene/terrain-cm/grass.js.map +0 -1
- package/dist/src/scene/terrain-cm/grassmaterial.js +0 -159
- package/dist/src/scene/terrain-cm/grassmaterial.js.map +0 -1
- package/dist/src/scene/terrain-cm/terrain-cm.js +0 -538
- package/dist/src/scene/terrain-cm/terrain-cm.js.map +0 -1
- package/dist/src/scene/water.js +0 -374
- package/dist/src/scene/water.js.map +0 -1
- package/dist/src/shaders/atmosphere.js +0 -957
- package/dist/src/shaders/atmosphere.js.map +0 -1
- package/dist/src/shaders/fog.js +0 -112
- package/dist/src/shaders/fog.js.map +0 -1
- package/dist/src/shaders/misc.js +0 -266
- package/dist/src/shaders/misc.js.map +0 -1
- package/dist/src/shaders/noise.js +0 -222
- package/dist/src/shaders/noise.js.map +0 -1
- package/dist/src/shaders/pbr.js +0 -51
- package/dist/src/shaders/pbr.js.map +0 -1
- package/dist/src/shaders/shadow.js +0 -636
- package/dist/src/shaders/shadow.js.map +0 -1
- package/dist/src/shaders/ssr.js +0 -490
- package/dist/src/shaders/ssr.js.map +0 -1
- package/dist/src/shaders/temporal.js +0 -215
- package/dist/src/shaders/temporal.js.map +0 -1
- package/dist/src/shaders/water.js +0 -756
- package/dist/src/shaders/water.js.map +0 -1
- package/dist/src/shadow/esm.js +0 -237
- package/dist/src/shadow/esm.js.map +0 -1
- package/dist/src/shadow/pcf_opt.js +0 -181
- package/dist/src/shadow/pcf_opt.js.map +0 -1
- package/dist/src/shadow/pcf_pd.js +0 -189
- package/dist/src/shadow/pcf_pd.js.map +0 -1
- package/dist/src/shadow/shader.js +0 -37
- package/dist/src/shadow/shader.js.map +0 -1
- package/dist/src/shadow/shadow_impl.js +0 -15
- package/dist/src/shadow/shadow_impl.js.map +0 -1
- package/dist/src/shadow/shadowmapper.js +0 -790
- package/dist/src/shadow/shadowmapper.js.map +0 -1
- package/dist/src/shadow/ssm.js +0 -159
- package/dist/src/shadow/ssm.js.map +0 -1
- package/dist/src/shadow/vsm.js +0 -297
- package/dist/src/shadow/vsm.js.map +0 -1
- package/dist/src/shapes/box.js +0 -386
- package/dist/src/shapes/box.js.map +0 -1
- package/dist/src/shapes/cylinder.js +0 -125
- package/dist/src/shapes/cylinder.js.map +0 -1
- package/dist/src/shapes/plane.js +0 -88
- package/dist/src/shapes/plane.js.map +0 -1
- package/dist/src/shapes/shape.js +0 -87
- package/dist/src/shapes/shape.js.map +0 -1
- package/dist/src/shapes/sphere.js +0 -114
- package/dist/src/shapes/sphere.js.map +0 -1
- package/dist/src/shapes/tetrahedron.js +0 -188
- package/dist/src/shapes/tetrahedron.js.map +0 -1
- package/dist/src/shapes/torus.js +0 -111
- package/dist/src/shapes/torus.js.map +0 -1
- package/dist/src/utility/aabbtree.js +0 -400
- package/dist/src/utility/aabbtree.js.map +0 -1
- package/dist/src/utility/bounding_volume.js +0 -29
- package/dist/src/utility/bounding_volume.js.map +0 -1
- package/dist/src/utility/debug.js +0 -28
- package/dist/src/utility/debug.js.map +0 -1
- package/dist/src/utility/draco/decoder.js +0 -116
- package/dist/src/utility/draco/decoder.js.map +0 -1
- package/dist/src/utility/misc.js +0 -105
- package/dist/src/utility/misc.js.map +0 -1
- package/dist/src/utility/panorama.js +0 -163
- package/dist/src/utility/panorama.js.map +0 -1
- package/dist/src/utility/pmrem.js +0 -354
- package/dist/src/utility/pmrem.js.map +0 -1
- package/dist/src/utility/rendermipmap.js +0 -115
- package/dist/src/utility/rendermipmap.js.map +0 -1
- package/dist/src/utility/serialization/json.js +0 -402
- package/dist/src/utility/serialization/json.js.map +0 -1
- package/dist/src/utility/serialization/manager.js +0 -623
- package/dist/src/utility/serialization/manager.js.map +0 -1
- package/dist/src/utility/serialization/scene/animation.js +0 -248
- package/dist/src/utility/serialization/scene/animation.js.map +0 -1
- package/dist/src/utility/serialization/scene/batch.js +0 -59
- package/dist/src/utility/serialization/scene/batch.js.map +0 -1
- package/dist/src/utility/serialization/scene/camera.js +0 -790
- package/dist/src/utility/serialization/scene/camera.js.map +0 -1
- package/dist/src/utility/serialization/scene/common.js +0 -222
- package/dist/src/utility/serialization/scene/common.js.map +0 -1
- package/dist/src/utility/serialization/scene/light.js +0 -575
- package/dist/src/utility/serialization/scene/light.js.map +0 -1
- package/dist/src/utility/serialization/scene/material.js +0 -1111
- package/dist/src/utility/serialization/scene/material.js.map +0 -1
- package/dist/src/utility/serialization/scene/mesh.js +0 -148
- package/dist/src/utility/serialization/scene/mesh.js.map +0 -1
- package/dist/src/utility/serialization/scene/misc.js +0 -39
- package/dist/src/utility/serialization/scene/misc.js.map +0 -1
- package/dist/src/utility/serialization/scene/node.js +0 -451
- package/dist/src/utility/serialization/scene/node.js.map +0 -1
- package/dist/src/utility/serialization/scene/particle.js +0 -425
- package/dist/src/utility/serialization/scene/particle.js.map +0 -1
- package/dist/src/utility/serialization/scene/primitive.js +0 -692
- package/dist/src/utility/serialization/scene/primitive.js.map +0 -1
- package/dist/src/utility/serialization/scene/scene.js +0 -704
- package/dist/src/utility/serialization/scene/scene.js.map +0 -1
- package/dist/src/utility/serialization/scene/terrain.js +0 -488
- package/dist/src/utility/serialization/scene/terrain.js.map +0 -1
- package/dist/src/utility/serialization/scene/water.js +0 -465
- package/dist/src/utility/serialization/scene/water.js.map +0 -1
- package/dist/src/utility/shprojector.js +0 -297
- package/dist/src/utility/shprojector.js.map +0 -1
- package/dist/src/utility/textures/ggxlut.js +0 -213
- package/dist/src/utility/textures/ggxlut.js.map +0 -1
- package/dist/src/utility/textures/gradientnoise.js +0 -62
- package/dist/src/utility/textures/gradientnoise.js.map +0 -1
- package/dist/src/utility/textures/randomnoise.js +0 -41
- package/dist/src/utility/textures/randomnoise.js.map +0 -1
- package/dist/src/values.js +0 -162
- package/dist/src/values.js.map +0 -1
- package/dist/utility/blueprint/material/common.js +0 -7
- package/dist/utility/blueprint/material/common.js.map +0 -1
- package/dist/utility/serialization/blueprint/constants.js +0 -255
- package/dist/utility/serialization/blueprint/constants.js.map +0 -1
- package/dist/utility/serialization/blueprint/material/constants.js +0 -203
- package/dist/utility/serialization/blueprint/material/constants.js.map +0 -1
- package/dist/utility/serialization/blueprint/material/texture.js +0 -165
- package/dist/utility/serialization/blueprint/material/texture.js.map +0 -1
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { Vector3, Quaternion } from '@zephyr3d/base';
|
|
2
|
+
import { IKSolver } from './ik_solver.js';
|
|
3
|
+
import { IKUtils } from './ik_utils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* FABRIK (Forward And Backward Reaching Inverse Kinematics) solver.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* FABRIK is an iterative IK algorithm that alternates between:
|
|
10
|
+
* 1. Forward pass: Move from end effector to root, pulling joints toward target
|
|
11
|
+
* 2. Backward pass: Move from root to end effector, restoring root position
|
|
12
|
+
*
|
|
13
|
+
* Supports multiple pole vectors to control the bending direction of different joints.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/ class FABRIKSolver extends IKSolver {
|
|
17
|
+
/** Map of joint index to pole vector configuration */ _poleVectors;
|
|
18
|
+
/** Twist constraints for each joint (indexed by joint index) */ _twistConstraints;
|
|
19
|
+
/**
|
|
20
|
+
* Create a FABRIK solver.
|
|
21
|
+
*
|
|
22
|
+
* @param chain - The IK chain to solve
|
|
23
|
+
* @param maxIterations - Maximum number of iterations (default: 15)
|
|
24
|
+
* @param tolerance - Convergence tolerance in world units (default: 0.001)
|
|
25
|
+
*/ constructor(chain, maxIterations = 15, tolerance = 0.001){
|
|
26
|
+
super(chain, maxIterations, tolerance);
|
|
27
|
+
this._poleVectors = new Map();
|
|
28
|
+
this._twistConstraints = new Map();
|
|
29
|
+
// Set default twist constraints for all joints
|
|
30
|
+
for(let i = 0; i < chain.joints.length - 1; i++){
|
|
31
|
+
// Middle joints have more restrictive twist limits
|
|
32
|
+
const isMiddleJoint = i > 0 && i < chain.joints.length - 2;
|
|
33
|
+
this._twistConstraints.set(i, {
|
|
34
|
+
minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,
|
|
35
|
+
maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,
|
|
36
|
+
smoothFactor: 0.3
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set twist constraint for a specific joint.
|
|
42
|
+
*
|
|
43
|
+
* @param jointIndex - Index of the joint
|
|
44
|
+
* @param minTwist - Minimum twist angle in radians
|
|
45
|
+
* @param maxTwist - Maximum twist angle in radians
|
|
46
|
+
* @param smoothFactor - Smoothing factor [0-1] (default: 0.3)
|
|
47
|
+
*/ setTwistConstraint(jointIndex, minTwist, maxTwist, smoothFactor = 0.3) {
|
|
48
|
+
if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {
|
|
49
|
+
throw new Error(`Invalid joint index: ${jointIndex}`);
|
|
50
|
+
}
|
|
51
|
+
this._twistConstraints.set(jointIndex, {
|
|
52
|
+
minTwist,
|
|
53
|
+
maxTwist,
|
|
54
|
+
smoothFactor: Math.max(0, Math.min(1, smoothFactor))
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get twist constraint for a specific joint.
|
|
59
|
+
*
|
|
60
|
+
* @param jointIndex - Index of the joint
|
|
61
|
+
* @returns Twist constraint or undefined if not set
|
|
62
|
+
*/ getTwistConstraint(jointIndex) {
|
|
63
|
+
return this._twistConstraints.get(jointIndex);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Remove twist constraint for a specific joint.
|
|
67
|
+
*
|
|
68
|
+
* @param jointIndex - Index of the joint
|
|
69
|
+
* @returns True if a constraint was removed
|
|
70
|
+
*/ removeTwistConstraint(jointIndex) {
|
|
71
|
+
return this._twistConstraints.delete(jointIndex);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Clear all twist constraints.
|
|
75
|
+
*/ clearTwistConstraints() {
|
|
76
|
+
this._twistConstraints.clear();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set pole vector for a specific joint.
|
|
80
|
+
*
|
|
81
|
+
* @param jointIndex - Index of the joint to apply pole vector to
|
|
82
|
+
* @param poleVector - Pole vector position in world space
|
|
83
|
+
* @param weight - Weight of the pole vector constraint (0-1, default: 1)
|
|
84
|
+
*/ setPoleVector(jointIndex, poleVector, weight = 1) {
|
|
85
|
+
if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {
|
|
86
|
+
throw new Error(`Invalid joint index: ${jointIndex}`);
|
|
87
|
+
}
|
|
88
|
+
this._poleVectors.set(jointIndex, {
|
|
89
|
+
position: poleVector.clone(),
|
|
90
|
+
weight: Math.max(0, Math.min(1, weight))
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Remove pole vector for a specific joint.
|
|
95
|
+
*
|
|
96
|
+
* @param jointIndex - Index of the joint to remove pole vector from
|
|
97
|
+
* @returns True if a pole vector was removed, false if none existed
|
|
98
|
+
*/ removePoleVector(jointIndex) {
|
|
99
|
+
return this._poleVectors.delete(jointIndex);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Clear all pole vectors.
|
|
103
|
+
*/ clearPoleVectors() {
|
|
104
|
+
this._poleVectors.clear();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get pole vector configuration for a specific joint.
|
|
108
|
+
*
|
|
109
|
+
* @param jointIndex - Index of the joint
|
|
110
|
+
* @returns Pole vector configuration or undefined if not set
|
|
111
|
+
*/ getPoleVector(jointIndex) {
|
|
112
|
+
const config = this._poleVectors.get(jointIndex);
|
|
113
|
+
if (config) {
|
|
114
|
+
return {
|
|
115
|
+
position: config.position.clone(),
|
|
116
|
+
weight: config.weight
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if a joint has a pole vector.
|
|
123
|
+
*
|
|
124
|
+
* @param jointIndex - Index of the joint
|
|
125
|
+
* @returns True if the joint has a pole vector
|
|
126
|
+
*/ hasPoleVector(jointIndex) {
|
|
127
|
+
return this._poleVectors.has(jointIndex);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Solve the IK chain to reach the target position using FABRIK algorithm.
|
|
131
|
+
*
|
|
132
|
+
* @param target - Target position for the end effector
|
|
133
|
+
* @returns True if converged within tolerance, false otherwise
|
|
134
|
+
*/ solve(target) {
|
|
135
|
+
const joints = this._chain.joints;
|
|
136
|
+
// Update joint positions from scene nodes before solving
|
|
137
|
+
this._chain.updateFromNodes();
|
|
138
|
+
// Store original positions
|
|
139
|
+
this._chain.storeOriginalPositions();
|
|
140
|
+
const rootPos = joints[0].originalPosition.clone();
|
|
141
|
+
// Check if target is reachable
|
|
142
|
+
const distToTarget = Vector3.distance(rootPos, target);
|
|
143
|
+
if (distToTarget > this._chain.totalLength) {
|
|
144
|
+
// Target unreachable - stretch chain toward target
|
|
145
|
+
this._stretchToward(target);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
let converged = false;
|
|
149
|
+
for(let iteration = 0; iteration < this._maxIterations; iteration++){
|
|
150
|
+
// Check convergence
|
|
151
|
+
const distToEnd = Vector3.distance(joints[joints.length - 1].position, target);
|
|
152
|
+
if (distToEnd < this._tolerance) {
|
|
153
|
+
converged = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
// Forward pass: end effector to root
|
|
157
|
+
this._forwardPass(target);
|
|
158
|
+
// Backward pass: root to end effector (constraints are applied within the pass)
|
|
159
|
+
this._backwardPass(rootPos);
|
|
160
|
+
}
|
|
161
|
+
return converged;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Apply the solved joint positions to scene nodes as rotations.
|
|
165
|
+
*
|
|
166
|
+
* @param weight - Blend weight (0 = original, 1 = full IK, default: 1)
|
|
167
|
+
*/ applyToNodes(weight = 1) {
|
|
168
|
+
const joints = this._chain.joints;
|
|
169
|
+
for(let i = 0; i < joints.length - 1; i++){
|
|
170
|
+
const joint = joints[i];
|
|
171
|
+
const nextJoint = joints[i + 1];
|
|
172
|
+
// Calculate direction from current joint to next joint in world space
|
|
173
|
+
const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());
|
|
174
|
+
const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());
|
|
175
|
+
const originalDirNorm = Vector3.normalize(originalDir, new Vector3());
|
|
176
|
+
const newDirNorm = Vector3.normalize(newDir, new Vector3());
|
|
177
|
+
// Calculate basic rotation
|
|
178
|
+
const deltaRotation = new Quaternion();
|
|
179
|
+
IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);
|
|
180
|
+
// Calculate new world rotation
|
|
181
|
+
let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());
|
|
182
|
+
// Apply swing-twist constraint to prevent over-rotation
|
|
183
|
+
const swing = new Quaternion();
|
|
184
|
+
const twist = new Quaternion();
|
|
185
|
+
worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);
|
|
186
|
+
// Get twist angle
|
|
187
|
+
let twistAngle = twist.getTwistAngle(newDirNorm);
|
|
188
|
+
// Get twist constraint for this joint
|
|
189
|
+
const constraint = this._twistConstraints.get(i);
|
|
190
|
+
if (constraint) {
|
|
191
|
+
// Clamp and smooth twist
|
|
192
|
+
twistAngle = IKUtils.clampAndSmoothTwist(twistAngle, joint.previousTwist, constraint.minTwist, constraint.maxTwist, constraint.smoothFactor);
|
|
193
|
+
}
|
|
194
|
+
// Store for next frame
|
|
195
|
+
joint.previousTwist = twistAngle;
|
|
196
|
+
// Reconstruct rotation from clamped twist: Q = Twist * Swing
|
|
197
|
+
const clampedTwist = Quaternion.fromAxisAngle(newDirNorm, twistAngle);
|
|
198
|
+
worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
|
|
199
|
+
// Blend with original rotation based on weight
|
|
200
|
+
if (weight < 1) {
|
|
201
|
+
Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);
|
|
202
|
+
}
|
|
203
|
+
// Store this frame's world rotation
|
|
204
|
+
if (!joint.previousIKRotation) {
|
|
205
|
+
joint.previousIKRotation = worldRotation.clone();
|
|
206
|
+
} else {
|
|
207
|
+
joint.previousIKRotation.set(worldRotation);
|
|
208
|
+
}
|
|
209
|
+
// Convert world rotation to local rotation (relative to parent)
|
|
210
|
+
if (joint.node.parent) {
|
|
211
|
+
const parentWorldRotation = new Quaternion();
|
|
212
|
+
joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);
|
|
213
|
+
// localRotation = conjugate(parentWorldRotation) * worldRotation
|
|
214
|
+
const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());
|
|
215
|
+
const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());
|
|
216
|
+
joint.node.rotation = localRotation;
|
|
217
|
+
} else {
|
|
218
|
+
// Root node has no parent, world rotation is local rotation
|
|
219
|
+
joint.node.rotation = worldRotation;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Forward pass: move from end effector toward root.
|
|
225
|
+
* Each joint is pulled toward its child, maintaining bone length.
|
|
226
|
+
* Constraints are applied immediately after each joint adjustment.
|
|
227
|
+
*
|
|
228
|
+
* @param target - Target position for end effector
|
|
229
|
+
*/ _forwardPass(target) {
|
|
230
|
+
const joints = this._chain.joints;
|
|
231
|
+
// Set end effector to target
|
|
232
|
+
joints[joints.length - 1].position.set(target);
|
|
233
|
+
// Move backward through chain
|
|
234
|
+
for(let i = joints.length - 2; i >= 0; i--){
|
|
235
|
+
const joint = joints[i];
|
|
236
|
+
const childJoint = joints[i + 1];
|
|
237
|
+
// Calculate direction from child to current joint
|
|
238
|
+
const direction = Vector3.sub(joint.position, childJoint.position, new Vector3());
|
|
239
|
+
const distance = direction.magnitude;
|
|
240
|
+
if (distance > 0.000001) {
|
|
241
|
+
direction.scaleBy(1 / distance);
|
|
242
|
+
// Place joint at correct distance from child
|
|
243
|
+
Vector3.scale(direction, joint.boneLength, direction);
|
|
244
|
+
Vector3.add(childJoint.position, direction, joint.position);
|
|
245
|
+
}
|
|
246
|
+
// Apply constraints immediately after adjusting this joint
|
|
247
|
+
// This ensures constraints are integrated into the FABRIK algorithm
|
|
248
|
+
if (i > 0) {
|
|
249
|
+
// Apply constraints for joint i (not for root joint)
|
|
250
|
+
this._applyConstraintsForJoint(i);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Backward pass: move from root toward end effector.
|
|
256
|
+
* Each joint is pulled toward its parent, maintaining bone length.
|
|
257
|
+
* Constraints are applied immediately after each joint adjustment.
|
|
258
|
+
*
|
|
259
|
+
* @param rootPos - Original root position to restore
|
|
260
|
+
*/ _backwardPass(rootPos) {
|
|
261
|
+
const joints = this._chain.joints;
|
|
262
|
+
// Restore root position
|
|
263
|
+
joints[0].position.set(rootPos);
|
|
264
|
+
// Move forward through chain
|
|
265
|
+
for(let i = 0; i < joints.length - 1; i++){
|
|
266
|
+
const joint = joints[i];
|
|
267
|
+
const childJoint = joints[i + 1];
|
|
268
|
+
// Calculate direction from current joint to child
|
|
269
|
+
const direction = Vector3.sub(childJoint.position, joint.position, new Vector3());
|
|
270
|
+
const distance = direction.magnitude;
|
|
271
|
+
if (distance > 0.000001) {
|
|
272
|
+
direction.scaleBy(1 / distance);
|
|
273
|
+
// Place child at correct distance from current joint
|
|
274
|
+
Vector3.scale(direction, joint.boneLength, direction);
|
|
275
|
+
Vector3.add(joint.position, direction, childJoint.position);
|
|
276
|
+
}
|
|
277
|
+
// Apply constraints immediately after adjusting this joint
|
|
278
|
+
// This ensures constraints are integrated into the FABRIK algorithm
|
|
279
|
+
this._applyConstraintsForJoint(i + 1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Apply constraints for a specific joint.
|
|
284
|
+
* This is called during the FABRIK passes to integrate constraints into the algorithm.
|
|
285
|
+
*
|
|
286
|
+
* @param jointIndex - Index of the joint to apply constraints to
|
|
287
|
+
*/ _applyConstraintsForJoint(jointIndex) {
|
|
288
|
+
const constraints = this._chain.constraints;
|
|
289
|
+
// Apply non-pole-vector constraints
|
|
290
|
+
// IKPoleVectorConstraint is deprecated and ignored in favor of built-in pole vectors
|
|
291
|
+
for (const constraint of constraints){
|
|
292
|
+
if (constraint.jointIndex === jointIndex) {
|
|
293
|
+
// Skip IKPoleVectorConstraint - use built-in pole vectors instead
|
|
294
|
+
if (constraint.constructor.name === 'IKPoleVectorConstraint') {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
constraint.apply(this._chain.joints);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Apply built-in pole vector if configured for this joint
|
|
301
|
+
const poleConfig = this._poleVectors.get(jointIndex);
|
|
302
|
+
if (poleConfig && poleConfig.weight > 0.001) {
|
|
303
|
+
this._applyPoleVectorTwist(jointIndex, poleConfig.position, poleConfig.weight);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Apply pole vector twist to a specific joint.
|
|
308
|
+
*
|
|
309
|
+
* @remarks
|
|
310
|
+
* This method adjusts the joint position to align with the pole vector.
|
|
311
|
+
* It uses the same algorithm as IKPoleVectorConstraint but is integrated
|
|
312
|
+
* into the solver for better performance and control.
|
|
313
|
+
*
|
|
314
|
+
* @param jointIndex - Index of the pole joint
|
|
315
|
+
* @param poleVector - Pole vector position in world space
|
|
316
|
+
* @param weight - Weight of the pole vector constraint (0-1)
|
|
317
|
+
*/ _applyPoleVectorTwist(jointIndex, poleVector, weight) {
|
|
318
|
+
const joints = this._chain.joints;
|
|
319
|
+
// We need at least 3 joints to apply pole vector (parent, pole joint, child)
|
|
320
|
+
if (jointIndex < 1 || jointIndex >= joints.length - 1) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const parentJoint = joints[jointIndex - 1];
|
|
324
|
+
const currentJoint = joints[jointIndex];
|
|
325
|
+
const childJoint = joints[jointIndex + 1];
|
|
326
|
+
const parentPos = parentJoint.position;
|
|
327
|
+
const currentPos = currentJoint.position;
|
|
328
|
+
const childPos = childJoint.position;
|
|
329
|
+
// Calculate the plane defined by parent, child, and pole vector
|
|
330
|
+
// Vector from parent to child (the "line" we're bending around)
|
|
331
|
+
const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());
|
|
332
|
+
const lineLength = parentToChild.magnitude;
|
|
333
|
+
if (lineLength < 0.000001) {
|
|
334
|
+
return; // Parent and child are at same position
|
|
335
|
+
}
|
|
336
|
+
const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());
|
|
337
|
+
// Project current joint onto the parent-child line
|
|
338
|
+
const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());
|
|
339
|
+
const projectionLength = Vector3.dot(parentToCurrent, lineDir);
|
|
340
|
+
const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());
|
|
341
|
+
Vector3.add(parentPos, projectionPoint, projectionPoint);
|
|
342
|
+
// Vector from projection point to current joint (perpendicular to line)
|
|
343
|
+
const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());
|
|
344
|
+
const perpLength = perpendicular.magnitude;
|
|
345
|
+
if (perpLength < 0.000001) {
|
|
346
|
+
return; // Current joint is on the line
|
|
347
|
+
}
|
|
348
|
+
// Calculate desired direction toward pole vector
|
|
349
|
+
const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());
|
|
350
|
+
const poleProjectionLength = Vector3.dot(parentToPole, lineDir);
|
|
351
|
+
const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());
|
|
352
|
+
Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);
|
|
353
|
+
// Direction from projection to pole (perpendicular to line)
|
|
354
|
+
const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());
|
|
355
|
+
const poleDirLength = poleDirection.magnitude;
|
|
356
|
+
if (poleDirLength < 0.000001) {
|
|
357
|
+
return; // Pole is on the line
|
|
358
|
+
}
|
|
359
|
+
poleDirection.scaleBy(1 / poleDirLength);
|
|
360
|
+
// Calculate new position for current joint
|
|
361
|
+
// Keep the same distance from the line, but rotate toward pole direction
|
|
362
|
+
const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());
|
|
363
|
+
const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());
|
|
364
|
+
// Apply weight (blend between original and constrained position)
|
|
365
|
+
if (weight < 0.999) {
|
|
366
|
+
const blended = new Vector3();
|
|
367
|
+
blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;
|
|
368
|
+
blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;
|
|
369
|
+
blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;
|
|
370
|
+
currentJoint.position.set(blended);
|
|
371
|
+
} else {
|
|
372
|
+
currentJoint.position.set(newPosition);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Stretch the chain toward an unreachable target.
|
|
377
|
+
* All joints are aligned in a straight line toward the target.
|
|
378
|
+
*
|
|
379
|
+
* @param target - Unreachable target position
|
|
380
|
+
*/ _stretchToward(target) {
|
|
381
|
+
const joints = this._chain.joints;
|
|
382
|
+
const rootPos = joints[0].originalPosition;
|
|
383
|
+
// Calculate direction from root to target
|
|
384
|
+
const direction = Vector3.sub(target, rootPos, new Vector3()).inplaceNormalize();
|
|
385
|
+
// Place each joint along the direction at its bone length
|
|
386
|
+
let currentPos = rootPos.clone();
|
|
387
|
+
for(let i = 0; i < joints.length; i++){
|
|
388
|
+
joints[i].position.set(currentPos);
|
|
389
|
+
if (i < joints.length - 1) {
|
|
390
|
+
const offset = Vector3.scale(direction, joints[i].boneLength, new Vector3());
|
|
391
|
+
currentPos.addBy(offset);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export { FABRIKSolver };
|
|
398
|
+
//# sourceMappingURL=fabrik_solver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fabrik_solver.js","sources":["../../../src/animation/ik/fabrik_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 * Pole vector configuration for a specific joint.\r\n */\r\ninterface PoleVectorConfig {\r\n /** Pole vector position in world space */\r\n position: Vector3;\r\n /** Weight of the pole vector constraint (0-1) */\r\n weight: number;\r\n}\r\n\r\n/**\r\n * FABRIK (Forward And Backward Reaching Inverse Kinematics) solver.\r\n *\r\n * @remarks\r\n * FABRIK is an iterative IK algorithm that alternates between:\r\n * 1. Forward pass: Move from end effector to root, pulling joints toward target\r\n * 2. Backward pass: Move from root to end effector, restoring root position\r\n *\r\n * Supports multiple pole vectors to control the bending direction of different joints.\r\n *\r\n * @public\r\n */\r\nexport class FABRIKSolver extends IKSolver {\r\n /** Map of joint index to pole vector configuration */\r\n private _poleVectors: Map<number, PoleVectorConfig>;\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 FABRIK solver.\r\n *\r\n * @param chain - The IK chain to solve\r\n * @param maxIterations - Maximum number of iterations (default: 15)\r\n * @param tolerance - Convergence tolerance in world units (default: 0.001)\r\n */\r\n constructor(chain: IKChain, maxIterations = 15, tolerance = 0.001) {\r\n super(chain, maxIterations, tolerance);\r\n this._poleVectors = new Map();\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints for all joints\r\n for (let i = 0; i < chain.joints.length - 1; i++) {\r\n // Middle joints have more restrictive twist limits\r\n const isMiddleJoint = i > 0 && i < chain.joints.length - 2;\r\n this._twistConstraints.set(i, {\r\n minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,\r\n maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,\r\n smoothFactor: 0.3\r\n });\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\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 * Set pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply pole vector to\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n setPoleVector(jointIndex: number, poleVector: Vector3, weight = 1): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._poleVectors.set(jointIndex, {\r\n position: poleVector.clone(),\r\n weight: Math.max(0, Math.min(1, weight))\r\n });\r\n }\r\n\r\n /**\r\n * Remove pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to remove pole vector from\r\n * @returns True if a pole vector was removed, false if none existed\r\n */\r\n removePoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all pole vectors.\r\n */\r\n clearPoleVectors(): void {\r\n this._poleVectors.clear();\r\n }\r\n\r\n /**\r\n * Get pole vector configuration for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Pole vector configuration or undefined if not set\r\n */\r\n getPoleVector(jointIndex: number): { position: Vector3; weight: number } | undefined {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config) {\r\n return {\r\n position: config.position.clone(),\r\n weight: config.weight\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Check if a joint has a pole vector.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if the joint has a pole vector\r\n */\r\n hasPoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.has(jointIndex);\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using FABRIK algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if converged within tolerance, false otherwise\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 rootPos = joints[0].originalPosition.clone();\r\n\r\n // Check if target is reachable\r\n const distToTarget = Vector3.distance(rootPos, target);\r\n if (distToTarget > this._chain.totalLength) {\r\n // Target unreachable - stretch chain toward target\r\n this._stretchToward(target);\r\n return false;\r\n }\r\n\r\n let converged = false;\r\n for (let iteration = 0; iteration < this._maxIterations; iteration++) {\r\n // Check convergence\r\n const distToEnd = Vector3.distance(joints[joints.length - 1].position, target);\r\n if (distToEnd < this._tolerance) {\r\n converged = true;\r\n break;\r\n }\r\n\r\n // Forward pass: end effector to root\r\n this._forwardPass(target);\r\n\r\n // Backward pass: root to end effector (constraints are applied within the pass)\r\n this._backwardPass(rootPos);\r\n }\r\n\r\n return converged;\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 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 const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = twist.getTwistAngle(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 = Quaternion.fromAxisAngle(newDirNorm, twistAngle);\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\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 * Forward pass: move from end effector toward root.\r\n * Each joint is pulled toward its child, maintaining bone length.\r\n * Constraints are applied immediately after each joint adjustment.\r\n *\r\n * @param target - Target position for end effector\r\n */\r\n private _forwardPass(target: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Set end effector to target\r\n joints[joints.length - 1].position.set(target);\r\n\r\n // Move backward through chain\r\n for (let i = joints.length - 2; i >= 0; i--) {\r\n const joint = joints[i];\r\n const childJoint = joints[i + 1];\r\n\r\n // Calculate direction from child to current joint\r\n const direction = Vector3.sub(joint.position, childJoint.position, new Vector3());\r\n const distance = direction.magnitude;\r\n\r\n if (distance > 0.000001) {\r\n direction.scaleBy(1 / distance);\r\n // Place joint at correct distance from child\r\n Vector3.scale(direction, joint.boneLength, direction);\r\n Vector3.add(childJoint.position, direction, joint.position);\r\n }\r\n\r\n // Apply constraints immediately after adjusting this joint\r\n // This ensures constraints are integrated into the FABRIK algorithm\r\n if (i > 0) {\r\n // Apply constraints for joint i (not for root joint)\r\n this._applyConstraintsForJoint(i);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Backward pass: move from root toward end effector.\r\n * Each joint is pulled toward its parent, maintaining bone length.\r\n * Constraints are applied immediately after each joint adjustment.\r\n *\r\n * @param rootPos - Original root position to restore\r\n */\r\n private _backwardPass(rootPos: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Restore root position\r\n joints[0].position.set(rootPos);\r\n\r\n // Move forward through chain\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const childJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to child\r\n const direction = Vector3.sub(childJoint.position, joint.position, new Vector3());\r\n const distance = direction.magnitude;\r\n\r\n if (distance > 0.000001) {\r\n direction.scaleBy(1 / distance);\r\n // Place child at correct distance from current joint\r\n Vector3.scale(direction, joint.boneLength, direction);\r\n Vector3.add(joint.position, direction, childJoint.position);\r\n }\r\n\r\n // Apply constraints immediately after adjusting this joint\r\n // This ensures constraints are integrated into the FABRIK algorithm\r\n this._applyConstraintsForJoint(i + 1);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraints for a specific joint.\r\n * This is called during the FABRIK passes to integrate constraints into the algorithm.\r\n *\r\n * @param jointIndex - Index of the joint to apply constraints to\r\n */\r\n private _applyConstraintsForJoint(jointIndex: number): void {\r\n const constraints = this._chain.constraints;\r\n\r\n // Apply non-pole-vector constraints\r\n // IKPoleVectorConstraint is deprecated and ignored in favor of built-in pole vectors\r\n for (const constraint of constraints) {\r\n if (constraint.jointIndex === jointIndex) {\r\n // Skip IKPoleVectorConstraint - use built-in pole vectors instead\r\n if (constraint.constructor.name === 'IKPoleVectorConstraint') {\r\n continue;\r\n }\r\n constraint.apply(this._chain.joints);\r\n }\r\n }\r\n\r\n // Apply built-in pole vector if configured for this joint\r\n const poleConfig = this._poleVectors.get(jointIndex);\r\n if (poleConfig && poleConfig.weight > 0.001) {\r\n this._applyPoleVectorTwist(jointIndex, poleConfig.position, poleConfig.weight);\r\n }\r\n }\r\n\r\n /**\r\n * Apply pole vector twist to a specific joint.\r\n *\r\n * @remarks\r\n * This method adjusts the joint position to align with the pole vector.\r\n * It uses the same algorithm as IKPoleVectorConstraint but is integrated\r\n * into the solver for better performance and control.\r\n *\r\n * @param jointIndex - Index of the pole joint\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1)\r\n */\r\n private _applyPoleVectorTwist(jointIndex: number, poleVector: Vector3, weight: number): void {\r\n const joints = this._chain.joints;\r\n\r\n // We need at least 3 joints to apply pole vector (parent, pole joint, child)\r\n if (jointIndex < 1 || jointIndex >= joints.length - 1) {\r\n return;\r\n }\r\n\r\n const parentJoint = joints[jointIndex - 1];\r\n const currentJoint = joints[jointIndex];\r\n const childJoint = joints[jointIndex + 1];\r\n\r\n const parentPos = parentJoint.position;\r\n const currentPos = currentJoint.position;\r\n const childPos = childJoint.position;\r\n\r\n // Calculate the plane defined by parent, child, and pole vector\r\n // Vector from parent to child (the \"line\" we're bending around)\r\n const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());\r\n const lineLength = parentToChild.magnitude;\r\n\r\n if (lineLength < 0.000001) {\r\n return; // Parent and child are at same position\r\n }\r\n\r\n const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());\r\n\r\n // Project current joint onto the parent-child line\r\n const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());\r\n const projectionLength = Vector3.dot(parentToCurrent, lineDir);\r\n const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());\r\n Vector3.add(parentPos, projectionPoint, projectionPoint);\r\n\r\n // Vector from projection point to current joint (perpendicular to line)\r\n const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());\r\n const perpLength = perpendicular.magnitude;\r\n\r\n if (perpLength < 0.000001) {\r\n return; // Current joint is on the line\r\n }\r\n\r\n // Calculate desired direction toward pole vector\r\n const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());\r\n const poleProjectionLength = Vector3.dot(parentToPole, lineDir);\r\n const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());\r\n Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);\r\n\r\n // Direction from projection to pole (perpendicular to line)\r\n const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());\r\n const poleDirLength = poleDirection.magnitude;\r\n\r\n if (poleDirLength < 0.000001) {\r\n return; // Pole is on the line\r\n }\r\n\r\n poleDirection.scaleBy(1 / poleDirLength);\r\n\r\n // Calculate new position for current joint\r\n // Keep the same distance from the line, but rotate toward pole direction\r\n const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());\r\n const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());\r\n\r\n // Apply weight (blend between original and constrained position)\r\n if (weight < 0.999) {\r\n const blended = new Vector3();\r\n blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;\r\n blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;\r\n blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;\r\n currentJoint.position.set(blended);\r\n } else {\r\n currentJoint.position.set(newPosition);\r\n }\r\n }\r\n\r\n /**\r\n * Stretch the chain toward an unreachable target.\r\n * All joints are aligned in a straight line toward the target.\r\n *\r\n * @param target - Unreachable target position\r\n */\r\n private _stretchToward(target: Vector3): void {\r\n const joints = this._chain.joints;\r\n const rootPos = joints[0].originalPosition;\r\n\r\n // Calculate direction from root to target\r\n const direction = Vector3.sub(target, rootPos, new Vector3()).inplaceNormalize();\r\n\r\n // Place each joint along the direction at its bone length\r\n let currentPos = rootPos.clone();\r\n for (let i = 0; i < joints.length; i++) {\r\n joints[i].position.set(currentPos);\r\n if (i < joints.length - 1) {\r\n const offset = Vector3.scale(direction, joints[i].boneLength, new Vector3());\r\n currentPos.addBy(offset);\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["FABRIKSolver","IKSolver","chain","maxIterations","tolerance","_poleVectors","Map","_twistConstraints","i","joints","length","isMiddleJoint","set","minTwist","Math","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","Error","max","min","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","setPoleVector","poleVector","weight","position","clone","removePoleVector","clearPoleVectors","getPoleVector","config","undefined","hasPoleVector","has","solve","target","updateFromNodes","storeOriginalPositions","rootPos","originalPosition","distToTarget","Vector3","distance","totalLength","_stretchToward","converged","iteration","_maxIterations","distToEnd","_tolerance","_forwardPass","_backwardPass","applyToNodes","joint","nextJoint","originalDir","sub","newDir","originalDirNorm","normalize","newDirNorm","deltaRotation","Quaternion","IKUtils","fromToRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","constraint","clampAndSmoothTwist","previousTwist","clampedTwist","fromAxisAngle","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","rotation","childJoint","direction","magnitude","scaleBy","scale","boneLength","add","_applyConstraintsForJoint","constraints","name","apply","poleConfig","_applyPoleVectorTwist","parentJoint","currentJoint","parentPos","currentPos","childPos","parentToChild","lineLength","lineDir","parentToCurrent","projectionLength","dot","projectionPoint","perpendicular","perpLength","parentToPole","poleProjectionLength","poleProjectionPoint","poleDirection","poleDirLength","desiredPerpendicular","newPosition","blended","x","y","z","inplaceNormalize","offset","addBy"],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Vector3 } from '@zephyr3d/base';
|
|
2
|
+
import { IKConstraint } from './ik_constraint.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Angle constraint for IK joints.
|
|
6
|
+
*
|
|
7
|
+
* Limits the angle between the bone from parent to this joint
|
|
8
|
+
* and the bone from this joint to child.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* This is useful for joints like elbows and knees that have
|
|
12
|
+
* limited range of motion.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/ class IKAngleConstraint extends IKConstraint {
|
|
16
|
+
/** Minimum angle in degrees */ _minAngle;
|
|
17
|
+
/** Maximum angle in degrees */ _maxAngle;
|
|
18
|
+
/**
|
|
19
|
+
* Create an angle constraint.
|
|
20
|
+
*
|
|
21
|
+
* @param jointIndex - Index of the joint in the chain
|
|
22
|
+
* @param minAngle - Minimum angle in degrees (0 = straight)
|
|
23
|
+
* @param maxAngle - Maximum angle in degrees (180 = fully bent)
|
|
24
|
+
*/ constructor(jointIndex, minAngle, maxAngle){
|
|
25
|
+
super(jointIndex);
|
|
26
|
+
this._minAngle = Math.max(0, minAngle);
|
|
27
|
+
this._maxAngle = Math.min(180, maxAngle);
|
|
28
|
+
if (this._minAngle > this._maxAngle) {
|
|
29
|
+
throw new Error('IKAngleConstraint: minAngle must be <= maxAngle');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the minimum angle in degrees.
|
|
34
|
+
*/ get minAngle() {
|
|
35
|
+
return this._minAngle;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Set the minimum angle in degrees.
|
|
39
|
+
*/ set minAngle(value) {
|
|
40
|
+
this._minAngle = Math.max(0, Math.min(value, this._maxAngle));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the maximum angle in degrees.
|
|
44
|
+
*/ get maxAngle() {
|
|
45
|
+
return this._maxAngle;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Set the maximum angle in degrees.
|
|
49
|
+
*/ set maxAngle(value) {
|
|
50
|
+
this._maxAngle = Math.min(180, Math.max(value, this._minAngle));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Apply the angle constraint to limit joint bending.
|
|
54
|
+
*/ apply(joints) {
|
|
55
|
+
const index = this._jointIndex;
|
|
56
|
+
// For end effector (last joint), we constrain the angle between the last two bones
|
|
57
|
+
// For other joints, we constrain the angle at the joint itself
|
|
58
|
+
if (index === joints.length - 1) {
|
|
59
|
+
// End effector: constrain angle between (parent-1 -> parent) and (parent -> this)
|
|
60
|
+
if (index < 2) {
|
|
61
|
+
return; // Need at least 3 joints total
|
|
62
|
+
}
|
|
63
|
+
this._applyEndEffectorConstraint(joints, index);
|
|
64
|
+
} else {
|
|
65
|
+
// Regular joint: constrain angle between (parent -> this) and (this -> child)
|
|
66
|
+
if (index < 1) {
|
|
67
|
+
return; // Root joint cannot be constrained this way
|
|
68
|
+
}
|
|
69
|
+
this._applyRegularConstraint(joints, index);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Apply constraint to end effector joint.
|
|
74
|
+
*/ _applyEndEffectorConstraint(joints, index) {
|
|
75
|
+
const grandParentJoint = joints[index - 2];
|
|
76
|
+
const parentJoint = joints[index - 1];
|
|
77
|
+
const currentJoint = joints[index];
|
|
78
|
+
// Calculate bone vectors
|
|
79
|
+
const incomingBone = Vector3.sub(parentJoint.position, grandParentJoint.position, new Vector3());
|
|
80
|
+
const outgoingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());
|
|
81
|
+
const incomingLen = incomingBone.magnitude;
|
|
82
|
+
const outgoingLen = outgoingBone.magnitude;
|
|
83
|
+
if (incomingLen < 0.000001 || outgoingLen < 0.000001) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Normalize
|
|
87
|
+
const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());
|
|
88
|
+
const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());
|
|
89
|
+
// Calculate current angle
|
|
90
|
+
const dot = Vector3.dot(incomingNorm, outgoingNorm);
|
|
91
|
+
const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);
|
|
92
|
+
// Check if constraint is violated
|
|
93
|
+
let targetAngleDeg = currentAngleDeg;
|
|
94
|
+
if (currentAngleDeg < this._minAngle) {
|
|
95
|
+
targetAngleDeg = this._minAngle;
|
|
96
|
+
} else if (currentAngleDeg > this._maxAngle) {
|
|
97
|
+
targetAngleDeg = this._maxAngle;
|
|
98
|
+
} else {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Apply the same constraint logic as regular joints
|
|
102
|
+
this._adjustJointAngle(incomingNorm, outgoingNorm, currentAngleDeg, targetAngleDeg, parentJoint, currentJoint);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Apply constraint to regular joint.
|
|
106
|
+
*/ _applyRegularConstraint(joints, index) {
|
|
107
|
+
const parentJoint = joints[index - 1];
|
|
108
|
+
const currentJoint = joints[index];
|
|
109
|
+
const childJoint = joints[index + 1];
|
|
110
|
+
// Calculate bone vectors: incoming bone (parent->current) and outgoing bone (current->child)
|
|
111
|
+
const incomingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());
|
|
112
|
+
const outgoingBone = Vector3.sub(childJoint.position, currentJoint.position, new Vector3());
|
|
113
|
+
const incomingLen = incomingBone.magnitude;
|
|
114
|
+
const outgoingLen = outgoingBone.magnitude;
|
|
115
|
+
if (incomingLen < 0.000001 || outgoingLen < 0.000001) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Normalize
|
|
119
|
+
const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());
|
|
120
|
+
const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());
|
|
121
|
+
// Calculate current angle between incoming and outgoing bones (interior angle)
|
|
122
|
+
const dot = Vector3.dot(incomingNorm, outgoingNorm);
|
|
123
|
+
const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);
|
|
124
|
+
// Check if constraint is violated
|
|
125
|
+
let targetAngleDeg = currentAngleDeg;
|
|
126
|
+
if (currentAngleDeg < this._minAngle) {
|
|
127
|
+
targetAngleDeg = this._minAngle;
|
|
128
|
+
} else if (currentAngleDeg > this._maxAngle) {
|
|
129
|
+
targetAngleDeg = this._maxAngle;
|
|
130
|
+
} else {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Apply the constraint
|
|
134
|
+
this._adjustJointAngle(incomingNorm, outgoingNorm, currentAngleDeg, targetAngleDeg, currentJoint, childJoint);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Adjust joint angle by rotating the outgoing bone.
|
|
138
|
+
*/ _adjustJointAngle(incomingNorm, outgoingNorm, currentAngleDeg, targetAngleDeg, pivotJoint, targetJoint) {
|
|
139
|
+
// Add a dead zone to prevent oscillation
|
|
140
|
+
const angleDifference = Math.abs(targetAngleDeg - currentAngleDeg);
|
|
141
|
+
const isHardConstraint = Math.abs(this._maxAngle - this._minAngle) < 0.01;
|
|
142
|
+
const deadZone = isHardConstraint ? 0.2 : 0.1;
|
|
143
|
+
if (angleDifference < deadZone) {
|
|
144
|
+
return; // Too close to target, avoid over-correction
|
|
145
|
+
}
|
|
146
|
+
// Calculate rotation axis (perpendicular to both bone vectors)
|
|
147
|
+
const axis = Vector3.cross(incomingNorm, outgoingNorm, new Vector3());
|
|
148
|
+
const axisLen = axis.magnitude;
|
|
149
|
+
// Use a smaller threshold to allow constraint to work at small angles
|
|
150
|
+
if (axisLen < 0.0001) {
|
|
151
|
+
return; // Vectors are too close to parallel or anti-parallel
|
|
152
|
+
}
|
|
153
|
+
axis.scaleBy(1 / axisLen);
|
|
154
|
+
// Calculate the angle we need to rotate
|
|
155
|
+
const targetAngleRad = targetAngleDeg * (Math.PI / 180);
|
|
156
|
+
const currentAngleRad = currentAngleDeg * (Math.PI / 180);
|
|
157
|
+
let deltaAngle = targetAngleRad - currentAngleRad;
|
|
158
|
+
// Apply full correction without damping to ensure constraints are enforced
|
|
159
|
+
// This is necessary because FABRIK will try to undo the constraint in the next iteration
|
|
160
|
+
// So we need strong constraint enforcement
|
|
161
|
+
// Rotate the outgoing bone vector around the axis by deltaAngle
|
|
162
|
+
const cos = Math.cos(deltaAngle);
|
|
163
|
+
const sin = Math.sin(deltaAngle);
|
|
164
|
+
const oneMinusCos = 1 - cos;
|
|
165
|
+
// Rodrigues' rotation formula
|
|
166
|
+
const rotated = new Vector3();
|
|
167
|
+
rotated.x = outgoingNorm.x * (cos + axis.x * axis.x * oneMinusCos) + outgoingNorm.y * (axis.x * axis.y * oneMinusCos - axis.z * sin) + outgoingNorm.z * (axis.x * axis.z * oneMinusCos + axis.y * sin);
|
|
168
|
+
rotated.y = outgoingNorm.x * (axis.y * axis.x * oneMinusCos + axis.z * sin) + outgoingNorm.y * (cos + axis.y * axis.y * oneMinusCos) + outgoingNorm.z * (axis.y * axis.z * oneMinusCos - axis.x * sin);
|
|
169
|
+
rotated.z = outgoingNorm.x * (axis.z * axis.x * oneMinusCos - axis.y * sin) + outgoingNorm.y * (axis.z * axis.y * oneMinusCos + axis.x * sin) + outgoingNorm.z * (cos + axis.z * axis.z * oneMinusCos);
|
|
170
|
+
// Update target joint position using the rotated bone vector
|
|
171
|
+
const boneLength = pivotJoint.boneLength;
|
|
172
|
+
rotated.scaleBy(boneLength);
|
|
173
|
+
Vector3.add(pivotJoint.position, rotated, targetJoint.position);
|
|
174
|
+
// Note: We do NOT recursively update subsequent joints here.
|
|
175
|
+
// Instead, we let FABRIK algorithm handle the propagation in subsequent iterations.
|
|
176
|
+
// This ensures that each joint's constraint is properly applied.
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export { IKAngleConstraint };
|
|
181
|
+
//# sourceMappingURL=ik_angle_constraint.js.map
|