Skip to content

Hinge Constraints #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion build/three-ik.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function setQuaternionFromDirection(direction, up, target) {
var el = m1.elements;
z.copy(direction);
x.crossVectors(up, z);
if (x.lengthSq() === 0) {
if (x.lengthSq() == 0) {
if (Math.abs(up.z) === 1) {
z.x += 0.0001;
} else {
Expand Down Expand Up @@ -367,11 +367,14 @@ var IKJoint = function () {
this.bone = bone;
this.distance = 0;
this._originalDirection = new three.Vector3();
this._originalHinge = new three.Vector3();
this._direction = new three.Vector3();
this._worldPosition = new three.Vector3();
this._isSubBase = false;
this._subBasePositions = null;
this.isIKJoint = true;
this._originalUp = new three.Vector3(0, 1, 0);
this._originalUp.applyQuaternion(this.bone.quaternion).normalize();
this._updateWorldPosition();
}
createClass(IKJoint, [{
Expand Down Expand Up @@ -553,6 +556,7 @@ var IKChain = function () {
}
else {
var previousJoint = this.joints[this.joints.length - 2];
var previousPreviousJoint = this.joints[this.joints.length - 3];
previousJoint._updateMatrixWorld();
previousJoint._updateWorldPosition();
joint._updateWorldPosition();
Expand All @@ -565,6 +569,9 @@ var IKChain = function () {
var direction = previousJoint._getWorldDirection(joint);
previousJoint._originalDirection = new three.Vector3().copy(direction);
joint._originalDirection = new three.Vector3().copy(direction);
if (previousPreviousJoint) {
previousJoint._originalHinge = previousJoint._worldToLocalDirection(previousJoint._originalDirection.clone().cross(previousPreviousJoint._originalDirection).normalize());
}
this.totalLengths += distance;
}
if (target) {
Expand Down Expand Up @@ -847,6 +854,44 @@ var IK = function () {
return IK;
}();

var Z_AXIS$1 = new three.Vector3(0, 0, -1);
var X_AXIS = new three.Vector3(1, 0, 0);
var t1$1 = new three.Vector3();
var t2$1 = new three.Vector3();
var t3$1 = new three.Vector3();
var t4 = new three.Vector3();
var RAD2DEG$1 = three.Math.RAD2DEG;
var IKHingeConstraint = function () {
function IKHingeConstraint(angle) {
classCallCheck(this, IKHingeConstraint);
this.angle = angle;
this.rotationPlane = new three.Plane();
}
createClass(IKHingeConstraint, [{
key: '_apply',
value: function _apply(joint) {
var direction = new three.Vector3().copy(joint._getDirection());
var parentDirection = joint._localToWorldDirection(t1$1.copy(Z_AXIS$1)).normalize();
var rotationPlaneNormal = joint._localToWorldDirection(t2$1.copy(joint._originalHinge)).normalize();
this.rotationPlane.normal = rotationPlaneNormal;
var projectedDir = this.rotationPlane.projectPoint(direction, new three.Vector3());
var parentDirectionProjected = this.rotationPlane.projectPoint(parentDirection, t3$1);
var currentAngle = projectedDir.angleTo(parentDirectionProjected) * RAD2DEG$1;
var cross = t4.crossVectors(projectedDir, parentDirectionProjected);
if (cross.dot(rotationPlaneNormal) > 0) {
currentAngle += 180;
}
if (currentAngle > this.angle) {
parentDirectionProjected.applyAxisAngle(rotationPlaneNormal, this.angle / RAD2DEG$1);
joint._setDirection(parentDirectionProjected);
} else {
joint._setDirection(projectedDir);
}
}
}]);
return IKHingeConstraint;
}();

var BoneHelper = function (_Object3D) {
inherits(BoneHelper, _Object3D);
function BoneHelper(height, boneSize, axesSize) {
Expand Down Expand Up @@ -1169,13 +1214,15 @@ if (typeof window !== 'undefined' && _typeof(window.THREE) === 'object') {
window.THREE.IKChain = IKChain;
window.THREE.IKJoint = IKJoint;
window.THREE.IKBallConstraint = IKBallConstraint;
window.THREE.IKHingeConstraint = IKHingeConstraint;
window.THREE.IKHelper = IKHelper;
}

exports.IK = IK;
exports.IKChain = IKChain;
exports.IKJoint = IKJoint;
exports.IKBallConstraint = IKBallConstraint;
exports.IKHingeConstraint = IKHingeConstraint;
exports.IKHelper = IKHelper;

Object.defineProperty(exports, '__esModule', { value: true });
Expand Down
52 changes: 49 additions & 3 deletions build/three-ik.module.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AxesHelper, Color, ConeBufferGeometry, Math as Math$1, Matrix4, Mesh, MeshBasicMaterial, Object3D, Vector3 } from 'three';
import { AxesHelper, Color, ConeBufferGeometry, Math as Math$1, Matrix4, Mesh, MeshBasicMaterial, Object3D, Plane, Vector3 } from 'three';

var t1 = new Vector3();
var t2 = new Vector3();
Expand Down Expand Up @@ -43,7 +43,7 @@ function setQuaternionFromDirection(direction, up, target) {
var el = m1.elements;
z.copy(direction);
x.crossVectors(up, z);
if (x.lengthSq() === 0) {
if (x.lengthSq() == 0) {
if (Math.abs(up.z) === 1) {
z.x += 0.0001;
} else {
Expand Down Expand Up @@ -363,11 +363,14 @@ var IKJoint = function () {
this.bone = bone;
this.distance = 0;
this._originalDirection = new Vector3();
this._originalHinge = new Vector3();
this._direction = new Vector3();
this._worldPosition = new Vector3();
this._isSubBase = false;
this._subBasePositions = null;
this.isIKJoint = true;
this._originalUp = new Vector3(0, 1, 0);
this._originalUp.applyQuaternion(this.bone.quaternion).normalize();
this._updateWorldPosition();
}
createClass(IKJoint, [{
Expand Down Expand Up @@ -549,6 +552,7 @@ var IKChain = function () {
}
else {
var previousJoint = this.joints[this.joints.length - 2];
var previousPreviousJoint = this.joints[this.joints.length - 3];
previousJoint._updateMatrixWorld();
previousJoint._updateWorldPosition();
joint._updateWorldPosition();
Expand All @@ -561,6 +565,9 @@ var IKChain = function () {
var direction = previousJoint._getWorldDirection(joint);
previousJoint._originalDirection = new Vector3().copy(direction);
joint._originalDirection = new Vector3().copy(direction);
if (previousPreviousJoint) {
previousJoint._originalHinge = previousJoint._worldToLocalDirection(previousJoint._originalDirection.clone().cross(previousPreviousJoint._originalDirection).normalize());
}
this.totalLengths += distance;
}
if (target) {
Expand Down Expand Up @@ -843,6 +850,44 @@ var IK = function () {
return IK;
}();

var Z_AXIS$1 = new Vector3(0, 0, -1);
var X_AXIS = new Vector3(1, 0, 0);
var t1$1 = new Vector3();
var t2$1 = new Vector3();
var t3$1 = new Vector3();
var t4 = new Vector3();
var RAD2DEG$1 = Math$1.RAD2DEG;
var IKHingeConstraint = function () {
function IKHingeConstraint(angle) {
classCallCheck(this, IKHingeConstraint);
this.angle = angle;
this.rotationPlane = new Plane();
}
createClass(IKHingeConstraint, [{
key: '_apply',
value: function _apply(joint) {
var direction = new Vector3().copy(joint._getDirection());
var parentDirection = joint._localToWorldDirection(t1$1.copy(Z_AXIS$1)).normalize();
var rotationPlaneNormal = joint._localToWorldDirection(t2$1.copy(joint._originalHinge)).normalize();
this.rotationPlane.normal = rotationPlaneNormal;
var projectedDir = this.rotationPlane.projectPoint(direction, new Vector3());
var parentDirectionProjected = this.rotationPlane.projectPoint(parentDirection, t3$1);
var currentAngle = projectedDir.angleTo(parentDirectionProjected) * RAD2DEG$1;
var cross = t4.crossVectors(projectedDir, parentDirectionProjected);
if (cross.dot(rotationPlaneNormal) > 0) {
currentAngle += 180;
}
if (currentAngle > this.angle) {
parentDirectionProjected.applyAxisAngle(rotationPlaneNormal, this.angle / RAD2DEG$1);
joint._setDirection(parentDirectionProjected);
} else {
joint._setDirection(projectedDir);
}
}
}]);
return IKHingeConstraint;
}();

var BoneHelper = function (_Object3D) {
inherits(BoneHelper, _Object3D);
function BoneHelper(height, boneSize, axesSize) {
Expand Down Expand Up @@ -1165,7 +1210,8 @@ if (typeof window !== 'undefined' && _typeof(window.THREE) === 'object') {
window.THREE.IKChain = IKChain;
window.THREE.IKJoint = IKJoint;
window.THREE.IKBallConstraint = IKBallConstraint;
window.THREE.IKHingeConstraint = IKHingeConstraint;
window.THREE.IKHelper = IKHelper;
}

export { IK, IKChain, IKJoint, IKBallConstraint, IKHelper };
export { IK, IKChain, IKJoint, IKBallConstraint, IKHingeConstraint, IKHelper };
125 changes: 125 additions & 0 deletions examples/hinge-constraints.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>THREE.IK - hinge constraint test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}

#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display: block;
}

#info a {
color: #046;
font-weight: bold;
}

</style>
</head>

<body>
<script src="node_modules/dat.gui/build/dat.gui.js"></script>
<script src="node_modules/three/build/three.js"></script>
<script src="node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script src="node_modules/three/examples/js/loaders/FBXLoader.js"></script>
<script src="scripts/IKApp.js"></script>
<script src="scripts/AxisUtils.js"></script>

<script src="../build/three-ik.js"></script>
<script>
class SingleTargetApp extends IKApp {
setupGUI() {
this.config.constraintType = 'ball';
this.config.constraintAngle = 90;

}

setupIK() {

var fbxLoader = new THREE.FBXLoader();
fbxLoader.load('assets/rigTest-02.fbx', (rigGroup) => {
this.scene.add(rigGroup)
rigGroup.updateMatrixWorld()

var rigMesh = rigGroup.children[0];
var rootBone = rigGroup.children[1].children[0]

/**
This model's bind matrices are -Z forward, while the IK system operates in +Z Forward -- assuming
the parent's +Z forward faces the child. This utility helps us recalculate the models bone matrices
to be consistent with the IK system.
**/
setZForward(rootBone);
//must rebind the skeleton to reset the bind matrix.
rigMesh.bind(rigMesh.skeleton)

rigMesh.material = new THREE.MeshPhysicalMaterial({
skinning: true,
wireframe: true
})

this.target = new THREE.Mesh(
new THREE.SphereGeometry(0.5),
new THREE.MeshBasicMaterial({wireframe: true})
);
this.target.position.set(1,0,5.5)
this.scene.add(this.target)

var boneGroup = rootBone;
var ik = new IK.IK();
const chain = new IK.IKChain();
var currentBone = boneGroup;
var constraintArray = [
new IK.IKBallConstraint(90),
new IK.IKHingeConstraint(180),
new IK.IKHingeConstraint(180),
new IK.IKHingeConstraint(100),
];

for (let i = 0; i < 5; i++) {
const target = i === 4 ? this.target : null;
const constraints = [constraintArray[i]];
chain.add(new IK.IKJoint(currentBone, { constraints }), { target });
currentBone = currentBone.children[0]
}
ik.add(chain);
const helper = new IK.IKHelper(ik);
this.scene.add(helper);
this.iks.push(ik)

}, console.log, console.log);
}

onChange() {
super.onChange();
}

update() {
if(this.target){
this.target.position.y = 2 + 2 * Math.sin(0.003 * performance.now())
this.target.position.x = 1 + 2 * Math.sin(0.003 * performance.now())
}
}
};

window.app = new SingleTargetApp();

</script>
</body>

</html>
3 changes: 2 additions & 1 deletion examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ <h1><a href="http://jsantell.github.io/THREE.IK">THREE<span>.IK</span></a></h1>
"single-target",
"multi-effector",
"readme-example",
"skinned-mesh"
"skinned-mesh",
"hinge-constraints"
]
};
function extractQuery() {
Expand Down
Loading