Path: blob/master/modules/godot_physics_3d/joints/godot_slider_joint_3d.cpp
10278 views
/**************************************************************************/1/* godot_slider_joint_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930/*31Adapted to Godot from the Bullet library.32*/3334/*35Bullet Continuous Collision Detection and Physics Library36Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/3738This software is provided 'as-is', without any express or implied warranty.39In no event will the authors be held liable for any damages arising from the use of this software.40Permission is granted to anyone to use this software for any purpose,41including commercial applications, and to alter it and redistribute it freely,42subject to the following restrictions:43441. 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.452. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.463. This notice may not be removed or altered from any source distribution.47*/4849/*50Added by Roman Ponomarev ([email protected])51April 04, 20085253*/5455#include "godot_slider_joint_3d.h"5657//-----------------------------------------------------------------------------5859GodotSliderJoint3D::GodotSliderJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameInA, const Transform3D &frameInB) :60GodotJoint3D(_arr, 2),61m_frameInA(frameInA),62m_frameInB(frameInB) {63A = rbA;64B = rbB;6566A->add_constraint(this, 0);67B->add_constraint(this, 1);68}6970//-----------------------------------------------------------------------------7172bool GodotSliderJoint3D::setup(real_t p_step) {73dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);74dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);7576if (!dynamic_A && !dynamic_B) {77return false;78}7980//calculate transforms81m_calculatedTransformA = A->get_transform() * m_frameInA;82m_calculatedTransformB = B->get_transform() * m_frameInB;83m_realPivotAInW = m_calculatedTransformA.origin;84m_realPivotBInW = m_calculatedTransformB.origin;85m_sliderAxis = m_calculatedTransformA.basis.get_column(0); // along X86m_delta = m_realPivotBInW - m_realPivotAInW;87m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;88m_relPosA = m_projPivotInW - A->get_transform().origin;89m_relPosB = m_realPivotBInW - B->get_transform().origin;90Vector3 normalWorld;91int i;92//linear part93for (i = 0; i < 3; i++) {94normalWorld = m_calculatedTransformA.basis.get_column(i);95memnew_placement(96&m_jacLin[i],97GodotJacobianEntry3D(98A->get_principal_inertia_axes().transposed(),99B->get_principal_inertia_axes().transposed(),100m_relPosA - A->get_center_of_mass(),101m_relPosB - B->get_center_of_mass(),102normalWorld,103A->get_inv_inertia(),104A->get_inv_mass(),105B->get_inv_inertia(),106B->get_inv_mass()));107m_jacLinDiagABInv[i] = real_t(1.) / m_jacLin[i].getDiagonal();108m_depth[i] = m_delta.dot(normalWorld);109}110testLinLimits();111// angular part112for (i = 0; i < 3; i++) {113normalWorld = m_calculatedTransformA.basis.get_column(i);114memnew_placement(115&m_jacAng[i],116GodotJacobianEntry3D(117normalWorld,118A->get_principal_inertia_axes().transposed(),119B->get_principal_inertia_axes().transposed(),120A->get_inv_inertia(),121B->get_inv_inertia()));122}123testAngLimits();124Vector3 axisA = m_calculatedTransformA.basis.get_column(0);125m_kAngle = real_t(1.0) / (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA));126// clear accumulator for motors127m_accumulatedLinMotorImpulse = real_t(0.0);128m_accumulatedAngMotorImpulse = real_t(0.0);129130return true;131}132133//-----------------------------------------------------------------------------134135void GodotSliderJoint3D::solve(real_t p_step) {136int i;137// linear138Vector3 velA = A->get_velocity_in_local_point(m_relPosA);139Vector3 velB = B->get_velocity_in_local_point(m_relPosB);140Vector3 vel = velA - velB;141for (i = 0; i < 3; i++) {142const Vector3 &normal = m_jacLin[i].m_linearJointAxis;143real_t rel_vel = normal.dot(vel);144// calculate positional error145real_t depth = m_depth[i];146// get parameters147real_t softness = (i) ? m_softnessOrthoLin : (m_solveLinLim ? m_softnessLimLin : m_softnessDirLin);148real_t restitution = (i) ? m_restitutionOrthoLin : (m_solveLinLim ? m_restitutionLimLin : m_restitutionDirLin);149real_t damping = (i) ? m_dampingOrthoLin : (m_solveLinLim ? m_dampingLimLin : m_dampingDirLin);150// Calculate and apply impulse.151real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i];152Vector3 impulse_vector = normal * normalImpulse;153if (dynamic_A) {154A->apply_impulse(impulse_vector, m_relPosA);155}156if (dynamic_B) {157B->apply_impulse(-impulse_vector, m_relPosB);158}159if (m_poweredLinMotor && (!i)) { // apply linear motor160if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) {161real_t desiredMotorVel = m_targetLinMotorVelocity;162real_t motor_relvel = desiredMotorVel + rel_vel;163normalImpulse = -motor_relvel * m_jacLinDiagABInv[i];164// clamp accumulated impulse165real_t new_acc = m_accumulatedLinMotorImpulse + Math::abs(normalImpulse);166if (new_acc > m_maxLinMotorForce) {167new_acc = m_maxLinMotorForce;168}169real_t del = new_acc - m_accumulatedLinMotorImpulse;170if (normalImpulse < real_t(0.0)) {171normalImpulse = -del;172} else {173normalImpulse = del;174}175m_accumulatedLinMotorImpulse = new_acc;176// apply clamped impulse177impulse_vector = normal * normalImpulse;178if (dynamic_A) {179A->apply_impulse(impulse_vector, m_relPosA);180}181if (dynamic_B) {182B->apply_impulse(-impulse_vector, m_relPosB);183}184}185}186}187// angular188// get axes in world space189Vector3 axisA = m_calculatedTransformA.basis.get_column(0);190Vector3 axisB = m_calculatedTransformB.basis.get_column(0);191192const Vector3 &angVelA = A->get_angular_velocity();193const Vector3 &angVelB = B->get_angular_velocity();194195Vector3 angVelAroundAxisA = axisA * axisA.dot(angVelA);196Vector3 angVelAroundAxisB = axisB * axisB.dot(angVelB);197198Vector3 angAorthog = angVelA - angVelAroundAxisA;199Vector3 angBorthog = angVelB - angVelAroundAxisB;200Vector3 velrelOrthog = angAorthog - angBorthog;201//solve orthogonal angular velocity correction202real_t len = velrelOrthog.length();203if (len > real_t(0.00001)) {204Vector3 normal = velrelOrthog.normalized();205real_t denom = A->compute_angular_impulse_denominator(normal) + B->compute_angular_impulse_denominator(normal);206velrelOrthog *= (real_t(1.) / denom) * m_dampingOrthoAng * m_softnessOrthoAng;207}208//solve angular positional correction209Vector3 angularError = axisA.cross(axisB) * (real_t(1.) / p_step);210real_t len2 = angularError.length();211if (len2 > real_t(0.00001)) {212Vector3 normal2 = angularError.normalized();213real_t denom2 = A->compute_angular_impulse_denominator(normal2) + B->compute_angular_impulse_denominator(normal2);214angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;215}216// apply impulse217if (dynamic_A) {218A->apply_torque_impulse(-velrelOrthog + angularError);219}220if (dynamic_B) {221B->apply_torque_impulse(velrelOrthog - angularError);222}223real_t impulseMag;224//solve angular limits225if (m_solveAngLim) {226impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingLimAng + m_angDepth * m_restitutionLimAng / p_step;227impulseMag *= m_kAngle * m_softnessLimAng;228} else {229impulseMag = (angVelB - angVelA).dot(axisA) * m_dampingDirAng + m_angDepth * m_restitutionDirAng / p_step;230impulseMag *= m_kAngle * m_softnessDirAng;231}232Vector3 impulse = axisA * impulseMag;233if (dynamic_A) {234A->apply_torque_impulse(impulse);235}236if (dynamic_B) {237B->apply_torque_impulse(-impulse);238}239//apply angular motor240if (m_poweredAngMotor) {241if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) {242Vector3 velrel = angVelAroundAxisA - angVelAroundAxisB;243real_t projRelVel = velrel.dot(axisA);244245real_t desiredMotorVel = m_targetAngMotorVelocity;246real_t motor_relvel = desiredMotorVel - projRelVel;247248real_t angImpulse = m_kAngle * motor_relvel;249// clamp accumulated impulse250real_t new_acc = m_accumulatedAngMotorImpulse + Math::abs(angImpulse);251if (new_acc > m_maxAngMotorForce) {252new_acc = m_maxAngMotorForce;253}254real_t del = new_acc - m_accumulatedAngMotorImpulse;255if (angImpulse < real_t(0.0)) {256angImpulse = -del;257} else {258angImpulse = del;259}260m_accumulatedAngMotorImpulse = new_acc;261// apply clamped impulse262Vector3 motorImp = angImpulse * axisA;263if (dynamic_A) {264A->apply_torque_impulse(motorImp);265}266if (dynamic_B) {267B->apply_torque_impulse(-motorImp);268}269}270}271}272273//-----------------------------------------------------------------------------274275void GodotSliderJoint3D::calculateTransforms() {276m_calculatedTransformA = A->get_transform() * m_frameInA;277m_calculatedTransformB = B->get_transform() * m_frameInB;278m_realPivotAInW = m_calculatedTransformA.origin;279m_realPivotBInW = m_calculatedTransformB.origin;280m_sliderAxis = m_calculatedTransformA.basis.get_column(0); // along X281m_delta = m_realPivotBInW - m_realPivotAInW;282m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;283Vector3 normalWorld;284int i;285//linear part286for (i = 0; i < 3; i++) {287normalWorld = m_calculatedTransformA.basis.get_column(i);288m_depth[i] = m_delta.dot(normalWorld);289}290}291292//-----------------------------------------------------------------------------293294void GodotSliderJoint3D::testLinLimits() {295m_solveLinLim = false;296m_linPos = m_depth[0];297if (m_lowerLinLimit <= m_upperLinLimit) {298if (m_depth[0] > m_upperLinLimit) {299m_depth[0] -= m_upperLinLimit;300m_solveLinLim = true;301} else if (m_depth[0] < m_lowerLinLimit) {302m_depth[0] -= m_lowerLinLimit;303m_solveLinLim = true;304} else {305m_depth[0] = real_t(0.);306}307} else {308m_depth[0] = real_t(0.);309}310}311312//-----------------------------------------------------------------------------313314void GodotSliderJoint3D::testAngLimits() {315m_angDepth = real_t(0.);316m_solveAngLim = false;317if (m_lowerAngLimit <= m_upperAngLimit) {318const Vector3 axisA0 = m_calculatedTransformA.basis.get_column(1);319const Vector3 axisA1 = m_calculatedTransformA.basis.get_column(2);320const Vector3 axisB0 = m_calculatedTransformB.basis.get_column(1);321real_t rot = atan2fast(axisB0.dot(axisA1), axisB0.dot(axisA0));322if (rot < m_lowerAngLimit) {323m_angDepth = rot - m_lowerAngLimit;324m_solveAngLim = true;325} else if (rot > m_upperAngLimit) {326m_angDepth = rot - m_upperAngLimit;327m_solveAngLim = true;328}329}330}331332//-----------------------------------------------------------------------------333334Vector3 GodotSliderJoint3D::getAncorInA() {335Vector3 ancorInA;336ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * real_t(0.5) * m_sliderAxis;337ancorInA = A->get_transform().inverse().xform(ancorInA);338return ancorInA;339}340341//-----------------------------------------------------------------------------342343Vector3 GodotSliderJoint3D::getAncorInB() {344Vector3 ancorInB;345ancorInB = m_frameInB.origin;346return ancorInB;347}348349void GodotSliderJoint3D::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) {350switch (p_param) {351case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER:352m_upperLinLimit = p_value;353break;354case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER:355m_lowerLinLimit = p_value;356break;357case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS:358m_softnessLimLin = p_value;359break;360case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION:361m_restitutionLimLin = p_value;362break;363case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING:364m_dampingLimLin = p_value;365break;366case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS:367m_softnessDirLin = p_value;368break;369case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION:370m_restitutionDirLin = p_value;371break;372case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING:373m_dampingDirLin = p_value;374break;375case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS:376m_softnessOrthoLin = p_value;377break;378case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION:379m_restitutionOrthoLin = p_value;380break;381case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING:382m_dampingOrthoLin = p_value;383break;384385case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER:386m_upperAngLimit = p_value;387break;388case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER:389m_lowerAngLimit = p_value;390break;391case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS:392m_softnessLimAng = p_value;393break;394case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION:395m_restitutionLimAng = p_value;396break;397case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING:398m_dampingLimAng = p_value;399break;400case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS:401m_softnessDirAng = p_value;402break;403case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION:404m_restitutionDirAng = p_value;405break;406case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING:407m_dampingDirAng = p_value;408break;409case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS:410m_softnessOrthoAng = p_value;411break;412case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION:413m_restitutionOrthoAng = p_value;414break;415case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING:416m_dampingOrthoAng = p_value;417break;418419case PhysicsServer3D::SLIDER_JOINT_MAX:420break; // Can't happen, but silences warning421}422}423424real_t GodotSliderJoint3D::get_param(PhysicsServer3D::SliderJointParam p_param) const {425switch (p_param) {426case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER:427return m_upperLinLimit;428case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER:429return m_lowerLinLimit;430case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS:431return m_softnessLimLin;432case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION:433return m_restitutionLimLin;434case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING:435return m_dampingLimLin;436case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS:437return m_softnessDirLin;438case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION:439return m_restitutionDirLin;440case PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING:441return m_dampingDirLin;442case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS:443return m_softnessOrthoLin;444case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION:445return m_restitutionOrthoLin;446case PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING:447return m_dampingOrthoLin;448449case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER:450return m_upperAngLimit;451case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER:452return m_lowerAngLimit;453case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS:454return m_softnessLimAng;455case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION:456return m_restitutionLimAng;457case PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING:458return m_dampingLimAng;459case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS:460return m_softnessDirAng;461case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION:462return m_restitutionDirAng;463case PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING:464return m_dampingDirAng;465case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS:466return m_softnessOrthoAng;467case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION:468return m_restitutionOrthoAng;469case PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING:470return m_dampingOrthoAng;471472case PhysicsServer3D::SLIDER_JOINT_MAX:473break; // Can't happen, but silences warning474}475476return 0;477}478479480