void btConeTwistConstraint::setMotorTargetInConstraintSpace(const btQuaternion &q) { m_qTarget = q; // clamp motor target to within limits { btScalar softness = 1.f;//m_limitSoftness; // split into twist and cone btVector3 vTwisted = quatRotate(m_qTarget, vTwist); btQuaternion qTargetCone = shortestArcQuat(vTwist, vTwisted); qTargetCone.normalize(); btQuaternion qTargetTwist = qTargetCone.inverse() * m_qTarget; qTargetTwist.normalize(); // clamp cone if (m_swingSpan1 >= btScalar(0.05f) && m_swingSpan2 >= btScalar(0.05f)) { btScalar swingAngle, swingLimit; btVector3 swingAxis; computeConeLimitInfo(qTargetCone, swingAngle, swingAxis, swingLimit); if (fabs(swingAngle) > SIMD_EPSILON) { if (swingAngle > swingLimit*softness) swingAngle = swingLimit*softness; else if (swingAngle < -swingLimit*softness) swingAngle = -swingLimit*softness; qTargetCone = btQuaternion(swingAxis, swingAngle); } } // clamp twist if (m_twistSpan >= btScalar(0.05f)) { btScalar twistAngle; btVector3 twistAxis; computeTwistLimitInfo(qTargetTwist, twistAngle, twistAxis); if (fabs(twistAngle) > SIMD_EPSILON) { // eddy todo: limitSoftness used here??? if (twistAngle > m_twistSpan*softness) twistAngle = m_twistSpan*softness; else if (twistAngle < -m_twistSpan*softness) twistAngle = -m_twistSpan*softness; qTargetTwist = btQuaternion(twistAxis, twistAngle); } } m_qTarget = qTargetCone * qTargetTwist; } }
void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTransform& transB, const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB) { m_swingCorrection = btScalar(0.); m_twistLimitSign = btScalar(0.); m_solveTwistLimit = false; m_solveSwingLimit = false; // compute rotation of A wrt B (in constraint space) if (m_bMotorEnabled && (!m_useSolveConstraintObsolete)) { // it is assumed that setMotorTarget() was alredy called // and motor target m_qTarget is within constraint limits // TODO : split rotation to pure swing and pure twist // compute desired transforms in world btTransform trPose(m_qTarget); btTransform trA = transA * m_rbAFrame; btTransform trB = transB * m_rbBFrame; btTransform trDeltaAB = trB * trPose * trA.inverse(); btQuaternion qDeltaAB = trDeltaAB.getRotation(); btVector3 swingAxis = btVector3(qDeltaAB.x(), qDeltaAB.y(), qDeltaAB.z()); float swingAxisLen2 = swingAxis.length2(); if(btFuzzyZero(swingAxisLen2)) { return; } m_swingAxis = swingAxis; m_swingAxis.normalize(); m_swingCorrection = qDeltaAB.getAngle(); if(!btFuzzyZero(m_swingCorrection)) { m_solveSwingLimit = true; } return; } { // compute rotation of A wrt B (in constraint space) btQuaternion qA = transA.getRotation() * m_rbAFrame.getRotation(); btQuaternion qB = transB.getRotation() * m_rbBFrame.getRotation(); btQuaternion qAB = qB.inverse() * qA; // split rotation into cone and twist // (all this is done from B's perspective. Maybe I should be averaging axes...) btVector3 vConeNoTwist = quatRotate(qAB, vTwist); vConeNoTwist.normalize(); btQuaternion qABCone = shortestArcQuat(vTwist, vConeNoTwist); qABCone.normalize(); btQuaternion qABTwist = qABCone.inverse() * qAB; qABTwist.normalize(); if (m_swingSpan1 >= m_fixThresh && m_swingSpan2 >= m_fixThresh) { btScalar swingAngle, swingLimit = 0; btVector3 swingAxis; computeConeLimitInfo(qABCone, swingAngle, swingAxis, swingLimit); if (swingAngle > swingLimit * m_limitSoftness) { m_solveSwingLimit = true; // compute limit ratio: 0->1, where // 0 == beginning of soft limit // 1 == hard/real limit m_swingLimitRatio = 1.f; if (swingAngle < swingLimit && m_limitSoftness < 1.f - SIMD_EPSILON) { m_swingLimitRatio = (swingAngle - swingLimit * m_limitSoftness)/ (swingLimit - swingLimit * m_limitSoftness); } // swing correction tries to get back to soft limit m_swingCorrection = swingAngle - (swingLimit * m_limitSoftness); // adjustment of swing axis (based on ellipse normal) adjustSwingAxisToUseEllipseNormal(swingAxis); // Calculate necessary axis & factors m_swingAxis = quatRotate(qB, -swingAxis); m_twistAxisA.setValue(0,0,0); m_kSwing = btScalar(1.) / (computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldA) + computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldB)); } } else { // you haven't set any limits; // or you're trying to set at least one of the swing limits too small. (if so, do you really want a conetwist constraint?) // anyway, we have either hinge or fixed joint btVector3 ivA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); btVector3 jvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); btVector3 kvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(2); btVector3 ivB = transB.getBasis() * m_rbBFrame.getBasis().getColumn(0); btVector3 target; btScalar x = ivB.dot(ivA); btScalar y = ivB.dot(jvA); btScalar z = ivB.dot(kvA); if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh)) { // fixed. We'll need to add one more row to constraint if((!btFuzzyZero(y)) || (!(btFuzzyZero(z)))) { m_solveSwingLimit = true; m_swingAxis = -ivB.cross(ivA); } } else { if(m_swingSpan1 < m_fixThresh) { // hinge around Y axis if(!(btFuzzyZero(y))) { m_solveSwingLimit = true; if(m_swingSpan2 >= m_fixThresh) { y = btScalar(0.f); btScalar span2 = btAtan2(z, x); if(span2 > m_swingSpan2) { x = btCos(m_swingSpan2); z = btSin(m_swingSpan2); } else if(span2 < -m_swingSpan2) { x = btCos(m_swingSpan2); z = -btSin(m_swingSpan2); } } } } else { // hinge around Z axis if(!btFuzzyZero(z)) { m_solveSwingLimit = true; if(m_swingSpan1 >= m_fixThresh) { z = btScalar(0.f); btScalar span1 = btAtan2(y, x); if(span1 > m_swingSpan1) { x = btCos(m_swingSpan1); y = btSin(m_swingSpan1); } else if(span1 < -m_swingSpan1) { x = btCos(m_swingSpan1); y = -btSin(m_swingSpan1); } } } } target[0] = x * ivA[0] + y * jvA[0] + z * kvA[0]; target[1] = x * ivA[1] + y * jvA[1] + z * kvA[1]; target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2]; target.normalize(); m_swingAxis = -ivB.cross(target); m_swingCorrection = m_swingAxis.length(); m_swingAxis.normalize(); } } if (m_twistSpan >= btScalar(0.f)) { btVector3 twistAxis; computeTwistLimitInfo(qABTwist, m_twistAngle, twistAxis); if (m_twistAngle > m_twistSpan*m_limitSoftness) { m_solveTwistLimit = true; m_twistLimitRatio = 1.f; if (m_twistAngle < m_twistSpan && m_limitSoftness < 1.f - SIMD_EPSILON) { m_twistLimitRatio = (m_twistAngle - m_twistSpan * m_limitSoftness)/ (m_twistSpan - m_twistSpan * m_limitSoftness); } // twist correction tries to get back to soft limit m_twistCorrection = m_twistAngle - (m_twistSpan * m_limitSoftness); m_twistAxis = quatRotate(qB, -twistAxis); m_kTwist = btScalar(1.) / (computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldA) + computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldB)); } if (m_solveSwingLimit) m_twistAxisA = quatRotate(qA, -twistAxis); } else { m_twistAngle = btScalar(0.f); } } }