Fixed bug where reduced manifold would attempt to grab an invalid contact

This commit is contained in:
Diren D Bharwani 2023-03-02 07:09:14 +08:00
parent 199a9aa025
commit 991912f7b4
4 changed files with 26 additions and 21 deletions

View File

@ -1,4 +1,4 @@
Start Maximized: true Start Maximized: true
Working Scene ID: 92914350 Working Scene ID: 97402985
Window Size: {x: 2000, y: 1518} Window Size: {x: 2000, y: 1518}
Style: 0 Style: 0

View File

@ -207,7 +207,7 @@
Components: Components:
Transform Component: Transform Component:
Translate: {x: -1, y: 7, z: 0} Translate: {x: -1, y: 7, z: 0}
Rotate: {x: 0, y: 0, z: 0.785398185} Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 0.999999642, y: 0.999998569, z: 0.999999642} Scale: {x: 0.999999642, y: 0.999998569, z: 0.999999642}
IsActive: true IsActive: true
RigidBody Component: RigidBody Component:
@ -223,9 +223,9 @@
Freeze Position X: false Freeze Position X: false
Freeze Position Y: false Freeze Position Y: false
Freeze Position Z: false Freeze Position Z: false
Freeze Rotation X: false Freeze Rotation X: true
Freeze Rotation Y: false Freeze Rotation Y: true
Freeze Rotation Z: false Freeze Rotation Z: true
IsActive: true IsActive: true
Collider Component: Collider Component:
DrawColliders: false DrawColliders: false

View File

@ -542,13 +542,12 @@ namespace SHADE
} }
// Reduce contact manifold if more than 4 points // Reduce contact manifold if more than 4 points
if (numContacts > 4) if (numContacts > SHPHYSICS_MAX_MANIFOLD_CONTACTS)
{ {
const auto INDICES_TO_KEEP = reduceContacts(contacts, REF_NORMAL); const auto INDICES_TO_KEEP = reduceContacts(contacts, LOCAL_REF_NORMAL);
std::vector<SHContact> reducedContacts; std::vector<SHContact> reducedContacts;
const int32_t NUM_REDUCED = static_cast<int32_t>(INDICES_TO_KEEP.size()); for (int32_t i = 0; i < SHPHYSICS_MAX_MANIFOLD_CONTACTS; ++i)
for (int32_t i = 0; i < NUM_REDUCED; ++i)
reducedContacts.emplace_back(contacts[INDICES_TO_KEEP[i]]); reducedContacts.emplace_back(contacts[INDICES_TO_KEEP[i]]);
contacts.clear(); contacts.clear();
@ -638,7 +637,7 @@ namespace SHADE
// In case the edge is parallel, the intersection is just the end point // In case the edge is parallel, the intersection is just the end point
const float DOT = SHVec3::Dot(v2Pos - v1Pos, PLANE_NORMAL); const float DOT = SHVec3::Dot(v2Pos - v1Pos, PLANE_NORMAL);
const bool IS_PARALLEL = SHMath::CompareFloat(DOT, 0.0f); const bool IS_PARALLEL = SHMath::CompareFloat(DOT, 0.0f);
const float ALPHA = IS_PARALLEL ? 1.0f : (-plane.GetDistance() - SHVec3::Dot(v1Pos, PLANE_NORMAL)) / DOT; const float ALPHA = IS_PARALLEL ? 0.0f : (-plane.GetDistance() - SHVec3::Dot(v1Pos, PLANE_NORMAL)) / DOT;
intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA); intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA);
intersection.featurePair.inI = 0; intersection.featurePair.inI = 0;
@ -670,12 +669,13 @@ namespace SHADE
// Use a map to temporarily store and track the contacts we want // Use a map to temporarily store and track the contacts we want
std::unordered_map<int, const SHContact*> contactMap; std::unordered_map<int, const SHContact*> contactMap;
const int32_t NUM_CONTACTS = static_cast<int32_t>(in.size()); const int32_t NUM_CONTACTS = static_cast<int32_t>(in.size());
for (int32_t i = 0; i < NUM_CONTACTS; ++i) for (int32_t i = 0; i < NUM_CONTACTS; ++i)
contactMap.emplace(i, &in[i]); contactMap.emplace(i, &in[i]);
// Find the furthest point in a given direction // Find the furthest point in a given direction
int32_t indexToKeep = -1; int32_t indexToKeep = 0;
float bestDistance = std::numeric_limits<float>::lowest(); float bestDistance = std::numeric_limits<float>::lowest();
for (const auto& [index, contact] : contactMap) for (const auto& [index, contact] : contactMap)
@ -691,8 +691,7 @@ namespace SHADE
indicesToKeep.emplace_back(indexToKeep); indicesToKeep.emplace_back(indexToKeep);
contactMap.erase(indexToKeep); contactMap.erase(indexToKeep);
indexToKeep = 0;
indexToKeep = -1;
bestDistance = std::numeric_limits<float>::lowest(); bestDistance = std::numeric_limits<float>::lowest();
// Find point furthest away from the first index // Find point furthest away from the first index
@ -710,7 +709,7 @@ namespace SHADE
indicesToKeep.emplace_back(indexToKeep); indicesToKeep.emplace_back(indexToKeep);
contactMap.erase(indexToKeep); contactMap.erase(indexToKeep);
indexToKeep = -1; indexToKeep = 0;
// We compute the triangle with the largest area. // We compute the triangle with the largest area.
// The area can be positive or negative depending on the winding order. // The area can be positive or negative depending on the winding order.
@ -745,7 +744,7 @@ namespace SHADE
// Compare which triangle creates the largest area // Compare which triangle creates the largest area
bool isAreaPositive = false; bool isAreaPositive = false;
if (maxArea > (-minArea)) if (maxArea > std::fabs(minArea))
{ {
isAreaPositive = true; isAreaPositive = true;
indexToKeep = maxAreaIndex; indexToKeep = maxAreaIndex;
@ -759,7 +758,7 @@ namespace SHADE
indicesToKeep.emplace_back(indexToKeep); indicesToKeep.emplace_back(indexToKeep);
contactMap.erase(indexToKeep); contactMap.erase(indexToKeep);
indexToKeep = -1; indexToKeep = 0;
// For the last point, we want the point which forms the largest area that is winded opposite to the first triangle // For the last point, we want the point which forms the largest area that is winded opposite to the first triangle
// The areas should be inverted: If area was -ve, we want a +ve. Otherwise, vice versa. // The areas should be inverted: If area was -ve, we want a +ve. Otherwise, vice versa.

View File

@ -15,36 +15,42 @@
namespace SHADE namespace SHADE
{ {
/**
* @brief
* The number of contacts required to build a stable manifold.
*/
static constexpr int SHPHYSICS_MAX_MANIFOLD_CONTACTS = 4;
/** /**
* @brief * @brief
* The number of simulations length for every real world unit meter. <br/> * The number of simulations length for every real world unit meter. <br/>
* Modify this to change the global scale of the simulation. * Modify this to change the global scale of the simulation.
*/ */
static constexpr float SHPHYSICS_LENGTHS_PER_UNIT_METER = 1.0f; static constexpr float SHPHYSICS_LENGTHS_PER_UNIT_METER = 1.0f;
/** /**
* @brief * @brief
* Linear Collision & Constraint tolerance. * Linear Collision & Constraint tolerance.
*/ */
static constexpr float SHPHYSICS_LINEAR_SLOP = 0.01f * SHPHYSICS_LENGTHS_PER_UNIT_METER; static constexpr float SHPHYSICS_LINEAR_SLOP = 0.01f * SHPHYSICS_LENGTHS_PER_UNIT_METER;
/** /**
* @brief * @brief
* Velocity threshold for restitution to be applied. * Velocity threshold for restitution to be applied.
*/ */
static constexpr float SHPHYSICS_RESTITUTION_THRESHOLD = 1.0f; static constexpr float SHPHYSICS_RESTITUTION_THRESHOLD = 1.0f;
/** /**
* @brief * @brief
* Scaling factor to control how fast overlaps are resolved.<br/> * Scaling factor to control how fast overlaps are resolved.<br/>
* 1 is ideal for instant correction, but values close to 1 can lead to overshoot. * 1 is ideal for instant correction, but values close to 1 can lead to overshoot.
*/ */
static constexpr float SHPHYSICS_BAUMGARTE = 0.2f; static constexpr float SHPHYSICS_BAUMGARTE = 0.2f;
/** /**
* @brief * @brief
* Distance threshold to consider two contacts as the same. * Distance threshold to consider two contacts as the same.
*/ */
static constexpr float SHPHYSICS_SAME_CONTACT_DISTANCE = 0.01; static constexpr float SHPHYSICS_SAME_CONTACT_DISTANCE = 0.01;
} }