three-zoo 0.11.15 → 0.11.17
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/index.d.ts +1 -0
- package/dist/index.js +129 -3
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/miscellaneous/SceneSorter.d.ts +2 -1
- package/dist/miscellaneous/TwoBoneIK.d.ts +63 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -13,3 +13,4 @@ export { DualFovCamera } from "./miscellaneous/DualFovCamera";
|
|
|
13
13
|
export { SceneSorter } from "./miscellaneous/SceneSorter";
|
|
14
14
|
export { SceneTraversal } from "./miscellaneous/SceneTraversal";
|
|
15
15
|
export { SkinnedMeshBaker } from "./miscellaneous/SkinnedMeshBaker";
|
|
16
|
+
export { TwoBoneIK } from "./miscellaneous/TwoBoneIK";
|
package/dist/index.js
CHANGED
|
@@ -2198,8 +2198,9 @@ class SceneSorter {
|
|
|
2198
2198
|
* @param object - Root object to start from
|
|
2199
2199
|
* @param point - Reference point to measure distances against
|
|
2200
2200
|
* @param baseRenderOrder - Starting render order value
|
|
2201
|
+
* @param reverseOrder - Back-to-front order: closer objects get higher renderOrder (for transparent meshes)
|
|
2201
2202
|
*/
|
|
2202
|
-
static sortByDistanceToPoint(object, point, baseRenderOrder) {
|
|
2203
|
+
static sortByDistanceToPoint(object, point, baseRenderOrder, reverseOrder = false) {
|
|
2203
2204
|
object.updateWorldMatrix(true, true);
|
|
2204
2205
|
const meshes = [];
|
|
2205
2206
|
SceneTraversal.enumerateObjectsByType(object, Mesh, (mesh) => meshes.push(mesh));
|
|
@@ -2213,7 +2214,7 @@ class SceneSorter {
|
|
|
2213
2214
|
const distanceB = TEMP_BOX3.setFromObject(b)
|
|
2214
2215
|
.getCenter(TEMP_VECTOR)
|
|
2215
2216
|
.distanceToSquared(point);
|
|
2216
|
-
return distanceA - distanceB;
|
|
2217
|
+
return reverseOrder ? distanceB - distanceA : distanceA - distanceB;
|
|
2217
2218
|
});
|
|
2218
2219
|
for (let i = 0; i < meshes.length; i++) {
|
|
2219
2220
|
meshes[i].renderOrder = baseRenderOrder + i;
|
|
@@ -2271,5 +2272,130 @@ class SkinnedMeshBaker {
|
|
|
2271
2272
|
}
|
|
2272
2273
|
}
|
|
2273
2274
|
|
|
2274
|
-
|
|
2275
|
+
/**
|
|
2276
|
+
* Analytical two-bone IK solver operating in world space.
|
|
2277
|
+
*
|
|
2278
|
+
* Solves a three-bone chain (root → middle → end) so that the end bone
|
|
2279
|
+
* reaches the target position, with the pole controlling middle-joint
|
|
2280
|
+
* bend direction.
|
|
2281
|
+
*
|
|
2282
|
+
* Writes local quaternions to `root` and `middle` bones.
|
|
2283
|
+
* Does not modify the `end` bone.
|
|
2284
|
+
*
|
|
2285
|
+
* Call `solve()` after AnimationMixer update each frame.
|
|
2286
|
+
*/
|
|
2287
|
+
class TwoBoneIK {
|
|
2288
|
+
constructor(
|
|
2289
|
+
/** First bone in the chain (e.g. upper leg, upper arm). */
|
|
2290
|
+
root,
|
|
2291
|
+
/** Second bone in the chain (e.g. lower leg, forearm). */
|
|
2292
|
+
middle,
|
|
2293
|
+
/** Terminal bone (e.g. foot, hand). Not rotated by the solver. */
|
|
2294
|
+
end,
|
|
2295
|
+
/** Controls the bend direction of the middle joint. */
|
|
2296
|
+
pole,
|
|
2297
|
+
/** Solve target. When undefined, `solve()` is a no-op. */
|
|
2298
|
+
target) {
|
|
2299
|
+
this.root = root;
|
|
2300
|
+
this.middle = middle;
|
|
2301
|
+
this.end = end;
|
|
2302
|
+
this.pole = pole;
|
|
2303
|
+
this.target = target;
|
|
2304
|
+
/** Numerical stability threshold. */
|
|
2305
|
+
this.epsilon = 1e-5;
|
|
2306
|
+
this._private_rootPosition = new Vector3();
|
|
2307
|
+
this._private_middlePosition = new Vector3();
|
|
2308
|
+
this._private_endPosition = new Vector3();
|
|
2309
|
+
this._private_targetPosition = new Vector3();
|
|
2310
|
+
this._private_polePosition = new Vector3();
|
|
2311
|
+
this._private_chainDirection = new Vector3();
|
|
2312
|
+
this._private_perpendicularDirection = new Vector3();
|
|
2313
|
+
this._private_middleTarget = new Vector3();
|
|
2314
|
+
this._private_currentDirection = new Vector3();
|
|
2315
|
+
this._private_desiredDirection = new Vector3();
|
|
2316
|
+
this._private_bonePosition = new Vector3();
|
|
2317
|
+
this._private_childPosition = new Vector3();
|
|
2318
|
+
this._private_deltaRotation = new Quaternion();
|
|
2319
|
+
this._private_boneWorldQuaternion = new Quaternion();
|
|
2320
|
+
this._private_parentWorldQuaternion = new Quaternion();
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Solve IK for the current frame.
|
|
2324
|
+
* No-op when `target` is undefined.
|
|
2325
|
+
*/
|
|
2326
|
+
solve() {
|
|
2327
|
+
if (!this.target) {
|
|
2328
|
+
return;
|
|
2329
|
+
}
|
|
2330
|
+
const epsilon = this.epsilon;
|
|
2331
|
+
this.target.getWorldPosition(this._private_targetPosition);
|
|
2332
|
+
this.pole.getWorldPosition(this._private_polePosition);
|
|
2333
|
+
this.root.getWorldPosition(this._private_rootPosition);
|
|
2334
|
+
this.middle.getWorldPosition(this._private_middlePosition);
|
|
2335
|
+
this.end.getWorldPosition(this._private_endPosition);
|
|
2336
|
+
const upperLength = this._private_rootPosition.distanceTo(this._private_middlePosition);
|
|
2337
|
+
const lowerLength = this._private_middlePosition.distanceTo(this._private_endPosition);
|
|
2338
|
+
const chainLength = upperLength + lowerLength;
|
|
2339
|
+
this._private_chainDirection.subVectors(this._private_targetPosition, this._private_rootPosition);
|
|
2340
|
+
const targetDistance = MathUtils.clamp(this._private_chainDirection.length(), Math.abs(upperLength - lowerLength) + epsilon, chainLength - epsilon);
|
|
2341
|
+
this._private_chainDirection.normalize();
|
|
2342
|
+
// Law of cosines: angle at root joint
|
|
2343
|
+
const cosineRoot = (upperLength * upperLength +
|
|
2344
|
+
targetDistance * targetDistance -
|
|
2345
|
+
lowerLength * lowerLength) /
|
|
2346
|
+
(2 * upperLength * targetDistance);
|
|
2347
|
+
const angleRoot = Math.acos(MathUtils.clamp(cosineRoot, -1, 1));
|
|
2348
|
+
const middleAlongChain = upperLength * Math.cos(angleRoot);
|
|
2349
|
+
const middlePerpendicular = upperLength * Math.sin(angleRoot);
|
|
2350
|
+
// Project pole onto plane perpendicular to chain
|
|
2351
|
+
this._private_perpendicularDirection.subVectors(this._private_polePosition, this._private_rootPosition);
|
|
2352
|
+
this._private_perpendicularDirection.addScaledVector(this._private_chainDirection, -this._private_perpendicularDirection.dot(this._private_chainDirection));
|
|
2353
|
+
// Guard: pole collinear with chain — perpendicular is degenerate.
|
|
2354
|
+
// Pick an arbitrary axis perpendicular to chain.
|
|
2355
|
+
if (this._private_perpendicularDirection.lengthSq() < epsilon) {
|
|
2356
|
+
this._private_perpendicularDirection.set(0, 1, 0);
|
|
2357
|
+
this._private_perpendicularDirection.addScaledVector(this._private_chainDirection, -this._private_perpendicularDirection.dot(this._private_chainDirection));
|
|
2358
|
+
if (this._private_perpendicularDirection.lengthSq() < epsilon) {
|
|
2359
|
+
this._private_perpendicularDirection.set(1, 0, 0);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
this._private_perpendicularDirection.normalize();
|
|
2363
|
+
// Ideal middle-joint world position
|
|
2364
|
+
this._private_middleTarget.copy(this._private_rootPosition)
|
|
2365
|
+
.addScaledVector(this._private_chainDirection, middleAlongChain)
|
|
2366
|
+
.addScaledVector(this._private_perpendicularDirection, middlePerpendicular);
|
|
2367
|
+
// Aim root bone → middle target
|
|
2368
|
+
this._private_aimBone(this.root, this.middle, this._private_middleTarget);
|
|
2369
|
+
// Aim middle bone → end target
|
|
2370
|
+
this._private_aimBone(this.middle, this.end, this._private_targetPosition);
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* Rotate `bone` so that `child` points toward `worldTarget`.
|
|
2374
|
+
* Writes `bone.quaternion` in local space.
|
|
2375
|
+
*/
|
|
2376
|
+
_private_aimBone(bone, child, worldTarget) {
|
|
2377
|
+
bone.getWorldPosition(this._private_bonePosition);
|
|
2378
|
+
child.getWorldPosition(this._private_childPosition);
|
|
2379
|
+
this._private_currentDirection.subVectors(this._private_childPosition, this._private_bonePosition);
|
|
2380
|
+
this._private_desiredDirection.subVectors(worldTarget, this._private_bonePosition);
|
|
2381
|
+
if (this._private_currentDirection.lengthSq() < this.epsilon ||
|
|
2382
|
+
this._private_desiredDirection.lengthSq() < this.epsilon) {
|
|
2383
|
+
return;
|
|
2384
|
+
}
|
|
2385
|
+
this._private_currentDirection.normalize();
|
|
2386
|
+
this._private_desiredDirection.normalize();
|
|
2387
|
+
this._private_deltaRotation.setFromUnitVectors(this._private_currentDirection, this._private_desiredDirection);
|
|
2388
|
+
bone.getWorldQuaternion(this._private_boneWorldQuaternion);
|
|
2389
|
+
this._private_deltaRotation.multiply(this._private_boneWorldQuaternion);
|
|
2390
|
+
if (bone.parent) {
|
|
2391
|
+
bone.parent.getWorldQuaternion(this._private_parentWorldQuaternion);
|
|
2392
|
+
bone.quaternion.copy(this._private_parentWorldQuaternion.invert().multiply(this._private_deltaRotation));
|
|
2393
|
+
}
|
|
2394
|
+
else {
|
|
2395
|
+
bone.quaternion.copy(this._private_deltaRotation);
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
export { BasicToPhysicalConverter, DualFovCamera, InstancedMeshGroup, InstancedMeshInstance, InstancedMeshPool, SceneSorter, SceneTraversal, SkinnedMeshBaker, SkyLight, StandardToBasicConverter, StandardToLambertConverter, StandardToPhongConverter, StandardToPhysicalConverter, StandardToToonConverter, Sun, TwoBoneIK };
|
|
2275
2401
|
//# sourceMappingURL=index.js.map
|