PJani wrote:JoeJ you were saying you are using Quaternions for limts, how do you limit their rotation? Because i was searching using google but i didn't found anything useful.
For each body you define constraint space:
matrix cs0 = pody0.world * joint.localMatrix0;
matrix cs1 the same way.
Let's assume that the 'pin vector' is the x-axis of that space.
F. ex. Shoulder is body0, Arm is Body1.
Than cs1.xaxis would point from the joint along the arms length, and rotates with the arm.
cs0.xaxis would point from tho joint to the direction, where the arm is in most relaxed position, and rotates with shoulder.
I hope that's clear.
The limit is done using 2 angular limits.
1. 'Cone' or 'Swing' limit (easy - prevent right arm from moving outside a cone defined by cs0.xaxis and limitangle)
You take the angle between cs0.xaxis and cs1.xaxis.
if it is larger then the cone-limit, you need to costrain using:
fixangle = angle - limitangle;
swingAxis = cs0.xaxis.Cross(cs1.xaxis).Unit(); // maybe you need to swap
NewtonUserJointAddAngularRow (joint, fixangle, swingAxis);
NewtonUserJointSetRowMinimumFriction (joint, 0.0); // important: allow the arm to move inside the cone
2. Twist limit (not so easy - prevent arm from unlimited rotation around it's length):
Take the relative rotation from cs0 to cs1.
See how much rotation is around x axis*
If it is larger than limit, proceed like above, as rotation axis you can use either cs0.xaxis OR cs1.xaxis OR average of them.
I use quats mostly when it comes to rotations just because i'm used to it.
They are not necessary here, but i've read the term 'quaternion twist' often, and i think it refers exactly to point 2.
*) Here a code fregment that computes that with quaternions:
- Code: Select all
sQuat q0, q1;
BodyGetRotation (body0, q0); q0 *= localRot0; // same as 'cs0' in text above, but in quat form
BodyGetRotation (body1, q1); q1 *= localRot1;
// factor rotation about x axis: sQuat qt = q0.Inversed() * q1; float halfTwistAngle = atan (qt[0] / qt[3]);
float twistAngle = 2.0 * atan (
( ( ( (q0[3] * q1[0]) + (-q0[0] * q1[3]) ) + (-q0[1] * q1[2]) ) - (-q0[2] * q1[1]) ) /
( ( ( (q0[3] * q1[3]) - (-q0[0] * q1[0]) ) - (-q0[1] * q1[1]) ) - (-q0[2] * q1[2]) ) );
// WARNING: i use quaternion form (x,y,z, w) - Julio uses (w, x,y,z) - BodyGetRotation does the conversation for me
sVec3 twistAxis = sVec3(dir0+dir1).Unit(); // use average axis
if (twistLimitAngleP == twistLimitAngleN) // this joint does NOT allow twisting
{
NewtonUserJointAddAngularRow (joint, twistAngle - twistLimitAngleP, (float*)&twistAxis);
}
else if (twistAngle > twistLimitAngleP) // ...otherwise i use two limits, joint can twist between those
{
NewtonUserJointAddAngularRow (joint, twistAngle - twistLimitAngleP, (float*)&twistAxis);
NewtonUserJointSetRowMinimumFriction (joint, 0.0f);
}
else if (twistAngle < twistLimitAngleN)
{
NewtonUserJointAddAngularRow (joint, twistAngle - twistLimitAngleN, (float*)&twistAxis);
NewtonUserJointSetRowMaximumFriction (joint, 0.0f);
}