Implemented a custom physics engine #316

Merged
direnbharwani merged 95 commits from SHPhysics into main 2023-01-23 15:55:45 +08:00
9 changed files with 49 additions and 47 deletions
Showing only changes of commit 13d5625055 - Show all commits

View File

@ -45,9 +45,9 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Camera Component: Camera Component:
Position: {x: -0.5, y: 10, z: -3} Position: {x: 0, y: 0, z: 7}
Pitch: 0 Pitch: 0
Yaw: 180 Yaw: 0
Roll: 0 Roll: 0
Width: 1920 Width: 1920
Height: 1080 Height: 1080
@ -71,7 +71,7 @@
Auto Mass: false Auto Mass: false
Mass: 10 Mass: 10
Drag: 0.00999999978 Drag: 0.00999999978
Angular Drag: 0.00999999978 Angular Drag: 0
Use Gravity: true Use Gravity: true
Gravity Scale: 1 Gravity Scale: 1
Interpolate: true Interpolate: true
@ -95,15 +95,6 @@
Density: 1 Density: 1
Position Offset: {x: 0, y: 0, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0}
- Is Trigger: true
Collision Tag: 1
Type: Sphere
Radius: 0.5
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0.75, y: 0.5, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true IsActive: true
Scripts: Scripts:
- Type: PhysicsTestObj - Type: PhysicsTestObj
@ -280,7 +271,7 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0.524352431, y: 13.5, z: 0.0463808179} Translate: {x: 1, y: 2, z: 3}
Rotate: {x: -0, y: 0.785398066, z: 0.785398185} Rotate: {x: -0, y: 0.785398066, z: 0.785398185}
Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881} Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881}
IsActive: true IsActive: true
@ -321,7 +312,7 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: -0.5, y: 10, z: 0} Translate: {x: 0, y: 0, z: 3}
Rotate: {x: -0, y: 0, z: -0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true

View File

@ -337,7 +337,7 @@ namespace SHADE
{ {
SHASSERT(index >= 0 && index < capacity, "Trying to free an invalid AABB Tree node!") SHASSERT(index >= 0 && index < capacity, "Trying to free an invalid AABB Tree node!")
nodes[index].next = NULL_NODE; nodes[index].next = freeList;
nodes[index].height = NULL_NODE; nodes[index].height = NULL_NODE;
// Put it back on the free list // Put it back on the free list

View File

@ -31,22 +31,16 @@ namespace SHADE
/* Type Definit */ /* Type Definit */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
enum class Type : uint8_t
{
VERTEX = 0
, FACE = 1
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
struct struct
{ {
uint8_t indexA; uint8_t inI;
uint8_t indexB; uint8_t outI;
uint8_t typeA; uint8_t inR;
uint8_t typeB; uint8_t outR;
}; };
uint32_t key = std::numeric_limits<uint32_t>::max(); uint32_t key = std::numeric_limits<uint32_t>::max();

View File

@ -82,6 +82,7 @@ namespace SHADE
{ {
int32_t halfEdgeA = -1; int32_t halfEdgeA = -1;
int32_t halfEdgeB = -1; int32_t halfEdgeB = -1;
int32_t axis = -1;
float bestDistance = std::numeric_limits<float>::lowest(); float bestDistance = std::numeric_limits<float>::lowest();
}; };

View File

@ -48,7 +48,8 @@ namespace SHADE
bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept bool SHCollision::ConvexVsConvex(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept
{ {
static constexpr float TOLERANCE = 0.1f + SHPHYSICS_LINEAR_SLOP; static constexpr float ABSOLUTE_TOLERANCE = 0.01f;
static constexpr float RELATIVE_TOLERANCE = 0.95f;
const SHConvexPolyhedron& POLY_A = dynamic_cast<const SHConvexPolyhedron&>(A); const SHConvexPolyhedron& POLY_A = dynamic_cast<const SHConvexPolyhedron&>(A);
const SHConvexPolyhedron& POLY_B = dynamic_cast<const SHConvexPolyhedron&>(B); const SHConvexPolyhedron& POLY_B = dynamic_cast<const SHConvexPolyhedron&>(B);
@ -72,7 +73,7 @@ namespace SHADE
const SHConvexPolyhedron* incidentPoly = nullptr; const SHConvexPolyhedron* incidentPoly = nullptr;
FaceQuery minFaceQuery; FaceQuery minFaceQuery;
if (FACE_QUERY_A.bestDistance + TOLERANCE > FACE_QUERY_B.bestDistance) if (FACE_QUERY_A.bestDistance + ABSOLUTE_TOLERANCE > FACE_QUERY_B.bestDistance * RELATIVE_TOLERANCE)
{ {
minFaceQuery = FACE_QUERY_A; minFaceQuery = FACE_QUERY_A;
referencePoly = &POLY_A; referencePoly = &POLY_A;
@ -91,7 +92,7 @@ namespace SHADE
// If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on // If an edge pair contains the closest distance,vwe ignore any face queries and find the closest points on
// each edge and use that as the contact point. // each edge and use that as the contact point.
if (EDGE_QUERY.bestDistance > minFaceQuery.bestDistance + TOLERANCE) if (EDGE_QUERY.bestDistance * RELATIVE_TOLERANCE > minFaceQuery.bestDistance + ABSOLUTE_TOLERANCE)
{ {
const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_A = POLY_A.GetHalfEdge(EDGE_QUERY.halfEdgeA);
const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB); const SHHalfEdgeStructure::HalfEdge& HALF_EDGE_B = POLY_B.GetHalfEdge(EDGE_QUERY.halfEdgeB);
@ -111,13 +112,9 @@ namespace SHADE
// In this scenario, we only have one contact // In this scenario, we only have one contact
SHContact contact; SHContact contact;
contact.featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); contact.featurePair.key = EDGE_QUERY.axis;
contact.featurePair.indexA = HALF_EDGE_A.tailVertexIndex; contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB);
contact.featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX); contact.penetration = EDGE_QUERY.bestDistance;
contact.featurePair.indexB = HALF_EDGE_B.tailVertexIndex;
contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB);
contact.penetration = EDGE_QUERY.bestDistance;
manifold.contacts[numContacts++] = contact; manifold.contacts[numContacts++] = contact;
manifold.numContacts = numContacts; manifold.numContacts = numContacts;
@ -188,6 +185,7 @@ namespace SHADE
const int32_t EDGE_COUNT_A = A.GetHalfEdgeCount(); const int32_t EDGE_COUNT_A = A.GetHalfEdgeCount();
const int32_t EDGE_COUNT_B = B.GetHalfEdgeCount(); const int32_t EDGE_COUNT_B = B.GetHalfEdgeCount();
int32_t axis = -1;
for (int32_t i = 0; i < EDGE_COUNT_A; i += 2) for (int32_t i = 0; i < EDGE_COUNT_A; i += 2)
{ {
for (int32_t j = 0; j < EDGE_COUNT_B; j += 2) for (int32_t j = 0; j < EDGE_COUNT_B; j += 2)
@ -196,12 +194,15 @@ namespace SHADE
if (!IS_MINKOWSKI_FACE) if (!IS_MINKOWSKI_FACE)
continue; continue;
++axis;
const float SEPARATION = distanceBetweenEdges(A, B, i, j); const float SEPARATION = distanceBetweenEdges(A, B, i, j);
if (SEPARATION > edgeQuery.bestDistance) if (SEPARATION > edgeQuery.bestDistance)
{ {
edgeQuery.bestDistance = SEPARATION; edgeQuery.bestDistance = SEPARATION;
edgeQuery.halfEdgeA = i; edgeQuery.halfEdgeA = i;
edgeQuery.halfEdgeB = j; edgeQuery.halfEdgeB = j;
edgeQuery.axis = axis;
} }
} }
} }
@ -321,10 +322,10 @@ namespace SHADE
* R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 ) * R = (c1a2 / a1 - c2) / ( b2 - a2b1/a1 )
*/ */
const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA; const float A2_OVER_A1 = VB_DOT_VA == 0.0f ? 0.0f : VB_DOT_VB / VB_DOT_VA;
const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB; const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB;
const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1; const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1;
const float R = NUMERATOR / DENOMINATOR; const float R = DENOMINATOR == 0.0f ? NUMERATOR : NUMERATOR / DENOMINATOR;
// Just take a point from A since it's A -> B // Just take a point from A since it's A -> B
return TAIL_A + R * VA; return TAIL_A + R * VA;

View File

@ -179,7 +179,13 @@ namespace SHADE
bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept bool SHCollision::ConvexVsSphere(SHManifold& manifold, const SHCollisionShape& A, const SHCollisionShape& B) noexcept
{ {
return SphereVsConvex(manifold, B, A); if (SphereVsConvex(manifold, B, A))
{
manifold.normal = -manifold.normal;
return true;
};
return false;
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -326,7 +332,13 @@ namespace SHADE
// Face to vertex is in the opposite direction of any tangent. // Face to vertex is in the opposite direction of any tangent.
const float PROJECTION = SHVec3::Dot(FACE_TO_CENTER, tangent1); const float PROJECTION = SHVec3::Dot(FACE_TO_CENTER, tangent1);
if (PROJECTION < 0) if (PROJECTION < 0)
{
const float DISTANCE_SQUARED = SHVec3::DistanceSquared(faceVertex, CENTER);
if (DISTANCE_SQUARED > RADIUS * RADIUS)
return 0;
return 3; return 3;
}
// Belongs in region D by default // Belongs in region D by default
return 4; return 4;

View File

@ -238,6 +238,8 @@ namespace SHADE
void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept void SHContactManager::updateManifold(SHManifold& manifold, const SHManifold& oldManifold) noexcept
{ {
static const float SQRT_ONE_THIRD = std::sqrtf(1.0f / 3.0f);
// Early out since exiting a collision does not require an update beyond updating the state // Early out since exiting a collision does not require an update beyond updating the state
if (manifold.state == SHCollisionState::EXIT) if (manifold.state == SHCollisionState::EXIT)
return; return;
@ -250,7 +252,7 @@ namespace SHADE
const SHVec3& OLD_TANGENT_1 = oldManifold.tangents[1]; const SHVec3& OLD_TANGENT_1 = oldManifold.tangents[1];
// Compute tangents // Compute tangents
if (std::fabs(NORMAL.x) >= SHMath::EULER_CONSTANT) if (std::fabs(NORMAL.x) >= SQRT_ONE_THIRD)
tangent0 = SHVec3{ NORMAL.y, -NORMAL.x, 0.0f }; tangent0 = SHVec3{ NORMAL.y, -NORMAL.x, 0.0f };
else else
tangent0 = SHVec3{ 0.0f, NORMAL.z, -NORMAL.y }; tangent0 = SHVec3{ 0.0f, NORMAL.z, -NORMAL.y };

View File

@ -187,14 +187,7 @@ namespace SHADE
* restituion bias = restitution * (relative velocity /dot normal) * restituion bias = restitution * (relative velocity /dot normal)
*/ */
const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA);
const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB);
const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal);
const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP); const float ERROR_BIAS = SHPHYSICS_BAUMGARTE * INV_DT * std::min(0.0f, -contact.penetration + SHPHYSICS_LINEAR_SLOP);
const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f;
contact.bias = ERROR_BIAS + RESTITUTION_BIAS;
// Warm starting // Warm starting
// Compute impulses // Compute impulses
@ -208,6 +201,14 @@ namespace SHADE
vB += impulse * constraint.invMassB * LINEAR_LOCK_B; vB += impulse * constraint.invMassB * LINEAR_LOCK_B;
wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse) * ANGULAR_LOCK_B; wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, impulse) * ANGULAR_LOCK_B;
const SHVec3 RV_A = vA + SHVec3::Cross(wA, contact.rA);
const SHVec3 RV_B = vB + SHVec3::Cross(wB, contact.rB);
const float RV_N = SHVec3::Dot(RV_B - RV_A, constraint.normal);
const float RESTITUTION_BIAS = std::fabs(RV_N) > SHPHYSICS_RESTITUTION_THRESHOLD ? -constraint.restitution * RV_N : 0.0f;
contact.bias = ERROR_BIAS + RESTITUTION_BIAS;
} }
velocityStateA.LinearVelocity = vA; velocityStateA.LinearVelocity = vA;

View File

@ -26,7 +26,7 @@ namespace SHADE
* @brief * @brief
* Linear Collision & Constraint tolerance. * Linear Collision & Constraint tolerance.
*/ */
static constexpr float SHPHYSICS_LINEAR_SLOP = 0.005f * SHPHYSICS_LENGTHS_PER_UNIT_METER; static constexpr float SHPHYSICS_LINEAR_SLOP = 0.05f * SHPHYSICS_LENGTHS_PER_UNIT_METER;
/** /**
* @brief * @brief