2023-01-10 15:26:54 +01:00
|
|
|
/**************************************************************************/
|
|
|
|
/* generic_6dof_joint_sw.cpp */
|
|
|
|
/**************************************************************************/
|
|
|
|
/* This file is part of: */
|
|
|
|
/* GODOT ENGINE */
|
|
|
|
/* https://godotengine.org */
|
|
|
|
/**************************************************************************/
|
|
|
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
|
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
|
|
/* */
|
|
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
|
|
/* a copy of this software and associated documentation files (the */
|
|
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
|
|
/* the following conditions: */
|
|
|
|
/* */
|
|
|
|
/* The above copyright notice and this permission notice shall be */
|
|
|
|
/* included in all copies or substantial portions of the Software. */
|
|
|
|
/* */
|
|
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
/**************************************************************************/
|
2016-06-18 14:46:12 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Adapted to Godot from the Bullet library.
|
2017-05-06 23:38:44 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Bullet Continuous Collision Detection and Physics Library
|
|
|
|
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
|
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it freely,
|
|
|
|
subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
2007-09-09
|
|
|
|
Generic6DOFJointSW Refactored by Francisco Le?n
|
|
|
|
email: projectileman@yahoo.com
|
|
|
|
http://gimpact.sf.net
|
2016-06-18 14:46:12 +02:00
|
|
|
*/
|
|
|
|
|
2014-09-15 16:33:30 +02:00
|
|
|
#include "generic_6dof_joint_sw.h"
|
|
|
|
|
|
|
|
#define GENERIC_D6_DISABLE_WARMSTARTING 1
|
|
|
|
|
|
|
|
//////////////////////////// G6DOFRotationalLimitMotorSW ////////////////////////////////////
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
int G6DOFRotationalLimitMotorSW::testLimitValue(real_t test_value) {
|
|
|
|
if (m_loLimit > m_hiLimit) {
|
|
|
|
m_currentLimit = 0; //Free from violation
|
2014-09-15 16:33:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
if (test_value < m_loLimit) {
|
|
|
|
m_currentLimit = 1; //low limit violation
|
|
|
|
m_currentLimitError = test_value - m_loLimit;
|
2014-09-15 16:33:30 +02:00
|
|
|
return 1;
|
2017-03-05 16:44:50 +01:00
|
|
|
} else if (test_value > m_hiLimit) {
|
|
|
|
m_currentLimit = 2; //High limit violation
|
2014-09-15 16:33:30 +02:00
|
|
|
m_currentLimitError = test_value - m_hiLimit;
|
|
|
|
return 2;
|
|
|
|
};
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
m_currentLimit = 0; //Free from violation
|
2014-09-15 16:33:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
|
|
|
|
BodySW *body0, BodySW *body1) {
|
2021-05-05 12:44:11 +02:00
|
|
|
if (!needApplyTorques()) {
|
2021-05-04 14:28:27 +02:00
|
|
|
return 0.0f;
|
2021-05-05 12:44:11 +02:00
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t target_velocity = m_targetVelocity;
|
|
|
|
real_t maxMotorForce = m_maxMotorForce;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
//current error correction
|
2017-03-05 16:44:50 +01:00
|
|
|
if (m_currentLimit != 0) {
|
|
|
|
target_velocity = -m_ERP * m_currentLimitError / (timeStep);
|
|
|
|
maxMotorForce = m_maxLimitForce;
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
maxMotorForce *= timeStep;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
// current velocity difference
|
|
|
|
Vector3 vel_diff = body0->get_angular_velocity();
|
|
|
|
if (body1) {
|
|
|
|
vel_diff -= body1->get_angular_velocity();
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t rel_vel = axis.dot(vel_diff);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// correction velocity
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2019-01-16 16:42:53 +01:00
|
|
|
if (Math::is_zero_approx(motor_relvel)) {
|
2017-03-05 16:44:50 +01:00
|
|
|
return 0.0f; //no need for applying force
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// correction impulse
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t unclippedMotorImpulse = (1 + m_bounce) * motor_relvel * jacDiagABInv;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// clip correction impulse
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t clippedMotorImpulse;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
///@todo: should clip against accumulated impulse
|
|
|
|
if (unclippedMotorImpulse > 0.0f) {
|
|
|
|
clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse;
|
|
|
|
} else {
|
|
|
|
clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse;
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// sort with accumulated impulses
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t lo = real_t(-1e30);
|
|
|
|
real_t hi = real_t(1e30);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t oldaccumImpulse = m_accumulatedImpulse;
|
|
|
|
real_t sum = oldaccumImpulse + clippedMotorImpulse;
|
2021-01-12 16:57:55 +01:00
|
|
|
m_accumulatedImpulse = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 motorImp = clippedMotorImpulse * axis;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
body0->apply_torque_impulse(motorImp);
|
2021-05-05 12:44:11 +02:00
|
|
|
if (body1) {
|
2021-05-04 14:28:27 +02:00
|
|
|
body1->apply_torque_impulse(-motorImp);
|
2021-05-05 12:44:11 +02:00
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
return clippedMotorImpulse;
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////// End G6DOFRotationalLimitMotorSW ////////////////////////////////////
|
|
|
|
|
|
|
|
//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
|
|
|
|
real_t G6DOFTranslationalLimitMotorSW::solveLinearAxis(
|
|
|
|
real_t timeStep,
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t jacDiagABInv,
|
|
|
|
BodySW *body1, const Vector3 &pointInA,
|
|
|
|
BodySW *body2, const Vector3 &pointInB,
|
|
|
|
int limit_index,
|
|
|
|
const Vector3 &axis_normal_on_a,
|
|
|
|
const Vector3 &anchorPos) {
|
|
|
|
///find relative velocity
|
|
|
|
// Vector3 rel_pos1 = pointInA - body1->get_transform().origin;
|
|
|
|
// Vector3 rel_pos2 = pointInB - body2->get_transform().origin;
|
|
|
|
Vector3 rel_pos1 = anchorPos - body1->get_transform().origin;
|
|
|
|
Vector3 rel_pos2 = anchorPos - body2->get_transform().origin;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 vel1 = body1->get_velocity_in_local_point(rel_pos1);
|
|
|
|
Vector3 vel2 = body2->get_velocity_in_local_point(rel_pos2);
|
|
|
|
Vector3 vel = vel1 - vel2;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t rel_vel = axis_normal_on_a.dot(vel);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
/// apply displacement correction
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
//positional error (zeroth order error)
|
|
|
|
real_t depth = -(pointInA - pointInB).dot(axis_normal_on_a);
|
|
|
|
real_t lo = real_t(-1e30);
|
|
|
|
real_t hi = real_t(1e30);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t minLimit = m_lowerLimit[limit_index];
|
|
|
|
real_t maxLimit = m_upperLimit[limit_index];
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
//handle the limits
|
|
|
|
if (minLimit < maxLimit) {
|
2021-05-05 12:44:11 +02:00
|
|
|
if (depth > maxLimit) {
|
|
|
|
depth -= maxLimit;
|
|
|
|
lo = real_t(0.);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (depth < minLimit) {
|
|
|
|
depth -= minLimit;
|
|
|
|
hi = real_t(0.);
|
2017-03-05 16:44:50 +01:00
|
|
|
} else {
|
2021-05-05 12:44:11 +02:00
|
|
|
return 0.0f;
|
2017-03-05 16:44:50 +01:00
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t normalImpulse = m_limitSoftness[limit_index] * (m_restitution[limit_index] * depth / timeStep - m_damping[limit_index] * rel_vel) * jacDiagABInv;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t oldNormalImpulse = m_accumulatedImpulse[limit_index];
|
|
|
|
real_t sum = oldNormalImpulse + normalImpulse;
|
2021-01-12 16:57:55 +01:00
|
|
|
m_accumulatedImpulse[limit_index] = sum > hi ? real_t(0.) : (sum < lo ? real_t(0.) : sum);
|
2017-03-05 16:44:50 +01:00
|
|
|
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
|
|
|
|
body1->apply_impulse(rel_pos1, impulse_vector);
|
|
|
|
body2->apply_impulse(rel_pos2, -impulse_vector);
|
|
|
|
return normalImpulse;
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////// G6DOFTranslationalLimitMotorSW ////////////////////////////////////
|
|
|
|
|
2017-12-06 21:36:34 +01:00
|
|
|
Generic6DOFJointSW::Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
|
|
|
|
JointSW(_arr, 2),
|
|
|
|
m_frameInA(frameInA),
|
|
|
|
m_frameInB(frameInB),
|
|
|
|
m_useLinearReferenceFrameA(useLinearReferenceFrameA) {
|
2017-03-05 16:44:50 +01:00
|
|
|
A = rbA;
|
|
|
|
B = rbB;
|
|
|
|
A->add_constraint(this, 0);
|
|
|
|
B->add_constraint(this, 1);
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
void Generic6DOFJointSW::calculateAngleInfo() {
|
2017-09-16 18:50:46 +02:00
|
|
|
Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-09-17 02:48:46 +02:00
|
|
|
m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz();
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// in euler angle mode we do not actually constrain the angular velocity
|
2017-03-05 16:44:50 +01:00
|
|
|
// along the axes axis[0] and axis[2] (although we do use axis[1]) :
|
|
|
|
//
|
|
|
|
// to get constrain w2-w1 along ...not
|
|
|
|
// ------ --------------------- ------
|
|
|
|
// d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
|
|
|
|
// d(angle[1])/dt = 0 ax[1]
|
|
|
|
// d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
|
|
|
|
//
|
|
|
|
// constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
|
|
|
|
// to prove the result for angle[0], write the expression for angle[0] from
|
|
|
|
// GetInfo1 then take the derivative. to prove this for angle[2] it is
|
|
|
|
// easier to take the euler rate expression for d(angle[2])/dt with respect
|
|
|
|
// to the components of w and set that to 0.
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
Vector3 axis0 = m_calculatedTransformB.basis.get_axis(0);
|
|
|
|
Vector3 axis2 = m_calculatedTransformA.basis.get_axis(2);
|
|
|
|
|
|
|
|
m_calculatedAxis[1] = axis2.cross(axis0);
|
|
|
|
m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
|
|
|
|
m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
|
|
|
|
|
2017-01-14 12:26:56 +01:00
|
|
|
/*
|
|
|
|
if(m_debugDrawer)
|
|
|
|
{
|
|
|
|
|
|
|
|
char buff[300];
|
|
|
|
sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
|
|
|
|
m_calculatedAxisAngleDiff[0],
|
|
|
|
m_calculatedAxisAngleDiff[1],
|
|
|
|
m_calculatedAxisAngleDiff[2]);
|
|
|
|
m_debugDrawer->reportErrorWarning(buff);
|
|
|
|
}
|
|
|
|
*/
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
void Generic6DOFJointSW::calculateTransforms() {
|
|
|
|
m_calculatedTransformA = A->get_transform() * m_frameInA;
|
|
|
|
m_calculatedTransformB = B->get_transform() * m_frameInB;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
calculateAngleInfo();
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Generic6DOFJointSW::buildLinearJacobian(
|
2017-03-05 16:44:50 +01:00
|
|
|
JacobianEntrySW &jacLinear, const Vector3 &normalWorld,
|
|
|
|
const Vector3 &pivotAInW, const Vector3 &pivotBInW) {
|
2021-10-28 13:23:24 +02:00
|
|
|
memnew_placement(
|
|
|
|
&jacLinear,
|
|
|
|
JacobianEntrySW(
|
|
|
|
A->get_principal_inertia_axes().transposed(),
|
|
|
|
B->get_principal_inertia_axes().transposed(),
|
|
|
|
pivotAInW - A->get_transform().origin - A->get_center_of_mass(),
|
|
|
|
pivotBInW - B->get_transform().origin - B->get_center_of_mass(),
|
|
|
|
normalWorld,
|
|
|
|
A->get_inv_inertia(),
|
|
|
|
A->get_inv_mass(),
|
|
|
|
B->get_inv_inertia(),
|
|
|
|
B->get_inv_mass()));
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Generic6DOFJointSW::buildAngularJacobian(
|
2017-03-05 16:44:50 +01:00
|
|
|
JacobianEntrySW &jacAngular, const Vector3 &jointAxisW) {
|
2021-10-28 13:23:24 +02:00
|
|
|
memnew_placement(
|
|
|
|
&jacAngular,
|
|
|
|
JacobianEntrySW(
|
|
|
|
jointAxisW,
|
|
|
|
A->get_principal_inertia_axes().transposed(),
|
|
|
|
B->get_principal_inertia_axes().transposed(),
|
|
|
|
A->get_inv_inertia(),
|
|
|
|
B->get_inv_inertia()));
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
bool Generic6DOFJointSW::testAngularLimitMotor(int axis_index) {
|
|
|
|
real_t angle = m_calculatedAxisAngleDiff[axis_index];
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
//test limits
|
|
|
|
m_angularLimits[axis_index].testLimitValue(angle);
|
|
|
|
return m_angularLimits[axis_index].needApplyTorques();
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-08-11 21:10:05 +02:00
|
|
|
bool Generic6DOFJointSW::setup(real_t p_timestep) {
|
2021-04-16 02:53:15 +02:00
|
|
|
if ((A->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer::BODY_MODE_KINEMATIC)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
// Clear accumulated impulses for the next simulation step
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
m_angularLimits[i].m_accumulatedImpulse = real_t(0.);
|
|
|
|
}
|
|
|
|
//calculates transform
|
|
|
|
calculateTransforms();
|
|
|
|
|
|
|
|
// const Vector3& pivotAInW = m_calculatedTransformA.origin;
|
|
|
|
// const Vector3& pivotBInW = m_calculatedTransformB.origin;
|
2014-09-15 16:33:30 +02:00
|
|
|
calcAnchorPos();
|
|
|
|
Vector3 pivotAInW = m_AnchorPos;
|
|
|
|
Vector3 pivotBInW = m_AnchorPos;
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
// not used here
|
|
|
|
// Vector3 rel_pos1 = pivotAInW - A->get_transform().origin;
|
|
|
|
// Vector3 rel_pos2 = pivotBInW - B->get_transform().origin;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 normalWorld;
|
|
|
|
//linear part
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
|
2021-05-05 12:44:11 +02:00
|
|
|
if (m_useLinearReferenceFrameA) {
|
2017-03-05 16:44:50 +01:00
|
|
|
normalWorld = m_calculatedTransformA.basis.get_axis(i);
|
2021-05-05 12:44:11 +02:00
|
|
|
} else {
|
2017-03-05 16:44:50 +01:00
|
|
|
normalWorld = m_calculatedTransformB.basis.get_axis(i);
|
2021-05-05 12:44:11 +02:00
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
buildLinearJacobian(
|
|
|
|
m_jacLinear[i], normalWorld,
|
|
|
|
pivotAInW, pivotBInW);
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
// angular part
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
//calculates error angle
|
|
|
|
if (m_angularLimits[i].m_enableLimit && testAngularLimitMotor(i)) {
|
|
|
|
normalWorld = this->getAxis(i);
|
|
|
|
// Create angular atom
|
|
|
|
buildAngularJacobian(m_jacAng[i], normalWorld);
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-11 21:10:05 +02:00
|
|
|
void Generic6DOFJointSW::solve(real_t p_timestep) {
|
|
|
|
m_timeStep = p_timestep;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
//calculateTransforms();
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
int i;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
// linear
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 pointInA = m_calculatedTransformA.origin;
|
2014-09-15 16:33:30 +02:00
|
|
|
Vector3 pointInB = m_calculatedTransformB.origin;
|
|
|
|
|
|
|
|
real_t jacDiagABInv;
|
|
|
|
Vector3 linear_axis;
|
2017-03-05 16:44:50 +01:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
if (m_linearLimits.enable_limit[i] && m_linearLimits.isLimited(i)) {
|
|
|
|
jacDiagABInv = real_t(1.) / m_jacLinear[i].getDiagonal();
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2021-05-05 12:44:11 +02:00
|
|
|
if (m_useLinearReferenceFrameA) {
|
2017-03-05 16:44:50 +01:00
|
|
|
linear_axis = m_calculatedTransformA.basis.get_axis(i);
|
2021-05-05 12:44:11 +02:00
|
|
|
} else {
|
2017-03-05 16:44:50 +01:00
|
|
|
linear_axis = m_calculatedTransformB.basis.get_axis(i);
|
2021-05-05 12:44:11 +02:00
|
|
|
}
|
2017-03-05 16:44:50 +01:00
|
|
|
|
|
|
|
m_linearLimits.solveLinearAxis(
|
|
|
|
m_timeStep,
|
|
|
|
jacDiagABInv,
|
|
|
|
A, pointInA,
|
|
|
|
B, pointInB,
|
|
|
|
i, linear_axis, m_AnchorPos);
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
2017-03-05 16:44:50 +01:00
|
|
|
|
|
|
|
// angular
|
|
|
|
Vector3 angular_axis;
|
|
|
|
real_t angularJacDiagABInv;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
if (m_angularLimits[i].m_enableLimit && m_angularLimits[i].needApplyTorques()) {
|
2014-09-15 16:33:30 +02:00
|
|
|
// get axis
|
|
|
|
angular_axis = getAxis(i);
|
|
|
|
|
|
|
|
angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
|
|
|
|
}
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
void Generic6DOFJointSW::updateRHS(real_t timeStep) {
|
|
|
|
(void)timeStep;
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
Vector3 Generic6DOFJointSW::getAxis(int axis_index) const {
|
|
|
|
return m_calculatedAxis[axis_index];
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t Generic6DOFJointSW::getAngle(int axis_index) const {
|
|
|
|
return m_calculatedAxisAngleDiff[axis_index];
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2021-05-04 16:40:33 +02:00
|
|
|
void Generic6DOFJointSW::calcAnchorPos() {
|
2014-09-15 16:33:30 +02:00
|
|
|
real_t imA = A->get_inv_mass();
|
|
|
|
real_t imB = B->get_inv_mass();
|
|
|
|
real_t weight;
|
2017-03-05 16:44:50 +01:00
|
|
|
if (imB == real_t(0.0)) {
|
2014-09-15 16:33:30 +02:00
|
|
|
weight = real_t(1.0);
|
2017-03-05 16:44:50 +01:00
|
|
|
} else {
|
2014-09-15 16:33:30 +02:00
|
|
|
weight = imA / (imA + imB);
|
|
|
|
}
|
2017-03-05 16:44:50 +01:00
|
|
|
const Vector3 &pA = m_calculatedTransformA.origin;
|
|
|
|
const Vector3 &pB = m_calculatedTransformB.origin;
|
2014-09-15 16:33:30 +02:00
|
|
|
m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight);
|
|
|
|
} // Generic6DOFJointSW::calcAnchorPos()
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
void Generic6DOFJointSW::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) {
|
|
|
|
ERR_FAIL_INDEX(p_axis, 3);
|
|
|
|
switch (p_param) {
|
2014-09-15 16:33:30 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_lowerLimit[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_upperLimit[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_limitSoftness[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_restitution[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.m_damping[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_loLimit = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_hiLimit = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_limitSoftness = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_damping = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_bounce = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_maxLimitForce = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_ERP = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_targetVelocity = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_maxLimitForce = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
2018-09-26 13:13:56 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2018-11-09 12:58:57 +01:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2021-05-04 14:35:44 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_MAX:
|
|
|
|
break; // Can't happen, but silences warning
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
real_t Generic6DOFJointSW::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_axis, 3, 0);
|
|
|
|
switch (p_param) {
|
2014-09-15 16:33:30 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT: {
|
|
|
|
return m_linearLimits.m_lowerLimit[p_axis];
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT: {
|
|
|
|
return m_linearLimits.m_upperLimit[p_axis];
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS: {
|
|
|
|
return m_linearLimits.m_limitSoftness[p_axis];
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION: {
|
|
|
|
return m_linearLimits.m_restitution[p_axis];
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING: {
|
|
|
|
return m_linearLimits.m_damping[p_axis];
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT: {
|
|
|
|
return m_angularLimits[p_axis].m_loLimit;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT: {
|
|
|
|
return m_angularLimits[p_axis].m_hiLimit;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS: {
|
|
|
|
return m_angularLimits[p_axis].m_limitSoftness;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING: {
|
|
|
|
return m_angularLimits[p_axis].m_damping;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION: {
|
|
|
|
return m_angularLimits[p_axis].m_bounce;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT: {
|
|
|
|
return m_angularLimits[p_axis].m_maxLimitForce;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP: {
|
|
|
|
return m_angularLimits[p_axis].m_ERP;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY: {
|
|
|
|
return m_angularLimits[p_axis].m_targetVelocity;
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT: {
|
2017-02-03 22:23:23 +01:00
|
|
|
return m_angularLimits[p_axis].m_maxMotorForce;
|
2014-09-15 16:33:30 +02:00
|
|
|
|
|
|
|
} break;
|
2018-09-26 13:13:56 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2018-11-09 12:58:57 +01:00
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2021-05-04 14:35:44 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_MAX:
|
|
|
|
break; // Can't happen, but silences warning
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) {
|
|
|
|
ERR_FAIL_INDEX(p_axis, 3);
|
2014-09-15 16:33:30 +02:00
|
|
|
|
2017-03-05 16:44:50 +01:00
|
|
|
switch (p_flag) {
|
2014-09-15 16:33:30 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_linearLimits.enable_limit[p_axis] = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_enableLimit = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
|
2017-03-05 16:44:50 +01:00
|
|
|
m_angularLimits[p_axis].m_enableMotor = p_value;
|
2014-09-15 16:33:30 +02:00
|
|
|
} break;
|
2018-09-26 13:13:56 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2018-11-09 12:58:57 +01:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2021-05-04 14:35:44 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_MAX:
|
|
|
|
break; // Can't happen, but silences warning
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
}
|
2017-03-05 16:44:50 +01:00
|
|
|
bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
|
|
|
|
ERR_FAIL_INDEX_V(p_axis, 3, 0);
|
|
|
|
switch (p_flag) {
|
2014-09-15 16:33:30 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: {
|
|
|
|
return m_linearLimits.enable_limit[p_axis];
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
|
|
|
|
return m_angularLimits[p_axis].m_enableLimit;
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR: {
|
|
|
|
return m_angularLimits[p_axis].m_enableMotor;
|
|
|
|
} break;
|
2018-09-26 13:13:56 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2018-11-09 12:58:57 +01:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: {
|
|
|
|
// Not implemented in GodotPhysics backend
|
|
|
|
} break;
|
2021-05-04 14:35:44 +02:00
|
|
|
case PhysicsServer::G6DOF_JOINT_FLAG_MAX:
|
|
|
|
break; // Can't happen, but silences warning
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|
|
|
|
|
2021-05-04 16:28:24 +02:00
|
|
|
return false;
|
2014-09-15 16:33:30 +02:00
|
|
|
}
|