@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
75 lines • 2.79 kB
JavaScript
import { Vector3 } from "three";
import * as utils from "./../engine/engine_three_utils.js";
import { Behaviour } from "./Component.js";
/**
* The [BasicIKConstraint](https://engine.needle.tools/docs/api/BasicIKConstraint) provides simple two-bone inverse kinematics.
* Positions this GameObject as a "joint" between `from` and `to` targets,
* using a `hint` object to determine the bend direction.
*
* **Use cases:**
* - Simple arm/leg IK (elbow/knee positioning)
* - Mechanical linkages
* - Procedural animation joints
*
* **How it works:**
* - Calculates joint position based on `desiredDistance` (bone length)
* - Uses `hint` to determine which way the joint bends
* - Automatically handles stretching when targets are too far apart
*
* @example Setup basic limb IK
* ```ts
* // Attach to the elbow/knee joint object
* const ik = elbowJoint.addComponent(BasicIKConstraint);
* // Configure via serialized properties in editor:
* // - from: shoulder/hip
* // - to: wrist/ankle
* // - hint: control point for bend direction
* ```
*
* @summary Two-bone inverse kinematics constraint
* @category Animation and Sequencing
* @group Components
* @see {@link LookAtConstraint} for aim constraints
* @see {@link AlignmentConstraint} for simpler alignment
*/
export class BasicIKConstraint extends Behaviour {
from;
to;
hint;
desiredDistance = 1;
onEnable() {
// console.log(this);
}
update() {
if (!this.from || !this.to || !this.hint)
return;
// console.log(this);
// find center
const toPos = utils.getWorldPosition(this.to).clone();
const fromPos = utils.getWorldPosition(this.from).clone();
const dist = toPos.distanceTo(fromPos);
const dir0 = toPos.clone();
dir0.sub(fromPos);
const center = fromPos.clone();
center.add(toPos);
center.multiplyScalar(0.5);
// find direction we should offset in
const hintDir = utils.getWorldPosition(this.hint).clone();
hintDir.sub(center);
const offsetDir = new Vector3();
offsetDir.crossVectors(hintDir, dir0);
offsetDir.crossVectors(dir0, offsetDir);
offsetDir.normalize();
const halfDist = dist * 0.5;
const stretchDistance = Math.max(this.desiredDistance, halfDist);
const offsetLength = Math.sqrt(stretchDistance * stretchDistance - halfDist * halfDist);
const resultPos = offsetDir.clone();
resultPos.multiplyScalar(offsetLength);
resultPos.add(center);
utils.setWorldPosition(this.gameObject, resultPos);
const lookPos = center.clone();
lookPos.sub(offsetDir);
this.gameObject.lookAt(lookPos);
}
}
//# sourceMappingURL=BasicIKConstraint.js.map