Working on cone limit for BallAndSocket joint

This commit is contained in:
Daniel Chappuis 2021-03-21 15:22:43 +01:00
parent ef9ac01e52
commit 716aa1940d
4 changed files with 155 additions and 0 deletions

View File

@ -85,6 +85,18 @@ class BallAndSocketJointComponents : public Components {
/// Accumulated impulse /// Accumulated impulse
Vector3* mImpulse; Vector3* mImpulse;
/// True if the joint cone limit is enabled
bool* mIsConeLimitEnabled;
/// Cone limit impulse
decimal* mConeLimitImpulse;
/// Cone limit half angle
decimal* mConeLimitHalfAngle;
/// Inverse of mass matrix K=JM^-1J^t for the cone limit
decimal* mInverseMassMatrixConeLimit;
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
/// Allocate memory for a given number of components /// Allocate memory for a given number of components
@ -181,6 +193,30 @@ class BallAndSocketJointComponents : public Components {
/// Set the accumulated impulse /// Set the accumulated impulse
void setImpulse(Entity jointEntity, const Vector3& impulse); void setImpulse(Entity jointEntity, const Vector3& impulse);
/// Return true if the cone limit is enabled
bool getIsConeLimitEnabled(Entity jointEntity) const;
/// Set to true if the cone limit is enabled
void setIsConeLimitEnabled(Entity jointEntity, bool isLimitEnabled);
/// Return the cone limit impulse
bool getConeLimitImpulse(Entity jointEntity) const;
/// Set the cone limit impulse
void setConeLimitImpulse(Entity jointEntity, decimal impulse);
/// Return the cone limit half angle
bool getConeLimitHalfAngle(Entity jointEntity) const;
/// Set the cone limit half angle
void setConeLimitHalfAngle(Entity jointEntity, decimal halfAngle);
/// Return the inverse mass matrix cone limit
bool getInverseMassMatrixConeLimit(Entity jointEntity) const;
/// Set the inverse mass matrix cone limit
void setInverseMassMatrixCone(Entity jointEntity, decimal inverseMassMatrix);
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class BroadPhaseSystem; friend class BroadPhaseSystem;
@ -327,6 +363,62 @@ RP3D_FORCE_INLINE void BallAndSocketJointComponents::setImpulse(Entity jointEnti
mImpulse[mMapEntityToComponentIndex[jointEntity]] = impulse; mImpulse[mMapEntityToComponentIndex[jointEntity]] = impulse;
} }
// Return true if the cone limit is enabled
RP3D_FORCE_INLINE bool BallAndSocketJointComponents::getIsConeLimitEnabled(Entity jointEntity) const {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
return mIsConeLimitEnabled[mMapEntityToComponentIndex[jointEntity]];
}
// Set to true if the cone limit is enabled
RP3D_FORCE_INLINE void BallAndSocketJointComponents::setIsConeLimitEnabled(Entity jointEntity, bool isLimitEnabled) {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
mIsConeLimitEnabled[mMapEntityToComponentIndex[jointEntity]] = isLimitEnabled;
}
// Return the cone limit impulse
RP3D_FORCE_INLINE bool BallAndSocketJointComponents::getConeLimitImpulse(Entity jointEntity) const {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
return mConeLimitImpulse[mMapEntityToComponentIndex[jointEntity]];
}
// Set the cone limit impulse
RP3D_FORCE_INLINE void BallAndSocketJointComponents::setConeLimitImpulse(Entity jointEntity, decimal impulse) {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
mConeLimitImpulse[mMapEntityToComponentIndex[jointEntity]] = impulse;
}
// Return the cone limit half angle
RP3D_FORCE_INLINE bool BallAndSocketJointComponents::getConeLimitHalfAngle(Entity jointEntity) const {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
return mConeLimitHalfAngle[mMapEntityToComponentIndex[jointEntity]];
}
// Set the cone limit half angle
RP3D_FORCE_INLINE void BallAndSocketJointComponents::setConeLimitHalfAngle(Entity jointEntity, decimal halfAngle) {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
mConeLimitHalfAngle[mMapEntityToComponentIndex[jointEntity]] = halfAngle;
}
// Return the inverse mass matrix cone limit
RP3D_FORCE_INLINE bool BallAndSocketJointComponents::getInverseMassMatrixConeLimit(Entity jointEntity) const {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
return mInverseMassMatrixConeLimit[mMapEntityToComponentIndex[jointEntity]];
}
// Set the inverse mass matrix cone limit
RP3D_FORCE_INLINE void BallAndSocketJointComponents::setInverseMassMatrixCone(Entity jointEntity, decimal inverseMassMatrix) {
assert(mMapEntityToComponentIndex.containsKey(jointEntity));
mInverseMassMatrixConeLimit[mMapEntityToComponentIndex[jointEntity]] = inverseMassMatrix;
}
} }
#endif #endif

View File

@ -121,6 +121,18 @@ class BallAndSocketJoint : public Joint {
/// Deleted copy-constructor /// Deleted copy-constructor
BallAndSocketJoint(const BallAndSocketJoint& constraint) = delete; BallAndSocketJoint(const BallAndSocketJoint& constraint) = delete;
/// Enable/disable the cone limit of the joint
void enableConeLimit(bool isLimitEnabled);
/// Return true if the cone limit or the joint is enabled
bool isConeLimitEnabled() const;
/// Set the cone limit half angle
void setConeLimitHalfAngle(decimal coneHalfAngle);
/// Return the cone limit half angle
decimal getConeLimitHalfAngle() const;
/// Return the force (in Newtons) on body 2 required to satisfy the joint constraint in world-space /// Return the force (in Newtons) on body 2 required to satisfy the joint constraint in world-space
virtual Vector3 getReactionForce(decimal timeStep) const override; virtual Vector3 getReactionForce(decimal timeStep) const override;

View File

@ -67,6 +67,10 @@ void BallAndSocketJointComponents::allocate(uint32 nbComponentsToAllocate) {
Vector3* newBiasVector = reinterpret_cast<Vector3*>(newI2 + nbComponentsToAllocate); Vector3* newBiasVector = reinterpret_cast<Vector3*>(newI2 + nbComponentsToAllocate);
Matrix3x3* newInverseMassMatrix = reinterpret_cast<Matrix3x3*>(newBiasVector + nbComponentsToAllocate); Matrix3x3* newInverseMassMatrix = reinterpret_cast<Matrix3x3*>(newBiasVector + nbComponentsToAllocate);
Vector3* newImpulse = reinterpret_cast<Vector3*>(newInverseMassMatrix + nbComponentsToAllocate); Vector3* newImpulse = reinterpret_cast<Vector3*>(newInverseMassMatrix + nbComponentsToAllocate);
bool* newIsConeLimitEnabled = reinterpret_cast<bool*>(newImpulse + nbComponentsToAllocate);
decimal* newConeLimitImpulse = reinterpret_cast<decimal*>(newIsConeLimitEnabled + nbComponentsToAllocate);
decimal* newConeLimitHalfAngle = reinterpret_cast<decimal*>(newConeLimitImpulse + nbComponentsToAllocate);
decimal* newInverseMassMatrixConeLimit = reinterpret_cast<decimal*>(newConeLimitHalfAngle + nbComponentsToAllocate);
// If there was already components before // If there was already components before
if (mNbComponents > 0) { if (mNbComponents > 0) {
@ -83,6 +87,10 @@ void BallAndSocketJointComponents::allocate(uint32 nbComponentsToAllocate) {
memcpy(newBiasVector, mBiasVector, mNbComponents * sizeof(Vector3)); memcpy(newBiasVector, mBiasVector, mNbComponents * sizeof(Vector3));
memcpy(newInverseMassMatrix, mInverseMassMatrix, mNbComponents * sizeof(Matrix3x3)); memcpy(newInverseMassMatrix, mInverseMassMatrix, mNbComponents * sizeof(Matrix3x3));
memcpy(newImpulse, mImpulse, mNbComponents * sizeof(Vector3)); memcpy(newImpulse, mImpulse, mNbComponents * sizeof(Vector3));
memcpy(newIsConeLimitEnabled, mIsConeLimitEnabled, mNbComponents * sizeof(bool));
memcpy(newConeLimitImpulse, mConeLimitImpulse, mNbComponents * sizeof(decimal));
memcpy(newConeLimitHalfAngle, mConeLimitHalfAngle, mNbComponents * sizeof(decimal));
memcpy(newInverseMassMatrixConeLimit, mInverseMassMatrixConeLimit, mNbComponents * sizeof(decimal));
// Deallocate previous memory // Deallocate previous memory
mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize); mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize);
@ -101,6 +109,10 @@ void BallAndSocketJointComponents::allocate(uint32 nbComponentsToAllocate) {
mBiasVector = newBiasVector; mBiasVector = newBiasVector;
mInverseMassMatrix = newInverseMassMatrix; mInverseMassMatrix = newInverseMassMatrix;
mImpulse = newImpulse; mImpulse = newImpulse;
mIsConeLimitEnabled = newIsConeLimitEnabled;
mConeLimitImpulse = newConeLimitImpulse;
mConeLimitHalfAngle = newConeLimitHalfAngle;
mInverseMassMatrixConeLimit = newInverseMassMatrixConeLimit;
} }
// Add a component // Add a component
@ -121,6 +133,10 @@ void BallAndSocketJointComponents::addComponent(Entity jointEntity, bool isSleep
new (mBiasVector + index) Vector3(0, 0, 0); new (mBiasVector + index) Vector3(0, 0, 0);
new (mInverseMassMatrix + index) Matrix3x3(); new (mInverseMassMatrix + index) Matrix3x3();
new (mImpulse + index) Vector3(0, 0, 0); new (mImpulse + index) Vector3(0, 0, 0);
mIsConeLimitEnabled[index] = false;
mConeLimitImpulse[index] = decimal(0.0);
mConeLimitHalfAngle[index] = PI_RP3D;
mInverseMassMatrixConeLimit[index] = decimal(0.0);
// Map the entity with the new component lookup index // Map the entity with the new component lookup index
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(jointEntity, index)); mMapEntityToComponentIndex.add(Pair<Entity, uint32>(jointEntity, index));
@ -149,6 +165,10 @@ void BallAndSocketJointComponents::moveComponentToIndex(uint32 srcIndex, uint32
new (mBiasVector + destIndex) Vector3(mBiasVector[srcIndex]); new (mBiasVector + destIndex) Vector3(mBiasVector[srcIndex]);
new (mInverseMassMatrix + destIndex) Matrix3x3(mInverseMassMatrix[srcIndex]); new (mInverseMassMatrix + destIndex) Matrix3x3(mInverseMassMatrix[srcIndex]);
new (mImpulse + destIndex) Vector3(mImpulse[srcIndex]); new (mImpulse + destIndex) Vector3(mImpulse[srcIndex]);
mIsConeLimitEnabled[destIndex] = mIsConeLimitEnabled[srcIndex];
mConeLimitImpulse[destIndex] = mConeLimitImpulse[srcIndex];
mConeLimitHalfAngle[destIndex] = mConeLimitHalfAngle[srcIndex];
mInverseMassMatrixConeLimit[destIndex] = mInverseMassMatrixConeLimit[srcIndex];
// Destroy the source component // Destroy the source component
destroyComponent(srcIndex); destroyComponent(srcIndex);
@ -176,6 +196,10 @@ void BallAndSocketJointComponents::swapComponents(uint32 index1, uint32 index2)
Vector3 biasVector1(mBiasVector[index1]); Vector3 biasVector1(mBiasVector[index1]);
Matrix3x3 inverseMassMatrix1(mInverseMassMatrix[index1]); Matrix3x3 inverseMassMatrix1(mInverseMassMatrix[index1]);
Vector3 impulse1(mImpulse[index1]); Vector3 impulse1(mImpulse[index1]);
bool isConeLimitEnabled1 = mIsConeLimitEnabled[index1];
decimal coneLimitImpulse1 = mConeLimitImpulse[index1];
decimal coneLimitHalfAngle1 = mConeLimitHalfAngle[index1];
decimal inverseMassMatrixConeLimit1 = mInverseMassMatrixConeLimit[index1];
// Destroy component 1 // Destroy component 1
destroyComponent(index1); destroyComponent(index1);
@ -194,6 +218,10 @@ void BallAndSocketJointComponents::swapComponents(uint32 index1, uint32 index2)
new (mBiasVector + index2) Vector3(biasVector1); new (mBiasVector + index2) Vector3(biasVector1);
new (mInverseMassMatrix + index2) Matrix3x3(inverseMassMatrix1); new (mInverseMassMatrix + index2) Matrix3x3(inverseMassMatrix1);
new (mImpulse + index2) Vector3(impulse1); new (mImpulse + index2) Vector3(impulse1);
mIsConeLimitEnabled[index2] = isConeLimitEnabled1;
mConeLimitImpulse[index2] = coneLimitImpulse1;
mConeLimitHalfAngle[index2] = coneLimitHalfAngle1;
mInverseMassMatrixConeLimit[index2] = inverseMassMatrixConeLimit1;
// Update the entity to component index mapping // Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(jointEntity1, index2)); mMapEntityToComponentIndex.add(Pair<Entity, uint32>(jointEntity1, index2));

View File

@ -61,6 +61,29 @@ BallAndSocketJoint::BallAndSocketJoint(Entity entity, PhysicsWorld& world, const
mWorld.mBallAndSocketJointsComponents.setLocalAnchorPointBody2(entity, anchorPointBody2LocalSpace); mWorld.mBallAndSocketJointsComponents.setLocalAnchorPointBody2(entity, anchorPointBody2LocalSpace);
} }
// Enable/disable the cone limit of the joint
void BallAndSocketJoint::enableConeLimit(bool isLimitEnabled) {
mWorld.mBallAndSocketJointsComponents.setIsConeLimitEnabled(mEntity, isLimitEnabled);
}
// Return true if the cone limit or the joint is enabled
bool BallAndSocketJoint::isConeLimitEnabled() const {
return mWorld.mBallAndSocketJointsComponents.getIsConeLimitEnabled(mEntity);
}
// Set the cone limit half angle
/**
* @param coneHalfAngle The angle of the cone limit (in radian) from [0; PI]
*/
void BallAndSocketJoint::setConeLimitHalfAngle(decimal coneHalfAngle) {
mWorld.mBallAndSocketJointsComponents.setConeLimitHalfAngle(mEntity, coneHalfAngle);
}
// Return the cone angle limit (in radians) from [0; PI]
decimal BallAndSocketJoint::getConeLimitHalfAngle() const {
return mWorld.mBallAndSocketJointsComponents.getConeLimitHalfAngle(mEntity);
}
// Return the force (in Newtons) on body 2 required to satisfy the joint constraint in world-space // Return the force (in Newtons) on body 2 required to satisfy the joint constraint in world-space
Vector3 BallAndSocketJoint::getReactionForce(decimal timeStep) const { Vector3 BallAndSocketJoint::getReactionForce(decimal timeStep) const {
assert(timeStep > MACHINE_EPSILON); assert(timeStep > MACHINE_EPSILON);