@woosh/meep-engine 2.110.7 → 2.110.9
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/build/bundle-worker-terrain.js +1 -1
- package/build/meep.cjs +115 -119
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +115 -119
- package/editor/tools/v2/TransformControls.js +11 -6
- package/package.json +2 -1
- package/src/core/UUID.d.ts +3 -0
- package/src/core/UUID.d.ts.map +1 -1
- package/src/core/UUID.js +9 -7
- package/src/core/collection/array/arraySetDiff.d.ts.map +1 -1
- package/src/core/collection/array/arraySetDiff.js +0 -1
- package/src/core/collection/array/binarySearchHighIndex.d.ts.map +1 -1
- package/src/core/collection/array/binarySearchHighIndex.js +7 -1
- package/src/core/collection/array/computeHashArray.d.ts.map +1 -1
- package/src/core/collection/array/computeHashArray.js +3 -2
- package/src/core/collection/array/fastArrayEquals.d.ts +1 -0
- package/src/core/collection/array/fastArrayEquals.d.ts.map +1 -1
- package/src/core/collection/array/fastArrayEquals.js +1 -0
- package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
- package/src/core/collection/array/isArrayEqual.js +9 -12
- package/src/core/collection/array/isArrayEqual.spec.d.ts +2 -0
- package/src/core/collection/array/isArrayEqual.spec.d.ts.map +1 -0
- package/src/core/collection/array/isArrayEqual.spec.js +25 -0
- package/src/core/collection/array/typed/is_typed_array_equals.d.ts.map +1 -1
- package/src/core/collection/array/typed/is_typed_array_equals.js +1 -0
- package/src/core/function/makeSequenceLoop.d.ts.map +1 -0
- package/src/core/geom/3d/shape/AbstractShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/AbstractShape3D.js +14 -0
- package/src/core/geom/3d/shape/PointShape3D.d.ts +9 -0
- package/src/core/geom/3d/shape/PointShape3D.d.ts.map +1 -0
- package/src/core/geom/3d/shape/PointShape3D.js +14 -0
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +26 -8
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +33 -4
- package/src/core/geom/3d/shape/UnitCubeShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnitCubeShape3D.js +13 -6
- package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnitSphereShape3D.js +10 -0
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts +15 -8
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +33 -9
- package/src/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.d.ts +1 -1
- package/src/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +7 -7
- package/src/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_build_from_grid.spec.d.ts +2 -0
- package/src/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_build_from_grid.spec.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_build_from_grid.spec.js +38 -0
- package/src/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +42 -39
- package/src/core/geom/3d/v3_compute_triangle_normal.js +1 -1
- package/src/core/geom/3d/v3_negate_array.d.ts +9 -0
- package/src/core/geom/3d/v3_negate_array.d.ts.map +1 -0
- package/src/core/geom/3d/v3_negate_array.js +16 -0
- package/src/core/geom/Quaternion.d.ts.map +1 -1
- package/src/core/geom/Quaternion.js +30 -77
- package/src/core/geom/Vector3.d.ts +4 -0
- package/src/core/geom/Vector3.js +4 -4
- package/src/core/geom/vec3/v3_cross_array.d.ts +11 -0
- package/src/core/geom/vec3/v3_cross_array.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_cross_array.js +31 -0
- package/src/core/geom/vec3/v3_displace_in_direction.js +3 -2
- package/src/core/geom/vec3/v3_displace_in_direction_array.d.ts +12 -0
- package/src/core/geom/vec3/v3_displace_in_direction_array.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_displace_in_direction_array.js +22 -0
- package/src/core/geom/vec3/v3_dot_array_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_dot_array_array.js +4 -1
- package/src/core/geom/vec3/v3_normalize_array.d.ts +3 -3
- package/src/core/geom/vec3/v3_normalize_array.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_normalize_array.js +3 -3
- package/src/core/math/copysign.d.ts +1 -1
- package/src/core/math/copysign.js +1 -1
- package/src/core/math/epsilonEquals.d.ts.map +1 -1
- package/src/core/math/epsilonEquals.js +3 -2
- package/src/core/math/linalg/README.md +1 -1
- package/src/core/math/random/randomGaussian.spec.js +1 -1
- package/src/core/math/spline/spline_hermite3.d.ts +1 -1
- package/src/core/math/spline/spline_hermite3.js +1 -1
- package/src/core/process/delay.d.ts +6 -1
- package/src/core/process/delay.d.ts.map +1 -1
- package/src/core/process/delay.js +6 -1
- package/src/core/process/undo/Mark.d.ts +5 -5
- package/src/core/process/undo/Mark.d.ts.map +1 -1
- package/src/core/process/undo/Mark.js +6 -5
- package/src/core/process/worker/WorkerBuilder.d.ts +13 -2
- package/src/core/process/worker/WorkerBuilder.d.ts.map +1 -1
- package/src/core/process/worker/WorkerBuilder.js +9 -1
- package/src/core/process/worker/WorkerProxy.d.ts +16 -6
- package/src/core/process/worker/WorkerProxy.d.ts.map +1 -1
- package/src/core/process/worker/WorkerProxy.js +24 -5
- package/src/core/process/worker/extractTransferables.d.ts.map +1 -1
- package/src/core/process/worker/extractTransferables.js +3 -1
- package/src/engine/EngineHarness.d.ts +7 -1
- package/src/engine/EngineHarness.d.ts.map +1 -1
- package/src/engine/EngineHarness.js +12 -1
- package/src/engine/animation/clip/AnimationTrack.d.ts.map +1 -1
- package/src/engine/animation/clip/AnimationTrack.js +3 -0
- package/src/engine/animation/clip/bind_property_writer.d.ts +2 -2
- package/src/engine/animation/clip/bind_property_writer.d.ts.map +1 -1
- package/src/engine/animation/clip/bind_property_writer.js +22 -13
- package/src/engine/animation/clip/curve_from_track_data.d.ts.map +1 -1
- package/src/engine/animation/clip/curve_from_track_data.js +9 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.js +6 -5
- package/src/engine/animation/curve/AnimationCurve.d.ts +21 -0
- package/src/engine/animation/curve/AnimationCurve.d.ts.map +1 -1
- package/src/engine/animation/curve/AnimationCurve.js +43 -15
- package/src/engine/animation/curve/AnimationCurve.spec.js +67 -0
- package/src/engine/animation/curve/Keyframe.d.ts +24 -3
- package/src/engine/animation/curve/Keyframe.d.ts.map +1 -1
- package/src/engine/animation/curve/Keyframe.js +49 -3
- package/src/engine/animation/curve/Keyframe.spec.js +11 -0
- package/src/engine/animation/curve/animation_curve_compute_aabb.d.ts +7 -0
- package/src/engine/animation/curve/animation_curve_compute_aabb.d.ts.map +1 -0
- package/src/engine/animation/curve/{compute_curve_aabb.js → animation_curve_compute_aabb.js} +1 -1
- package/src/engine/animation/curve/animation_curve_optimize.d.ts +8 -0
- package/src/engine/animation/curve/animation_curve_optimize.d.ts.map +1 -0
- package/src/engine/animation/curve/animation_curve_optimize.js +89 -0
- package/src/engine/animation/curve/animation_curve_optimize.spec.d.ts +2 -0
- package/src/engine/animation/curve/animation_curve_optimize.spec.d.ts.map +1 -0
- package/src/engine/animation/curve/animation_curve_optimize.spec.js +50 -0
- package/src/engine/animation/curve/draw/build_curve_editor.js +2 -2
- package/src/engine/animation/curve/evaluate_two_key_curve.d.ts +9 -0
- package/src/engine/animation/curve/evaluate_two_key_curve.d.ts.map +1 -0
- package/src/engine/animation/curve/evaluate_two_key_curve.js +23 -0
- package/src/engine/animation/curve/prototypeGLTF.js +14 -14
- package/src/engine/asset/loaders/material/computeTextureEquality.d.ts.map +1 -1
- package/src/engine/asset/loaders/material/computeTextureEquality.js +4 -6
- package/src/engine/asset/loaders/material/computeTextureHash.d.ts.map +1 -1
- package/src/engine/asset/loaders/material/computeTextureHash.js +6 -6
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.d.ts +6 -1
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.d.ts.map +1 -1
- package/src/engine/ecs/dynamic_actions/rules/DynamicRuleDescription.js +11 -6
- package/src/engine/ecs/guid/GUIDSerializationAdapter.spec.js +5 -5
- package/src/engine/ecs/guid/{GUID.d.ts → UUID.d.ts} +17 -12
- package/src/engine/ecs/guid/UUID.d.ts.map +1 -0
- package/src/engine/ecs/guid/{GUID.js → UUID.js} +35 -12
- package/src/engine/ecs/guid/UUID.spec.d.ts +2 -0
- package/src/engine/ecs/guid/UUID.spec.d.ts.map +1 -0
- package/src/engine/ecs/guid/{GUID.spec.js → UUID.spec.js} +18 -12
- package/src/engine/ecs/guid/UUIDSerializationAdapter.d.ts +18 -0
- package/src/engine/ecs/guid/UUIDSerializationAdapter.d.ts.map +1 -0
- package/src/engine/ecs/guid/{GUIDSerializationAdapter.js → UUIDSerializationAdapter.js} +5 -5
- package/src/engine/ecs/ik/InverseKinematics.js +3 -3
- package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.d.ts.map +1 -1
- package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +1 -140
- package/src/engine/graphics/ecs/trail2d/Trail2DSystem.js +1 -1
- package/src/engine/graphics/material/manager/MaterialManager.d.ts.map +1 -1
- package/src/engine/graphics/texture/isImageBitmap.d.ts +7 -0
- package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -0
- package/src/engine/graphics/texture/isImageBitmap.js +12 -0
- package/src/engine/graphics/trail/x/RibbonXPlugin.d.ts.map +1 -1
- package/src/engine/graphics/trail/x/RibbonXPlugin.js +9 -1
- package/src/engine/input/ecs/systems/InputControllerSystem.js +1 -1
- package/src/engine/intelligence/blackboard/BlackboardDynamicStorageAdapter.d.ts +1 -1
- package/src/engine/intelligence/blackboard/BlackboardDynamicStorageAdapter.js +4 -4
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts +13 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.d.ts.map +1 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.js +395 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.spec.d.ts +2 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.spec.d.ts.map +1 -0
- package/src/engine/physics/gjk/expanding_polytope_algorithm.spec.js +46 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.d.ts +18 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.d.ts.map +1 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.js +277 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.spec.d.ts +2 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.spec.d.ts.map +1 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.spec.js +43 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.d.ts +12 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.d.ts.map +1 -0
- package/src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.js +100 -0
- package/src/engine/physics/inverse_kinematics/fabrik/prototype.d.ts +2 -0
- package/src/engine/physics/inverse_kinematics/fabrik/prototype.d.ts.map +1 -0
- package/src/engine/physics/inverse_kinematics/fabrik/prototype.js +112 -0
- package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts +16 -0
- package/src/engine/physics/inverse_kinematics/two_joint_ik.d.ts.map +1 -0
- package/src/engine/physics/inverse_kinematics/two_joint_ik.js +127 -0
- package/src/view/elements/DropDownSelectionView.js +2 -2
- package/src/view/elements/tiles2d/Tile.d.ts.map +1 -1
- package/src/view/elements/tiles2d/Tile.js +2 -3
- package/src/core/math/makeSequenceLoop.d.ts.map +0 -1
- package/src/engine/animation/curve/compute_curve_aabb.d.ts +0 -7
- package/src/engine/animation/curve/compute_curve_aabb.d.ts.map +0 -1
- package/src/engine/ecs/guid/GUID.d.ts.map +0 -1
- package/src/engine/ecs/guid/GUID.spec.d.ts +0 -2
- package/src/engine/ecs/guid/GUID.spec.d.ts.map +0 -1
- package/src/engine/ecs/guid/GUIDSerializationAdapter.d.ts +0 -18
- package/src/engine/ecs/guid/GUIDSerializationAdapter.d.ts.map +0 -1
- /package/src/core/{math → function}/makeSequenceLoop.d.ts +0 -0
- /package/src/core/{math → function}/makeSequenceLoop.js +0 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { v3_displace_in_direction_array } from "../../../../core/geom/vec3/v3_displace_in_direction_array.js";
|
|
2
|
+
import { v3_distance } from "../../../../core/geom/vec3/v3_distance.js";
|
|
3
|
+
import { v3_distance_sqr } from "../../../../core/geom/vec3/v3_distance_sqr.js";
|
|
4
|
+
import { v3_length_sqr } from "../../../../core/geom/vec3/v3_length_sqr.js";
|
|
5
|
+
import { v3_normalize_array } from "../../../../core/geom/vec3/v3_normalize_array.js";
|
|
6
|
+
|
|
7
|
+
const scratch_direction = new Float32Array(3);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Implementation of FABRIK algorithm, "Forward And Backward Reaching Inverse Kinematics"
|
|
11
|
+
* This implementation deals with single chain at a time, without support for multiple effectors
|
|
12
|
+
* see "FABRIK: a fast, iterative solver for inverse kinematics"
|
|
13
|
+
* @param {number} size number of points in the chain
|
|
14
|
+
* @param {Float32Array|number[]} positions
|
|
15
|
+
* @param {Float32Array|number[]} lengths
|
|
16
|
+
* @param {number} origin_x
|
|
17
|
+
* @param {number} origin_y
|
|
18
|
+
* @param {number} origin_z
|
|
19
|
+
* @param {number} target_x
|
|
20
|
+
* @param {number} target_y
|
|
21
|
+
* @param {number} target_z
|
|
22
|
+
* @param {number} [max_iterations] More steps will lead to higher accuracy, but at the cost of computation. Generally solution will be reached in just a few iteration so this is just a ceiling
|
|
23
|
+
* @param {number} [distance_tolerance] Minimum squared distance to be achieved to the target, used to terminate earlier before maximum number of iterations is reached
|
|
24
|
+
*/
|
|
25
|
+
export function fabrik3d_solve_primitive(
|
|
26
|
+
size,
|
|
27
|
+
positions,
|
|
28
|
+
lengths,
|
|
29
|
+
origin_x, origin_y, origin_z,
|
|
30
|
+
target_x, target_y, target_z,
|
|
31
|
+
max_iterations = 4,
|
|
32
|
+
distance_tolerance = 1e-7
|
|
33
|
+
) {
|
|
34
|
+
|
|
35
|
+
if (size === 0) {
|
|
36
|
+
// nothing to solve, chain has insufficient number of joints
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
!is_reachable(
|
|
42
|
+
size, lengths,
|
|
43
|
+
origin_x, origin_y, origin_z,
|
|
44
|
+
target_x, target_y, target_z)
|
|
45
|
+
) {
|
|
46
|
+
// target is not reachable, so stretch out the chain towards it instead
|
|
47
|
+
reach_out(
|
|
48
|
+
size,
|
|
49
|
+
positions,
|
|
50
|
+
lengths,
|
|
51
|
+
origin_x, origin_y, origin_z,
|
|
52
|
+
target_x, target_y, target_z
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < max_iterations; i++) {
|
|
60
|
+
|
|
61
|
+
solve_backward(size, positions, lengths, target_x, target_y, target_z);
|
|
62
|
+
solve_forward(size, positions, lengths, origin_x, origin_y, origin_z);
|
|
63
|
+
|
|
64
|
+
const last_join_address = (size - 1) * 3;
|
|
65
|
+
|
|
66
|
+
const last_joint_x = positions[last_join_address];
|
|
67
|
+
const last_joint_y = positions[last_join_address + 1];
|
|
68
|
+
const last_joint_z = positions[last_join_address + 2];
|
|
69
|
+
|
|
70
|
+
if (v3_distance_sqr(last_joint_x, last_joint_y, last_joint_z, target_x, target_y, target_z) <= distance_tolerance) {
|
|
71
|
+
// close enough
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {number} size number of points in the chain
|
|
81
|
+
* @param {Float32Array|number[]} positions
|
|
82
|
+
* @param {Float32Array|number[]} lengths
|
|
83
|
+
* @param {number} origin_x
|
|
84
|
+
* @param {number} origin_y
|
|
85
|
+
* @param {number} origin_z
|
|
86
|
+
* @param {number} target_x
|
|
87
|
+
* @param {number} target_y
|
|
88
|
+
* @param {number} target_z
|
|
89
|
+
*/
|
|
90
|
+
function reach_out(
|
|
91
|
+
size,
|
|
92
|
+
positions,
|
|
93
|
+
lengths,
|
|
94
|
+
origin_x, origin_y, origin_z,
|
|
95
|
+
target_x, target_y, target_z,
|
|
96
|
+
) {
|
|
97
|
+
|
|
98
|
+
positions[0] = origin_x;
|
|
99
|
+
positions[1] = origin_y;
|
|
100
|
+
positions[2] = origin_z;
|
|
101
|
+
|
|
102
|
+
scratch_direction[0] = target_x - origin_x;
|
|
103
|
+
scratch_direction[1] = target_y - origin_y;
|
|
104
|
+
scratch_direction[2] = target_z - origin_z;
|
|
105
|
+
|
|
106
|
+
v3_normalize_array(scratch_direction, 0, scratch_direction, 0);
|
|
107
|
+
|
|
108
|
+
for (let i = 1; i < size; i++) {
|
|
109
|
+
const current_offset = i * 3;
|
|
110
|
+
|
|
111
|
+
const previous_offset = current_offset - 3;
|
|
112
|
+
|
|
113
|
+
const previous_x = positions[previous_offset];
|
|
114
|
+
const previous_y = positions[previous_offset + 1];
|
|
115
|
+
const previous_z = positions[previous_offset + 2];
|
|
116
|
+
|
|
117
|
+
const length = lengths[i - 1];
|
|
118
|
+
|
|
119
|
+
positions[current_offset] = previous_x + scratch_direction[0] * length;
|
|
120
|
+
positions[current_offset + 1] = previous_y + scratch_direction[1] * length;
|
|
121
|
+
positions[current_offset + 2] = previous_z + scratch_direction[2] * length;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
* @param {number} size
|
|
129
|
+
* @param {number[]} lengths
|
|
130
|
+
* @param {number} origin_x
|
|
131
|
+
* @param {number} origin_y
|
|
132
|
+
* @param {number} origin_z
|
|
133
|
+
* @param {number} target_x
|
|
134
|
+
* @param {number} target_y
|
|
135
|
+
* @param {number} target_z
|
|
136
|
+
*/
|
|
137
|
+
function is_reachable(
|
|
138
|
+
size, lengths,
|
|
139
|
+
origin_x, origin_y, origin_z,
|
|
140
|
+
target_x, target_y, target_z
|
|
141
|
+
) {
|
|
142
|
+
|
|
143
|
+
let total_length = 0;
|
|
144
|
+
|
|
145
|
+
const limit = size - 1;
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < limit; i++) {
|
|
148
|
+
const x = lengths[i];
|
|
149
|
+
|
|
150
|
+
total_length += x;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const distance_to_target = v3_distance(origin_x, origin_y, origin_z, target_x, target_y, target_z);
|
|
154
|
+
|
|
155
|
+
return distance_to_target <= total_length;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Produced vector normalize(B-A)
|
|
160
|
+
* @param result
|
|
161
|
+
* @param result_offset
|
|
162
|
+
* @param positions
|
|
163
|
+
* @param offsetA
|
|
164
|
+
* @param offsetB
|
|
165
|
+
*/
|
|
166
|
+
function compute_direction(
|
|
167
|
+
result, result_offset,
|
|
168
|
+
positions, offsetA, offsetB
|
|
169
|
+
) {
|
|
170
|
+
|
|
171
|
+
const ax = positions[offsetA];
|
|
172
|
+
const ay = positions[offsetA + 1];
|
|
173
|
+
const az = positions[offsetA + 2];
|
|
174
|
+
|
|
175
|
+
const bx = positions[offsetB];
|
|
176
|
+
const by = positions[offsetB + 1];
|
|
177
|
+
const bz = positions[offsetB + 2];
|
|
178
|
+
|
|
179
|
+
const dx = bx - ax;
|
|
180
|
+
const dy = by - ay;
|
|
181
|
+
const dz = bz - az;
|
|
182
|
+
|
|
183
|
+
const length_sqr = v3_length_sqr(dx, dy, dz);
|
|
184
|
+
|
|
185
|
+
if (length_sqr === 0) {
|
|
186
|
+
// TODO use random point on a sphere to prevent pathology
|
|
187
|
+
|
|
188
|
+
// points are on top of each other, set arbitrary direction
|
|
189
|
+
result[result_offset + 0] = 0;
|
|
190
|
+
result[result_offset + 1] = 0;
|
|
191
|
+
result[result_offset + 2] = 1;
|
|
192
|
+
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const m = 1 / Math.sqrt(length_sqr);
|
|
197
|
+
|
|
198
|
+
result[result_offset + 0] = dx * m;
|
|
199
|
+
result[result_offset + 1] = dy * m;
|
|
200
|
+
result[result_offset + 2] = dz * m;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
*
|
|
206
|
+
* @param {number} size
|
|
207
|
+
* @param {Float32Array} positions
|
|
208
|
+
* @param {Float32Array|number[]} lengths
|
|
209
|
+
* @param {number} origin_x
|
|
210
|
+
* @param {number} origin_y
|
|
211
|
+
* @param {number} origin_z
|
|
212
|
+
*/
|
|
213
|
+
function solve_forward(size, positions, lengths, origin_x, origin_y, origin_z) {
|
|
214
|
+
|
|
215
|
+
// move first point to origin
|
|
216
|
+
positions[0] = origin_x;
|
|
217
|
+
positions[1] = origin_y;
|
|
218
|
+
positions[2] = origin_z;
|
|
219
|
+
|
|
220
|
+
for (let i = 1; i < size; i++) {
|
|
221
|
+
const current_address = i * 3;
|
|
222
|
+
const previous_address = current_address - 3;
|
|
223
|
+
|
|
224
|
+
compute_direction(
|
|
225
|
+
scratch_direction, 0,
|
|
226
|
+
positions, previous_address, current_address
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const length = lengths[i - 1];
|
|
230
|
+
|
|
231
|
+
v3_displace_in_direction_array(
|
|
232
|
+
positions, current_address,
|
|
233
|
+
positions, previous_address,
|
|
234
|
+
scratch_direction, 0,
|
|
235
|
+
length
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
*
|
|
243
|
+
* @param {number} size
|
|
244
|
+
* @param {Float32Array} positions
|
|
245
|
+
* @param {Float32Array|number[]} lengths
|
|
246
|
+
* @param {number} target_x
|
|
247
|
+
* @param {number} target_y
|
|
248
|
+
* @param {number} target_z
|
|
249
|
+
*/
|
|
250
|
+
function solve_backward(size, positions, lengths, target_x, target_y, target_z) {
|
|
251
|
+
|
|
252
|
+
const last_index = size - 1;
|
|
253
|
+
|
|
254
|
+
// move last point to target
|
|
255
|
+
const last_address = last_index * 3;
|
|
256
|
+
|
|
257
|
+
positions[last_address] = target_x;
|
|
258
|
+
positions[last_address + 1] = target_y;
|
|
259
|
+
positions[last_address + 2] = target_z;
|
|
260
|
+
|
|
261
|
+
for (let i = last_index - 1; i >= 0; i--) {
|
|
262
|
+
const current_address = i * 3;
|
|
263
|
+
const next_address = current_address + 3;
|
|
264
|
+
|
|
265
|
+
compute_direction(
|
|
266
|
+
scratch_direction, 0,
|
|
267
|
+
positions, next_address, current_address
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
v3_displace_in_direction_array(
|
|
271
|
+
positions, current_address,
|
|
272
|
+
positions, next_address,
|
|
273
|
+
scratch_direction, 0,
|
|
274
|
+
lengths[i]
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fabrik3d_solve_primitive.spec.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/inverse_kinematics/fabrik/fabrik3d_solve_primitive.spec.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { fabrik3d_solve_primitive } from "./fabrik3d_solve_primitive.js";
|
|
2
|
+
|
|
3
|
+
test("0 size chain solve should succeed", () => {
|
|
4
|
+
|
|
5
|
+
fabrik3d_solve_primitive(
|
|
6
|
+
0, [], [],
|
|
7
|
+
0, 0, 0,
|
|
8
|
+
0, 0, 1
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("1 joint chain", () => {
|
|
14
|
+
|
|
15
|
+
const positions = [-1, -1, -1];
|
|
16
|
+
|
|
17
|
+
fabrik3d_solve_primitive(
|
|
18
|
+
1, positions, [1],
|
|
19
|
+
1, 2, 3,
|
|
20
|
+
0, 0, 1
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
expect(positions).toEqual([1, 2, 3]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("2 joint chain", () => {
|
|
27
|
+
const positions = [
|
|
28
|
+
-1, -1, -1,
|
|
29
|
+
-1, -1, -1,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
fabrik3d_solve_primitive(
|
|
33
|
+
2, positions, [1, 1],
|
|
34
|
+
1, 2, 3,
|
|
35
|
+
2, 2, 3
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(positions).toEqual([
|
|
39
|
+
1, 2, 3,
|
|
40
|
+
2, 2, 3
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {Transform[]} joints
|
|
4
|
+
* @param {number[]} lengths distance to next bone
|
|
5
|
+
* @param {Vector3} origin where should the first joint be placed at
|
|
6
|
+
* @param {Vector3} target where should the last joint be placed at
|
|
7
|
+
* @param {number} [max_iterations] More steps will lead to higher accuracy, but at the cost of computation. Generally solution will be reached in just a few iteration so this is just a ceiling
|
|
8
|
+
* @param {number} [distance_tolerance] Minimum squared distance to be achieved to the target, used to terminate earlier before maximum number of iterations is reached
|
|
9
|
+
*/
|
|
10
|
+
export function fabrik_solve(joints: Transform[], lengths: number[], origin: Vector3, target: Vector3, max_iterations?: number, distance_tolerance?: number): void;
|
|
11
|
+
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
12
|
+
//# sourceMappingURL=fabrik_solve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fabrik_solve.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/inverse_kinematics/fabrik/fabrik_solve.js"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AACH,qCAPW,WAAW,WACX,MAAM,EAAE,UACR,OAAO,UACP,OAAO,mBACP,MAAM,uBACN,MAAM,QAgFhB;oBAjGmB,kCAAkC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Quaternion from "../../../../core/geom/Quaternion.js";
|
|
2
|
+
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
3
|
+
import { fabrik3d_solve_primitive } from "./fabrik3d_solve_primitive.js";
|
|
4
|
+
|
|
5
|
+
const scratch_positions_count = 64;
|
|
6
|
+
const scratch_positions = new Float32Array(scratch_positions_count * 3);
|
|
7
|
+
|
|
8
|
+
const scratch_v3_0 = new Vector3();
|
|
9
|
+
const scratch_v3_1 = new Vector3();
|
|
10
|
+
const scratch_quat = new Quaternion();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Transform[]} joints
|
|
15
|
+
* @param {number[]} lengths distance to next bone
|
|
16
|
+
* @param {Vector3} origin where should the first joint be placed at
|
|
17
|
+
* @param {Vector3} target where should the last joint be placed at
|
|
18
|
+
* @param {number} [max_iterations] More steps will lead to higher accuracy, but at the cost of computation. Generally solution will be reached in just a few iteration so this is just a ceiling
|
|
19
|
+
* @param {number} [distance_tolerance] Minimum squared distance to be achieved to the target, used to terminate earlier before maximum number of iterations is reached
|
|
20
|
+
*/
|
|
21
|
+
export function fabrik_solve(
|
|
22
|
+
joints,
|
|
23
|
+
lengths,
|
|
24
|
+
origin,
|
|
25
|
+
target,
|
|
26
|
+
max_iterations = 4,
|
|
27
|
+
distance_tolerance = 1e-7
|
|
28
|
+
) {
|
|
29
|
+
|
|
30
|
+
const joint_count = joints.length;
|
|
31
|
+
|
|
32
|
+
let positions;
|
|
33
|
+
if (joint_count <= scratch_positions_count) {
|
|
34
|
+
positions = scratch_positions;
|
|
35
|
+
} else {
|
|
36
|
+
positions = new Float32Array(joint_count * 3);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < joint_count; i++) {
|
|
40
|
+
const offset = i * 3;
|
|
41
|
+
const joint = joints[i];
|
|
42
|
+
|
|
43
|
+
joint.position.toArray(positions, offset);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fabrik3d_solve_primitive(
|
|
47
|
+
joint_count,
|
|
48
|
+
positions,
|
|
49
|
+
lengths,
|
|
50
|
+
origin.x, origin.y, origin.z,
|
|
51
|
+
target.x, target.y, target.z,
|
|
52
|
+
max_iterations, distance_tolerance
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// apply rotation
|
|
56
|
+
for (let i = 1; i < joint_count; i++) {
|
|
57
|
+
const current_joint = joints[i];
|
|
58
|
+
const previous_joint = joints[i - 1];
|
|
59
|
+
|
|
60
|
+
const i3 = i * 3;
|
|
61
|
+
|
|
62
|
+
const previous_x = positions[i3 - 3];
|
|
63
|
+
const previous_y = positions[i3 - 2];
|
|
64
|
+
const previous_z = positions[i3 - 1];
|
|
65
|
+
|
|
66
|
+
const current_x = positions[i3];
|
|
67
|
+
const current_y = positions[i3 + 1];
|
|
68
|
+
const current_z = positions[i3 + 2];
|
|
69
|
+
|
|
70
|
+
scratch_v3_0.copy(current_joint.position);
|
|
71
|
+
scratch_v3_0.sub(previous_joint.position);
|
|
72
|
+
|
|
73
|
+
if (scratch_v3_0.lengthSqr() === 0) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
scratch_v3_1.set(
|
|
78
|
+
current_x - previous_x,
|
|
79
|
+
current_y - previous_y,
|
|
80
|
+
current_z - previous_z,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (scratch_v3_1.lengthSqr() === 0) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
scratch_v3_0.normalize();
|
|
88
|
+
scratch_v3_1.normalize();
|
|
89
|
+
|
|
90
|
+
scratch_quat.fromUnitVectors(scratch_v3_0, scratch_v3_1);
|
|
91
|
+
|
|
92
|
+
previous_joint.rotation.multiplyQuaternions(scratch_quat, previous_joint.rotation);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// apply positions
|
|
96
|
+
for (let i = 0; i < joint_count; i++) {
|
|
97
|
+
joints[i].position.fromArray(positions, i * 3);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototype.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/physics/inverse_kinematics/fabrik/prototype.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { CylinderBufferGeometry, MeshStandardMaterial } from "three";
|
|
2
|
+
import { TransformControls } from "../../../../../editor/tools/v2/TransformControls.js";
|
|
3
|
+
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
4
|
+
import { DEG_TO_RAD } from "../../../../core/math/DEG_TO_RAD.js";
|
|
5
|
+
import Entity from "../../../ecs/Entity.js";
|
|
6
|
+
import { TransformAttachmentSystem } from "../../../ecs/transform-attachment/TransformAttachmentSystem.js";
|
|
7
|
+
import { Transform } from "../../../ecs/transform/Transform.js";
|
|
8
|
+
import { EngineHarness } from "../../../EngineHarness.js";
|
|
9
|
+
import { ShadedGeometry } from "../../../graphics/ecs/mesh-v2/ShadedGeometry.js";
|
|
10
|
+
import { ShadedGeometrySystem } from "../../../graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
|
|
11
|
+
import InputController from "../../../input/ecs/components/InputController.js";
|
|
12
|
+
import InputControllerSystem from "../../../input/ecs/systems/InputControllerSystem.js";
|
|
13
|
+
import { BehaviorComponent } from "../../../intelligence/behavior/ecs/BehaviorComponent.js";
|
|
14
|
+
import { BehaviorSystem } from "../../../intelligence/behavior/ecs/BehaviorSystem.js";
|
|
15
|
+
import { fabrik_solve } from "./fabrik_solve.js";
|
|
16
|
+
|
|
17
|
+
EngineHarness.bootstrap({
|
|
18
|
+
configuration(config, engine) {
|
|
19
|
+
config.addSystem(new ShadedGeometrySystem(engine));
|
|
20
|
+
config.addSystem(new InputControllerSystem(engine.devices));
|
|
21
|
+
config.addSystem(new TransformAttachmentSystem());
|
|
22
|
+
config.addSystem(new BehaviorSystem(engine));
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
.then(async engine => {
|
|
26
|
+
|
|
27
|
+
const ecd = engine.entityManager.dataset;
|
|
28
|
+
|
|
29
|
+
await EngineHarness.buildBasics({
|
|
30
|
+
engine,
|
|
31
|
+
cameraController: false
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const controls = new TransformControls(engine.graphics.camera, engine.viewStack.el);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @type {Entity[]}
|
|
40
|
+
*/
|
|
41
|
+
const chain = [];
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const link_geometry = new CylinderBufferGeometry(1, 1, 2);
|
|
45
|
+
link_geometry.rotateX(90 * DEG_TO_RAD);
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < 50; i++) {
|
|
48
|
+
|
|
49
|
+
const entity = new Entity()
|
|
50
|
+
.add(Transform.fromJSON({
|
|
51
|
+
position: {
|
|
52
|
+
x: 10,
|
|
53
|
+
y: 0,
|
|
54
|
+
z: 10
|
|
55
|
+
},
|
|
56
|
+
scale: 0.1
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
entity.add(ShadedGeometry.from(link_geometry, new MeshStandardMaterial()));
|
|
60
|
+
|
|
61
|
+
chain.push(entity);
|
|
62
|
+
|
|
63
|
+
entity.build(ecd);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
controls.build(ecd);
|
|
67
|
+
controls.attach(chain[chain.length - 1].id);
|
|
68
|
+
|
|
69
|
+
const joints = chain.map(e => e.getComponent(Transform));
|
|
70
|
+
const lengths = chain.map(x => 0.1);
|
|
71
|
+
|
|
72
|
+
new Entity()
|
|
73
|
+
.add(BehaviorComponent.looping_function(timeDelta => {
|
|
74
|
+
const last = joints[joints.length - 1];
|
|
75
|
+
const target = last.position.clone();
|
|
76
|
+
|
|
77
|
+
for (let i = 0; i < joints.length; i++) {
|
|
78
|
+
// gravity
|
|
79
|
+
joints[i].position._add(0, -9 * timeDelta, 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
fabrik_solve(
|
|
84
|
+
joints,
|
|
85
|
+
lengths,
|
|
86
|
+
new Vector3(10, 2, 10),
|
|
87
|
+
target
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
last.position.copy(target);
|
|
91
|
+
}))
|
|
92
|
+
.build(ecd);
|
|
93
|
+
|
|
94
|
+
new Entity()
|
|
95
|
+
.add(new InputController([{
|
|
96
|
+
path: 'keyboard/keys/w/down',
|
|
97
|
+
listener() {
|
|
98
|
+
controls.mode = "translate"
|
|
99
|
+
}
|
|
100
|
+
}, {
|
|
101
|
+
path: 'keyboard/keys/e/down',
|
|
102
|
+
listener() {
|
|
103
|
+
controls.mode = "scale"
|
|
104
|
+
}
|
|
105
|
+
}, {
|
|
106
|
+
path: 'keyboard/keys/r/down',
|
|
107
|
+
listener() {
|
|
108
|
+
controls.mode = "rotate"
|
|
109
|
+
}
|
|
110
|
+
}]))
|
|
111
|
+
.build(ecd);
|
|
112
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Based on http://theorangeduck.com/page/simple-two-joint
|
|
3
|
+
* @param {Vector3} a Root bone position
|
|
4
|
+
* @param {Vector3} b Second bone position
|
|
5
|
+
* @param {Vector3} c Effector position
|
|
6
|
+
* @param {Vector3} t Target position
|
|
7
|
+
* @param {number} eps EPSILON value, small value for rounding error compensation
|
|
8
|
+
* @param {Quaternion} a_gr Global rotation of root bone
|
|
9
|
+
* @param {Quaternion} b_gr Global rotation of second bone
|
|
10
|
+
* @param {Quaternion} a_lr local rotation for root bone, this will be updated as a result
|
|
11
|
+
* @param {Quaternion} b_lr local rotation for second bone, this will be updated as a result
|
|
12
|
+
*/
|
|
13
|
+
export function two_joint_ik(a: Vector3, b: Vector3, c: Vector3, t: Vector3, eps: number, a_gr: Quaternion, b_gr: Quaternion, a_lr: Quaternion, b_lr: Quaternion): void;
|
|
14
|
+
import Vector3 from "../../../core/geom/Vector3.js";
|
|
15
|
+
import Quaternion from "../../../core/geom/Quaternion.js";
|
|
16
|
+
//# sourceMappingURL=two_joint_ik.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"two_joint_ik.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/inverse_kinematics/two_joint_ik.js"],"names":[],"mappings":"AAgDA;;;;;;;;;;;GAWG;AACH,gCAVW,OAAO,KACP,OAAO,KACP,OAAO,KACP,OAAO,OACP,MAAM,QACN,UAAU,QACV,UAAU,QACV,UAAU,QACV,UAAU,QAoEpB;oBA5HmB,+BAA+B;uBAF5B,kCAAkC"}
|