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 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
- export { BasicToPhysicalConverter, DualFovCamera, InstancedMeshGroup, InstancedMeshInstance, InstancedMeshPool, SceneSorter, SceneTraversal, SkinnedMeshBaker, SkyLight, StandardToBasicConverter, StandardToLambertConverter, StandardToPhongConverter, StandardToPhysicalConverter, StandardToToonConverter, Sun };
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