UNPKG

@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
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