Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/ConstraintPart/SpringPart.h
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56JPH_NAMESPACE_BEGIN7#ifndef JPH_PLATFORM_DOXYGEN // Somehow Doxygen gets confused and thinks the parameters to CalculateSpringProperties belong to this macro8JPH_MSVC_SUPPRESS_WARNING(4723) // potential divide by 0 - caused by line: outEffectiveMass = 1.0f / inInvEffectiveMass, note that JPH_NAMESPACE_BEGIN already pushes the warning state9#endif // !JPH_PLATFORM_DOXYGEN1011/// Class used in other constraint parts to calculate the required bias factor in the lagrange multiplier for creating springs12class SpringPart13{14private:15JPH_INLINE void CalculateSpringPropertiesHelper(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inStiffness, float inDamping, float &outEffectiveMass)16{17// Soft constraints as per: Soft Constraints: Reinventing The Spring - Erin Catto - GDC 20111819// Note that the calculation of beta and gamma below are based on the solution of an implicit Euler integration scheme20// This scheme is unconditionally stable but has built in damping, so even when you set the damping ratio to 0 there will still21// be damping. See page 16 and 32.2223// Calculate softness (gamma in the slides)24// See page 34 and note that the gamma needs to be divided by delta time since we're working with impulses rather than forces:25// softness = 1 / (dt * (c + dt * k))26// Note that the spring stiffness is k and the spring damping is c27mSoftness = 1.0f / (inDeltaTime * (inDamping + inDeltaTime * inStiffness));2829// Calculate bias factor (baumgarte stabilization):30// beta = dt * k / (c + dt * k) = dt * k^2 * softness31// b = beta / dt * C = dt * k * softness * C32mBias = inBias + inDeltaTime * inStiffness * mSoftness * inC;3334// Update the effective mass, see post by Erin Catto: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=135435//36// Newton's Law:37// M * (v2 - v1) = J^T * lambda38//39// Velocity constraint with softness and Baumgarte:40// J * v2 + softness * lambda + b = 041//42// where b = beta * C / dt43//44// We know everything except v2 and lambda.45//46// First solve Newton's law for v2 in terms of lambda:47//48// v2 = v1 + M^-1 * J^T * lambda49//50// Substitute this expression into the velocity constraint:51//52// J * (v1 + M^-1 * J^T * lambda) + softness * lambda + b = 053//54// Now collect coefficients of lambda:55//56// (J * M^-1 * J^T + softness) * lambda = - J * v1 - b57//58// Now we define:59//60// K = J * M^-1 * J^T + softness61//62// So our new effective mass is K^-163outEffectiveMass = 1.0f / (inInvEffectiveMass + mSoftness);64}6566public:67/// Turn off the spring and set a bias only68///69/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b70inline void CalculateSpringPropertiesWithBias(float inBias)71{72mSoftness = 0.0f;73mBias = inBias;74}7576/// Calculate spring properties based on frequency and damping ratio77///78/// @param inDeltaTime Time step79/// @param inInvEffectiveMass Inverse effective mass K80/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b81/// @param inC Value of the constraint equation (C). Set to zero if you don't want to drive the constraint to zero with a spring.82/// @param inFrequency Oscillation frequency (Hz). Set to zero if you don't want to drive the constraint to zero with a spring.83/// @param inDamping Damping factor (0 = no damping, 1 = critical damping). Set to zero if you don't want to drive the constraint to zero with a spring.84/// @param outEffectiveMass On return, this contains the new effective mass K^-185inline void CalculateSpringPropertiesWithFrequencyAndDamping(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inFrequency, float inDamping, float &outEffectiveMass)86{87outEffectiveMass = 1.0f / inInvEffectiveMass;8889if (inFrequency > 0.0f)90{91// Calculate angular frequency92float omega = 2.0f * JPH_PI * inFrequency;9394// Calculate spring stiffness k and damping constant c (page 45)95float k = outEffectiveMass * Square(omega);96float c = 2.0f * outEffectiveMass * inDamping * omega;9798CalculateSpringPropertiesHelper(inDeltaTime, inInvEffectiveMass, inBias, inC, k, c, outEffectiveMass);99}100else101{102CalculateSpringPropertiesWithBias(inBias);103}104}105106/// Calculate spring properties with spring Stiffness (k) and damping (c), this is based on the spring equation: F = -k * x - c * v107///108/// @param inDeltaTime Time step109/// @param inInvEffectiveMass Inverse effective mass K110/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b111/// @param inC Value of the constraint equation (C). Set to zero if you don't want to drive the constraint to zero with a spring.112/// @param inStiffness Spring stiffness k. Set to zero if you don't want to drive the constraint to zero with a spring.113/// @param inDamping Spring damping coefficient c. Set to zero if you don't want to drive the constraint to zero with a spring.114/// @param outEffectiveMass On return, this contains the new effective mass K^-1115inline void CalculateSpringPropertiesWithStiffnessAndDamping(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inStiffness, float inDamping, float &outEffectiveMass)116{117if (inStiffness > 0.0f)118{119CalculateSpringPropertiesHelper(inDeltaTime, inInvEffectiveMass, inBias, inC, inStiffness, inDamping, outEffectiveMass);120}121else122{123outEffectiveMass = 1.0f / inInvEffectiveMass;124125CalculateSpringPropertiesWithBias(inBias);126}127}128129/// Returns if this spring is active130inline bool IsActive() const131{132return mSoftness != 0.0f;133}134135/// Get total bias b, including supplied bias and bias for spring: lambda = J v + b136inline float GetBias(float inTotalLambda) const137{138// Remainder of post by Erin Catto: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=1354139//140// Each iteration we are not computing the whole impulse, we are computing an increment to the impulse and we are updating the velocity.141// Also, as we solve each constraint we get a perfect v2, but then some other constraint will come along and mess it up.142// So we want to patch up the constraint while acknowledging the accumulated impulse and the damaged velocity.143// To help with that we use P for the accumulated impulse and lambda as the update. Mathematically we have:144//145// M * (v2new - v2damaged) = J^T * lambda146// J * v2new + softness * (total_lambda + lambda) + b = 0147//148// If we solve this we get:149//150// v2new = v2damaged + M^-1 * J^T * lambda151// J * (v2damaged + M^-1 * J^T * lambda) + softness * total_lambda + softness * lambda + b = 0152//153// (J * M^-1 * J^T + softness) * lambda = -(J * v2damaged + softness * total_lambda + b)154//155// So our lagrange multiplier becomes:156//157// lambda = -K^-1 (J v + softness * total_lambda + b)158//159// So we return the bias: softness * total_lambda + b160return mSoftness * inTotalLambda + mBias;161}162163private:164float mBias = 0.0f;165float mSoftness = 0.0f;166};167168JPH_NAMESPACE_END169170171