@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,191 @@
|
|
|
1
|
+
import { Vector3, Quaternion } from '@zephyr3d/base';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility functions for IK calculations.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/ class IKUtils {
|
|
8
|
+
/**
|
|
9
|
+
* Calculate the rotation needed to align 'from' direction to 'to' direction.
|
|
10
|
+
*
|
|
11
|
+
* @param from - Starting direction vector
|
|
12
|
+
* @param to - Target direction vector
|
|
13
|
+
* @param result - Output quaternion
|
|
14
|
+
* @returns The rotation quaternion
|
|
15
|
+
*/ static fromToRotation(from, to, result) {
|
|
16
|
+
const fromNorm = Vector3.normalize(from, new Vector3());
|
|
17
|
+
const toNorm = Vector3.normalize(to, new Vector3());
|
|
18
|
+
const dot = Vector3.dot(fromNorm, toNorm);
|
|
19
|
+
// Vectors are parallel
|
|
20
|
+
if (dot >= 0.999999) {
|
|
21
|
+
return result.identity();
|
|
22
|
+
}
|
|
23
|
+
// Vectors are opposite
|
|
24
|
+
if (dot <= -0.999999) {
|
|
25
|
+
// Find an orthogonal axis
|
|
26
|
+
let axis = Vector3.cross(Vector3.axisPX(), fromNorm, new Vector3());
|
|
27
|
+
const lenSq = axis.x * axis.x + axis.y * axis.y + axis.z * axis.z;
|
|
28
|
+
if (lenSq < 0.000001) {
|
|
29
|
+
axis = Vector3.cross(Vector3.axisPY(), fromNorm, new Vector3());
|
|
30
|
+
}
|
|
31
|
+
axis.inplaceNormalize();
|
|
32
|
+
return result.fromAxisAngle(axis, Math.PI);
|
|
33
|
+
}
|
|
34
|
+
// General case
|
|
35
|
+
const axis = Vector3.cross(fromNorm, toNorm).inplaceNormalize();
|
|
36
|
+
const angle = Math.acos(dot);
|
|
37
|
+
return result.fromAxisAngle(axis, angle);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Calculate bone length between two positions.
|
|
41
|
+
*
|
|
42
|
+
* @param start - Start position
|
|
43
|
+
* @param end - End position
|
|
44
|
+
* @returns Distance between positions
|
|
45
|
+
*/ static calculateBoneLength(start, end) {
|
|
46
|
+
return Vector3.distance(start, end);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clamp twist angle and optionally smooth with previous twist.
|
|
50
|
+
*
|
|
51
|
+
* @param currentTwist - Current twist angle in radians
|
|
52
|
+
* @param previousTwist - Previous frame's twist angle in radians (optional)
|
|
53
|
+
* @param minTwist - Minimum allowed twist angle in radians
|
|
54
|
+
* @param maxTwist - Maximum allowed twist angle in radians
|
|
55
|
+
* @param smoothFactor - Smoothing factor [0-1], 0 = no smoothing, 1 = full smoothing
|
|
56
|
+
* @returns Clamped and smoothed twist angle
|
|
57
|
+
*/ static clampAndSmoothTwist(currentTwist, previousTwist, minTwist, maxTwist, smoothFactor = 0.5) {
|
|
58
|
+
// Clamp to range
|
|
59
|
+
let clampedTwist = Math.max(minTwist, Math.min(maxTwist, currentTwist));
|
|
60
|
+
// Smooth with previous frame if available
|
|
61
|
+
if (previousTwist !== undefined && smoothFactor > 0.001) {
|
|
62
|
+
// Normalize angle difference to [-PI, PI]
|
|
63
|
+
let diff = clampedTwist - previousTwist;
|
|
64
|
+
while(diff > Math.PI){
|
|
65
|
+
diff -= 2 * Math.PI;
|
|
66
|
+
}
|
|
67
|
+
while(diff < -Math.PI){
|
|
68
|
+
diff += 2 * Math.PI;
|
|
69
|
+
}
|
|
70
|
+
// Lerp
|
|
71
|
+
clampedTwist = previousTwist + diff * (1 - smoothFactor);
|
|
72
|
+
}
|
|
73
|
+
return clampedTwist;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Calculate a look-at rotation with twist constraint using a pole vector.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* This creates a rotation that:
|
|
80
|
+
* 1. Aligns 'forward' direction to 'targetDir'
|
|
81
|
+
* 2. Keeps the perpendicular plane aligned with 'poleDir'
|
|
82
|
+
*
|
|
83
|
+
* This prevents unwanted twist around the bone axis by using an external
|
|
84
|
+
* reference direction (pole vector) rather than relying on previous rotations.
|
|
85
|
+
*
|
|
86
|
+
* @param forward - Current forward direction (will be aligned to targetDir)
|
|
87
|
+
* @param targetDir - Desired forward direction
|
|
88
|
+
* @param poleDir - Direction that should be in the "up" hemisphere (from joint position)
|
|
89
|
+
* @param result - Output quaternion
|
|
90
|
+
* @returns The rotation quaternion
|
|
91
|
+
*/ static lookAtRotationWithPole(forward, targetDir, poleDir, result) {
|
|
92
|
+
const forwardNorm = Vector3.normalize(forward, new Vector3());
|
|
93
|
+
const targetDirNorm = Vector3.normalize(targetDir, new Vector3());
|
|
94
|
+
const poleDirNorm = Vector3.normalize(poleDir, new Vector3());
|
|
95
|
+
// First, align forward to targetDir (swing rotation)
|
|
96
|
+
const swingRotation = new Quaternion();
|
|
97
|
+
this.fromToRotation(forwardNorm, targetDirNorm, swingRotation);
|
|
98
|
+
// Calculate the "right" vector perpendicular to targetDir and poleDir
|
|
99
|
+
// This defines the plane that the bone should bend in
|
|
100
|
+
const right = Vector3.cross(targetDirNorm, poleDirNorm, new Vector3());
|
|
101
|
+
const rightLenSq = right.x * right.x + right.y * right.y + right.z * right.z;
|
|
102
|
+
// If pole is parallel to target direction, no twist correction possible
|
|
103
|
+
if (rightLenSq < 0.000001) {
|
|
104
|
+
result.set(swingRotation);
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
right.scaleBy(1 / Math.sqrt(rightLenSq));
|
|
108
|
+
// Calculate the "up" vector perpendicular to targetDir in the pole plane
|
|
109
|
+
const up = Vector3.cross(right, targetDirNorm, new Vector3()).inplaceNormalize();
|
|
110
|
+
// Now we need to find the twist rotation around targetDir
|
|
111
|
+
// We want the local "up" axis to align with the calculated "up" vector
|
|
112
|
+
// Get a perpendicular vector to forward in the original space
|
|
113
|
+
let originalUp = Vector3.cross(forwardNorm, Vector3.axisPY(), new Vector3());
|
|
114
|
+
const originalUpLenSq = originalUp.x * originalUp.x + originalUp.y * originalUp.y + originalUp.z * originalUp.z;
|
|
115
|
+
if (originalUpLenSq < 0.000001) {
|
|
116
|
+
originalUp = Vector3.cross(forwardNorm, Vector3.axisPX(), new Vector3());
|
|
117
|
+
}
|
|
118
|
+
originalUp.inplaceNormalize();
|
|
119
|
+
// Rotate originalUp by swing rotation to see where it ends up
|
|
120
|
+
const rotatedUp = swingRotation.transform(originalUp, new Vector3());
|
|
121
|
+
// Project rotatedUp onto the plane perpendicular to targetDir
|
|
122
|
+
const rotatedUpDot = Vector3.dot(rotatedUp, targetDirNorm);
|
|
123
|
+
const rotatedUpProj = Vector3.scale(targetDirNorm, rotatedUpDot, new Vector3());
|
|
124
|
+
const rotatedUpPerp = Vector3.sub(rotatedUp, rotatedUpProj, new Vector3());
|
|
125
|
+
const rotatedUpPerpLen = rotatedUpPerp.magnitude;
|
|
126
|
+
if (rotatedUpPerpLen < 0.000001) {
|
|
127
|
+
result.set(swingRotation);
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
rotatedUpPerp.scaleBy(1 / rotatedUpPerpLen);
|
|
131
|
+
// Calculate twist rotation to align rotatedUpPerp with up
|
|
132
|
+
const twistRotation = new Quaternion();
|
|
133
|
+
this.fromToRotation(rotatedUpPerp, up, twistRotation);
|
|
134
|
+
// Combine swing and twist
|
|
135
|
+
return Quaternion.multiply(twistRotation, swingRotation, result);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Calculate a look-at rotation with twist constraint.
|
|
139
|
+
*
|
|
140
|
+
* @remarks
|
|
141
|
+
* This creates a rotation that:
|
|
142
|
+
* 1. Aligns 'forward' direction to 'targetDir'
|
|
143
|
+
* 2. Keeps 'up' direction as close as possible to 'targetUp'
|
|
144
|
+
*
|
|
145
|
+
* This prevents unwanted twist around the bone axis.
|
|
146
|
+
*
|
|
147
|
+
* @param forward - Current forward direction (will be aligned to targetDir)
|
|
148
|
+
* @param targetDir - Desired forward direction
|
|
149
|
+
* @param up - Current up direction (perpendicular to forward)
|
|
150
|
+
* @param targetUp - Desired up direction (will be projected perpendicular to targetDir)
|
|
151
|
+
* @param result - Output quaternion
|
|
152
|
+
* @returns The rotation quaternion
|
|
153
|
+
*/ static lookAtRotation(forward, targetDir, up, targetUp, result) {
|
|
154
|
+
const forwardNorm = Vector3.normalize(forward, new Vector3());
|
|
155
|
+
const targetDirNorm = Vector3.normalize(targetDir, new Vector3());
|
|
156
|
+
// First, align forward to targetDir (swing rotation)
|
|
157
|
+
const swingRotation = new Quaternion();
|
|
158
|
+
this.fromToRotation(forwardNorm, targetDirNorm, swingRotation);
|
|
159
|
+
// Rotate the up vector by swing rotation
|
|
160
|
+
const rotatedUp = swingRotation.transform(up, new Vector3());
|
|
161
|
+
// Project targetUp onto plane perpendicular to targetDir
|
|
162
|
+
const dot = Vector3.dot(targetUp, targetDirNorm);
|
|
163
|
+
const projection = Vector3.scale(targetDirNorm, dot, new Vector3());
|
|
164
|
+
const targetUpPerp = Vector3.sub(targetUp, projection, new Vector3());
|
|
165
|
+
const targetUpPerpLen = targetUpPerp.magnitude;
|
|
166
|
+
// If targetUp is parallel to targetDir, no twist correction needed
|
|
167
|
+
if (targetUpPerpLen < 0.000001) {
|
|
168
|
+
result.set(swingRotation);
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
targetUpPerp.scaleBy(1 / targetUpPerpLen);
|
|
172
|
+
// Project rotatedUp onto the same plane
|
|
173
|
+
const rotatedUpDot = Vector3.dot(rotatedUp, targetDirNorm);
|
|
174
|
+
const rotatedUpProj = Vector3.scale(targetDirNorm, rotatedUpDot, new Vector3());
|
|
175
|
+
const rotatedUpPerp = Vector3.sub(rotatedUp, rotatedUpProj, new Vector3());
|
|
176
|
+
const rotatedUpPerpLen = rotatedUpPerp.magnitude;
|
|
177
|
+
if (rotatedUpPerpLen < 0.000001) {
|
|
178
|
+
result.set(swingRotation);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
rotatedUpPerp.scaleBy(1 / rotatedUpPerpLen);
|
|
182
|
+
// Calculate twist rotation around targetDir
|
|
183
|
+
const twistRotation = new Quaternion();
|
|
184
|
+
this.fromToRotation(rotatedUpPerp, targetUpPerp, twistRotation);
|
|
185
|
+
// Combine swing and twist
|
|
186
|
+
return Quaternion.multiply(twistRotation, swingRotation, result);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export { IKUtils };
|
|
191
|
+
//# sourceMappingURL=ik_utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik_utils.js","sources":["../../../src/animation/ik/ik_utils.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\n\r\n/**\r\n * Utility functions for IK calculations.\r\n *\r\n * @internal\r\n */\r\nexport class IKUtils {\r\n /**\r\n * Calculate the rotation needed to align 'from' direction to 'to' direction.\r\n *\r\n * @param from - Starting direction vector\r\n * @param to - Target direction vector\r\n * @param result - Output quaternion\r\n * @returns The rotation quaternion\r\n */\r\n static fromToRotation(from: Vector3, to: Vector3, result: Quaternion): Quaternion {\r\n const fromNorm = Vector3.normalize(from, new Vector3());\r\n const toNorm = Vector3.normalize(to, new Vector3());\r\n\r\n const dot = Vector3.dot(fromNorm, toNorm);\r\n\r\n // Vectors are parallel\r\n if (dot >= 0.999999) {\r\n return result.identity();\r\n }\r\n\r\n // Vectors are opposite\r\n if (dot <= -0.999999) {\r\n // Find an orthogonal axis\r\n let axis = Vector3.cross(Vector3.axisPX(), fromNorm, new Vector3());\r\n const lenSq = axis.x * axis.x + axis.y * axis.y + axis.z * axis.z;\r\n if (lenSq < 0.000001) {\r\n axis = Vector3.cross(Vector3.axisPY(), fromNorm, new Vector3());\r\n }\r\n axis.inplaceNormalize();\r\n return result.fromAxisAngle(axis, Math.PI);\r\n }\r\n\r\n // General case\r\n const axis = Vector3.cross(fromNorm, toNorm).inplaceNormalize();\r\n const angle = Math.acos(dot);\r\n return result.fromAxisAngle(axis, angle);\r\n }\r\n\r\n /**\r\n * Calculate bone length between two positions.\r\n *\r\n * @param start - Start position\r\n * @param end - End position\r\n * @returns Distance between positions\r\n */\r\n static calculateBoneLength(start: Vector3, end: Vector3): number {\r\n return Vector3.distance(start, end);\r\n }\r\n\r\n /**\r\n * Clamp twist angle and optionally smooth with previous twist.\r\n *\r\n * @param currentTwist - Current twist angle in radians\r\n * @param previousTwist - Previous frame's twist angle in radians (optional)\r\n * @param minTwist - Minimum allowed twist angle in radians\r\n * @param maxTwist - Maximum allowed twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1], 0 = no smoothing, 1 = full smoothing\r\n * @returns Clamped and smoothed twist angle\r\n */\r\n static clampAndSmoothTwist(\r\n currentTwist: number,\r\n previousTwist: number | undefined,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.5\r\n ): number {\r\n // Clamp to range\r\n let clampedTwist = Math.max(minTwist, Math.min(maxTwist, currentTwist));\r\n\r\n // Smooth with previous frame if available\r\n if (previousTwist !== undefined && smoothFactor > 0.001) {\r\n // Normalize angle difference to [-PI, PI]\r\n let diff = clampedTwist - previousTwist;\r\n while (diff > Math.PI) {\r\n diff -= 2 * Math.PI;\r\n }\r\n while (diff < -Math.PI) {\r\n diff += 2 * Math.PI;\r\n }\r\n\r\n // Lerp\r\n clampedTwist = previousTwist + diff * (1 - smoothFactor);\r\n }\r\n\r\n return clampedTwist;\r\n }\r\n\r\n /**\r\n * Calculate a look-at rotation with twist constraint using a pole vector.\r\n *\r\n * @remarks\r\n * This creates a rotation that:\r\n * 1. Aligns 'forward' direction to 'targetDir'\r\n * 2. Keeps the perpendicular plane aligned with 'poleDir'\r\n *\r\n * This prevents unwanted twist around the bone axis by using an external\r\n * reference direction (pole vector) rather than relying on previous rotations.\r\n *\r\n * @param forward - Current forward direction (will be aligned to targetDir)\r\n * @param targetDir - Desired forward direction\r\n * @param poleDir - Direction that should be in the \"up\" hemisphere (from joint position)\r\n * @param result - Output quaternion\r\n * @returns The rotation quaternion\r\n */\r\n static lookAtRotationWithPole(\r\n forward: Vector3,\r\n targetDir: Vector3,\r\n poleDir: Vector3,\r\n result: Quaternion\r\n ): Quaternion {\r\n const forwardNorm = Vector3.normalize(forward, new Vector3());\r\n const targetDirNorm = Vector3.normalize(targetDir, new Vector3());\r\n const poleDirNorm = Vector3.normalize(poleDir, new Vector3());\r\n\r\n // First, align forward to targetDir (swing rotation)\r\n const swingRotation = new Quaternion();\r\n this.fromToRotation(forwardNorm, targetDirNorm, swingRotation);\r\n\r\n // Calculate the \"right\" vector perpendicular to targetDir and poleDir\r\n // This defines the plane that the bone should bend in\r\n const right = Vector3.cross(targetDirNorm, poleDirNorm, new Vector3());\r\n const rightLenSq = right.x * right.x + right.y * right.y + right.z * right.z;\r\n\r\n // If pole is parallel to target direction, no twist correction possible\r\n if (rightLenSq < 0.000001) {\r\n result.set(swingRotation);\r\n return result;\r\n }\r\n\r\n right.scaleBy(1 / Math.sqrt(rightLenSq));\r\n\r\n // Calculate the \"up\" vector perpendicular to targetDir in the pole plane\r\n const up = Vector3.cross(right, targetDirNorm, new Vector3()).inplaceNormalize();\r\n\r\n // Now we need to find the twist rotation around targetDir\r\n // We want the local \"up\" axis to align with the calculated \"up\" vector\r\n\r\n // Get a perpendicular vector to forward in the original space\r\n let originalUp = Vector3.cross(forwardNorm, Vector3.axisPY(), new Vector3());\r\n const originalUpLenSq =\r\n originalUp.x * originalUp.x + originalUp.y * originalUp.y + originalUp.z * originalUp.z;\r\n if (originalUpLenSq < 0.000001) {\r\n originalUp = Vector3.cross(forwardNorm, Vector3.axisPX(), new Vector3());\r\n }\r\n originalUp.inplaceNormalize();\r\n\r\n // Rotate originalUp by swing rotation to see where it ends up\r\n const rotatedUp = swingRotation.transform(originalUp, new Vector3());\r\n\r\n // Project rotatedUp onto the plane perpendicular to targetDir\r\n const rotatedUpDot = Vector3.dot(rotatedUp, targetDirNorm);\r\n const rotatedUpProj = Vector3.scale(targetDirNorm, rotatedUpDot, new Vector3());\r\n const rotatedUpPerp = Vector3.sub(rotatedUp, rotatedUpProj, new Vector3());\r\n const rotatedUpPerpLen = rotatedUpPerp.magnitude;\r\n\r\n if (rotatedUpPerpLen < 0.000001) {\r\n result.set(swingRotation);\r\n return result;\r\n }\r\n\r\n rotatedUpPerp.scaleBy(1 / rotatedUpPerpLen);\r\n\r\n // Calculate twist rotation to align rotatedUpPerp with up\r\n const twistRotation = new Quaternion();\r\n this.fromToRotation(rotatedUpPerp, up, twistRotation);\r\n\r\n // Combine swing and twist\r\n return Quaternion.multiply(twistRotation, swingRotation, result);\r\n }\r\n\r\n /**\r\n * Calculate a look-at rotation with twist constraint.\r\n *\r\n * @remarks\r\n * This creates a rotation that:\r\n * 1. Aligns 'forward' direction to 'targetDir'\r\n * 2. Keeps 'up' direction as close as possible to 'targetUp'\r\n *\r\n * This prevents unwanted twist around the bone axis.\r\n *\r\n * @param forward - Current forward direction (will be aligned to targetDir)\r\n * @param targetDir - Desired forward direction\r\n * @param up - Current up direction (perpendicular to forward)\r\n * @param targetUp - Desired up direction (will be projected perpendicular to targetDir)\r\n * @param result - Output quaternion\r\n * @returns The rotation quaternion\r\n */\r\n static lookAtRotation(\r\n forward: Vector3,\r\n targetDir: Vector3,\r\n up: Vector3,\r\n targetUp: Vector3,\r\n result: Quaternion\r\n ): Quaternion {\r\n const forwardNorm = Vector3.normalize(forward, new Vector3());\r\n const targetDirNorm = Vector3.normalize(targetDir, new Vector3());\r\n\r\n // First, align forward to targetDir (swing rotation)\r\n const swingRotation = new Quaternion();\r\n this.fromToRotation(forwardNorm, targetDirNorm, swingRotation);\r\n\r\n // Rotate the up vector by swing rotation\r\n const rotatedUp = swingRotation.transform(up, new Vector3());\r\n\r\n // Project targetUp onto plane perpendicular to targetDir\r\n const dot = Vector3.dot(targetUp, targetDirNorm);\r\n const projection = Vector3.scale(targetDirNorm, dot, new Vector3());\r\n const targetUpPerp = Vector3.sub(targetUp, projection, new Vector3());\r\n const targetUpPerpLen = targetUpPerp.magnitude;\r\n\r\n // If targetUp is parallel to targetDir, no twist correction needed\r\n if (targetUpPerpLen < 0.000001) {\r\n result.set(swingRotation);\r\n return result;\r\n }\r\n\r\n targetUpPerp.scaleBy(1 / targetUpPerpLen);\r\n\r\n // Project rotatedUp onto the same plane\r\n const rotatedUpDot = Vector3.dot(rotatedUp, targetDirNorm);\r\n const rotatedUpProj = Vector3.scale(targetDirNorm, rotatedUpDot, new Vector3());\r\n const rotatedUpPerp = Vector3.sub(rotatedUp, rotatedUpProj, new Vector3());\r\n const rotatedUpPerpLen = rotatedUpPerp.magnitude;\r\n\r\n if (rotatedUpPerpLen < 0.000001) {\r\n result.set(swingRotation);\r\n return result;\r\n }\r\n\r\n rotatedUpPerp.scaleBy(1 / rotatedUpPerpLen);\r\n\r\n // Calculate twist rotation around targetDir\r\n const twistRotation = new Quaternion();\r\n this.fromToRotation(rotatedUpPerp, targetUpPerp, twistRotation);\r\n\r\n // Combine swing and twist\r\n return Quaternion.multiply(twistRotation, swingRotation, result);\r\n }\r\n}\r\n"],"names":["IKUtils","fromToRotation","from","to","result","fromNorm","Vector3","normalize","toNorm","dot","identity","axis","cross","axisPX","lenSq","x","y","z","axisPY","inplaceNormalize","fromAxisAngle","Math","PI","angle","acos","calculateBoneLength","start","end","distance","clampAndSmoothTwist","currentTwist","previousTwist","minTwist","maxTwist","smoothFactor","clampedTwist","max","min","undefined","diff","lookAtRotationWithPole","forward","targetDir","poleDir","forwardNorm","targetDirNorm","poleDirNorm","swingRotation","Quaternion","right","rightLenSq","set","scaleBy","sqrt","up","originalUp","originalUpLenSq","rotatedUp","transform","rotatedUpDot","rotatedUpProj","scale","rotatedUpPerp","sub","rotatedUpPerpLen","magnitude","twistRotation","multiply","lookAtRotation","targetUp","projection","targetUpPerp","targetUpPerpLen"],"mappings":"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"}
|
|
@@ -0,0 +1,331 @@
|
|
|
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
|
+
worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);
|
|
274
|
+
// Get twist angle
|
|
275
|
+
let twistAngle = twist.getTwistAngle(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 = Quaternion.fromAxisAngle(newDirNorm, twistAngle);
|
|
286
|
+
worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
|
|
287
|
+
// Blend with original rotation based on weight
|
|
288
|
+
if (weight < 1) {
|
|
289
|
+
Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);
|
|
290
|
+
}
|
|
291
|
+
// Store this frame's world rotation for next frame's twist continuity
|
|
292
|
+
if (!joint.previousIKRotation) {
|
|
293
|
+
joint.previousIKRotation = worldRotation.clone();
|
|
294
|
+
} else {
|
|
295
|
+
joint.previousIKRotation.set(worldRotation);
|
|
296
|
+
}
|
|
297
|
+
// Convert world rotation to local rotation (relative to parent)
|
|
298
|
+
if (joint.node.parent) {
|
|
299
|
+
const parentWorldRotation = new Quaternion();
|
|
300
|
+
joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);
|
|
301
|
+
// localRotation = conjugate(parentWorldRotation) * worldRotation
|
|
302
|
+
const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());
|
|
303
|
+
const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());
|
|
304
|
+
joint.node.rotation = localRotation;
|
|
305
|
+
} else {
|
|
306
|
+
// Root node has no parent, world rotation is local rotation
|
|
307
|
+
joint.node.rotation = worldRotation;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get a default bend normal when no pole vector is specified.
|
|
313
|
+
* This tries to find a reasonable perpendicular direction.
|
|
314
|
+
*
|
|
315
|
+
* @param rootToTarget - Direction from root to target
|
|
316
|
+
* @returns A normalized perpendicular vector
|
|
317
|
+
*/ _getDefaultBendNormal(rootToTarget) {
|
|
318
|
+
const rootToTargetDir = Vector3.normalize(rootToTarget, new Vector3());
|
|
319
|
+
// Try to use world up (Y axis) as reference
|
|
320
|
+
let bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPY(), new Vector3());
|
|
321
|
+
const lenSq = bendNormal.x * bendNormal.x + bendNormal.y * bendNormal.y + bendNormal.z * bendNormal.z;
|
|
322
|
+
// If root-to-target is parallel to Y axis, use X axis instead
|
|
323
|
+
if (lenSq < 0.000001) {
|
|
324
|
+
bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPX(), new Vector3());
|
|
325
|
+
}
|
|
326
|
+
return bendNormal.inplaceNormalize();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export { TwoBoneIKSolver };
|
|
331
|
+
//# 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 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 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","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","axisPY","lenSq","x","y","z","axisPX"],"mappings":"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"}
|