Implemented a custom physics engine #316
|
@ -45,7 +45,7 @@
|
||||||
NumberOfChildren: 0
|
NumberOfChildren: 0
|
||||||
Components:
|
Components:
|
||||||
Camera Component:
|
Camera Component:
|
||||||
Position: {x: 0, y: 0, z: 7}
|
Position: {x: 0, y: 2, z: 7}
|
||||||
Pitch: 0
|
Pitch: 0
|
||||||
Yaw: 0
|
Yaw: 0
|
||||||
Roll: 0
|
Roll: 0
|
||||||
|
@ -62,14 +62,14 @@
|
||||||
NumberOfChildren: 0
|
NumberOfChildren: 0
|
||||||
Components:
|
Components:
|
||||||
Transform Component:
|
Transform Component:
|
||||||
Translate: {x: -1.45715916, y: 7.37748241, z: 0.227711335}
|
Translate: {x: -1.5, y: 7.5, z: 0}
|
||||||
Rotate: {x: -0, y: 0, z: -0}
|
Rotate: {x: -0, y: 0, z: 0.785398185}
|
||||||
Scale: {x: 1, y: 1, z: 1}
|
Scale: {x: 1, y: 1, z: 1}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
RigidBody Component:
|
RigidBody Component:
|
||||||
Type: Dynamic
|
Type: Dynamic
|
||||||
Auto Mass: false
|
Auto Mass: false
|
||||||
Mass: 10
|
Mass: 0.52359879
|
||||||
Drag: 0.00999999978
|
Drag: 0.00999999978
|
||||||
Angular Drag: 0
|
Angular Drag: 0
|
||||||
Use Gravity: true
|
Use Gravity: true
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
Freeze Rotation Z: false
|
Freeze Rotation Z: false
|
||||||
IsActive: true
|
IsActive: true
|
||||||
Collider Component:
|
Collider Component:
|
||||||
DrawColliders: true
|
DrawColliders: false
|
||||||
Colliders:
|
Colliders:
|
||||||
- Is Trigger: false
|
- Is Trigger: false
|
||||||
Collision Tag: 1
|
Collision Tag: 1
|
||||||
|
@ -96,18 +96,14 @@
|
||||||
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}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
Scripts:
|
Scripts: ~
|
||||||
- Type: PhysicsTestObj
|
|
||||||
Enabled: true
|
|
||||||
forceAmount: 50
|
|
||||||
torqueAmount: 500
|
|
||||||
- EID: 2
|
- EID: 2
|
||||||
Name: Default
|
Name: Default
|
||||||
IsActive: true
|
IsActive: true
|
||||||
NumberOfChildren: 0
|
NumberOfChildren: 0
|
||||||
Components:
|
Components:
|
||||||
Transform Component:
|
Transform Component:
|
||||||
Translate: {x: 0, y: 4.09544182, z: 0}
|
Translate: {x: 0, y: 4, z: 0}
|
||||||
Rotate: {x: -0, y: 0, z: -0.436332315}
|
Rotate: {x: -0, y: 0, z: -0.436332315}
|
||||||
Scale: {x: 4.61071014, y: 0.999995887, z: 1}
|
Scale: {x: 4.61071014, y: 0.999995887, z: 1}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
|
@ -272,17 +268,17 @@
|
||||||
Components:
|
Components:
|
||||||
Transform Component:
|
Transform Component:
|
||||||
Translate: {x: 1, y: 2, z: 3}
|
Translate: {x: 1, y: 2, z: 3}
|
||||||
Rotate: {x: -0, y: 0.785398066, z: 0.785398185}
|
Rotate: {x: 0, y: 0.785398185, z: 0.785397708}
|
||||||
Scale: {x: 0.999999821, y: 0.999999821, z: 0.999999881}
|
Scale: {x: 0.999990404, y: 0.999994516, z: 0.999985456}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
RigidBody Component:
|
RigidBody Component:
|
||||||
Type: Dynamic
|
Type: Dynamic
|
||||||
Auto Mass: false
|
Auto Mass: false
|
||||||
Mass: 1
|
Mass: 1
|
||||||
Drag: 0.00999999978
|
Drag: 0.00999999978
|
||||||
Angular Drag: 0.00999999978
|
Angular Drag: 0
|
||||||
Use Gravity: true
|
Use Gravity: true
|
||||||
Gravity Scale: 0.5
|
Gravity Scale: 1
|
||||||
Interpolate: true
|
Interpolate: true
|
||||||
Sleeping Enabled: true
|
Sleeping Enabled: true
|
||||||
Freeze Position X: false
|
Freeze Position X: false
|
||||||
|
@ -305,7 +301,11 @@
|
||||||
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}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
Scripts: ~
|
Scripts:
|
||||||
|
- Type: PhysicsTestObj
|
||||||
|
Enabled: true
|
||||||
|
forceAmount: 50
|
||||||
|
torqueAmount: 5
|
||||||
- EID: 8
|
- EID: 8
|
||||||
Name: Default
|
Name: Default
|
||||||
IsActive: true
|
IsActive: true
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace SHADE
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/** Standard Epsilon value for comparing Single-Precision Floating-Point values. */
|
/** Standard Epsilon value for comparing Single-Precision Floating-Point values. */
|
||||||
static constexpr float EPSILON = 0.001f;
|
static constexpr float EPSILON = 0.0001f;
|
||||||
|
|
||||||
/** Single-Precision Floating-Point value of infinity */
|
/** Single-Precision Floating-Point value of infinity */
|
||||||
static constexpr float INF = std::numeric_limits<float>::infinity();
|
static constexpr float INF = std::numeric_limits<float>::infinity();
|
||||||
|
|
|
@ -27,20 +27,16 @@ namespace SHADE
|
||||||
union SHContactFeatures
|
union SHContactFeatures
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*---------------------------------------------------------------------------------*/
|
|
||||||
/* Type Definit */
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Data Members */
|
/* Data Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t inI;
|
uint8_t inI; // Incoming Incident Edge
|
||||||
uint8_t outI;
|
uint8_t outI; // Outgoing Incident Edge
|
||||||
uint8_t inR;
|
uint8_t inR; // Incoming Reference Edge
|
||||||
uint8_t outR;
|
uint8_t outR; // Outgoing Reference Edge
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t key = std::numeric_limits<uint32_t>::max();
|
uint32_t key = std::numeric_limits<uint32_t>::max();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Project Headers
|
// Project Headers
|
||||||
|
#include "Math/Geometry/SHPlane.h"
|
||||||
#include "Physics/Collision/Contacts/SHManifold.h"
|
#include "Physics/Collision/Contacts/SHManifold.h"
|
||||||
#include "Physics/Collision/Contacts/SHCollisionKey.h"
|
#include "Physics/Collision/Contacts/SHCollisionKey.h"
|
||||||
#include "Physics/Collision/Shapes/SHHalfEdgeStructure.h"
|
#include "Physics/Collision/Shapes/SHHalfEdgeStructure.h"
|
||||||
|
@ -86,6 +87,12 @@ namespace SHADE
|
||||||
float bestDistance = std::numeric_limits<float>::lowest();
|
float bestDistance = std::numeric_limits<float>::lowest();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ClipVertex
|
||||||
|
{
|
||||||
|
SHVec3 position;
|
||||||
|
SHContactFeatures featurePair;
|
||||||
|
};
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Member Functions */
|
/* Member Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -102,6 +109,12 @@ namespace SHADE
|
||||||
|
|
||||||
// Convex VS Convex
|
// Convex VS Convex
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ! References
|
||||||
|
* https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf
|
||||||
|
* https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
||||||
static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
||||||
|
|
||||||
|
@ -110,21 +123,8 @@ namespace SHADE
|
||||||
static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
||||||
static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
||||||
static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept;
|
static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept;
|
||||||
|
static std::vector<ClipVertex> clipPolygonWithPlane (const std::vector<ClipVertex>& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept;
|
||||||
/*
|
static std::vector<ClipVertex> reduceContacts (const std::vector<ClipVertex>& in) noexcept;
|
||||||
* TODO:
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* static uint32_t clip [sutherland-hodgemann clipping]
|
|
||||||
*
|
|
||||||
* ! References
|
|
||||||
* https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf
|
|
||||||
* https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace SHADE
|
} // namespace SHADE
|
|
@ -54,6 +54,8 @@ namespace SHADE
|
||||||
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);
|
||||||
|
|
||||||
|
// TODO: Check against cached separating axis.
|
||||||
|
|
||||||
const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B);
|
const FaceQuery FACE_QUERY_A = queryFaceDirections(POLY_A, POLY_B);
|
||||||
if (FACE_QUERY_A.bestDistance > 0.0f)
|
if (FACE_QUERY_A.bestDistance > 0.0f)
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,6 +80,7 @@ namespace SHADE
|
||||||
minFaceQuery = FACE_QUERY_A;
|
minFaceQuery = FACE_QUERY_A;
|
||||||
referencePoly = &POLY_A;
|
referencePoly = &POLY_A;
|
||||||
incidentPoly = &POLY_B;
|
incidentPoly = &POLY_B;
|
||||||
|
flipNormal = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -114,7 +117,7 @@ namespace SHADE
|
||||||
SHContact contact;
|
SHContact contact;
|
||||||
contact.featurePair.key = EDGE_QUERY.axis;
|
contact.featurePair.key = EDGE_QUERY.axis;
|
||||||
contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB);
|
contact.position = findClosestPointBetweenEdges(POLY_A, POLY_B, EDGE_QUERY.halfEdgeA, EDGE_QUERY.halfEdgeB);
|
||||||
contact.penetration = EDGE_QUERY.bestDistance;
|
contact.penetration = -EDGE_QUERY.bestDistance;
|
||||||
|
|
||||||
manifold.contacts[numContacts++] = contact;
|
manifold.contacts[numContacts++] = contact;
|
||||||
manifold.numContacts = numContacts;
|
manifold.numContacts = numContacts;
|
||||||
|
@ -125,23 +128,67 @@ namespace SHADE
|
||||||
const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace);
|
const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace);
|
||||||
const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL);
|
const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL);
|
||||||
|
|
||||||
|
const SHHalfEdgeStructure::Face& INCIDENT_FACE = incidentPoly->GetFace(INCIDENT_FACE_IDX);
|
||||||
|
const SHHalfEdgeStructure::Face& REFERENCE_FACE = referencePoly->GetFace(minFaceQuery.closestFace);
|
||||||
|
|
||||||
/*
|
const int32_t NUM_INCIDENT_VERTICES = static_cast<int32_t>(INCIDENT_FACE.vertexIndices.size());
|
||||||
* TODO:
|
const int32_t NUM_REFERENCE_VERTICES = static_cast<int32_t>(REFERENCE_FACE.vertexIndices.size());
|
||||||
*
|
|
||||||
* !!
|
|
||||||
* 4. From above, save the axis of minimum penetration (reference face)
|
|
||||||
* 5. Find the most anti-parallel face on other shape (incident face)
|
|
||||||
* 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping).
|
|
||||||
* Keep all vertices below reference face.
|
|
||||||
* 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold.
|
|
||||||
*
|
|
||||||
* Remember to save IDs in queries.
|
|
||||||
* During generation of incident face, store IDs of face.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// Build incoming vertices to clip
|
||||||
|
std::vector<ClipVertex> clipIn;
|
||||||
|
clipIn.resize(NUM_INCIDENT_VERTICES * 2, ClipVertex{});
|
||||||
|
|
||||||
|
int32_t numClipIn = 0;
|
||||||
|
for (int32_t i = 0; i < NUM_INCIDENT_VERTICES; ++i)
|
||||||
|
{
|
||||||
|
const int32_t prevI = i - 1 < 0 ? NUM_INCIDENT_VERTICES - 1 : i - 1;
|
||||||
|
|
||||||
|
const int32_t V_INDEX = INCIDENT_FACE.vertexIndices[i].index;
|
||||||
|
|
||||||
|
// The incoming id is the previous edge
|
||||||
|
// The outgoing id is the current edge (where this vertex is the tail of)
|
||||||
|
|
||||||
|
ClipVertex v;
|
||||||
|
v.position = incidentPoly->GetVertex(V_INDEX);
|
||||||
|
v.featurePair.inI = INCIDENT_FACE.vertexIndices[prevI].edgeIndex;
|
||||||
|
v.featurePair.outI = INCIDENT_FACE.vertexIndices[i].edgeIndex;
|
||||||
|
v.featurePair.inR = 0;
|
||||||
|
v.featurePair.outR = 0;
|
||||||
|
|
||||||
|
clipIn[numClipIn++] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip the vertices against the reference face side planes.
|
||||||
|
// Number of side planes == number of edges == number of vertices
|
||||||
|
for (int32_t i = 0; i < NUM_REFERENCE_VERTICES; ++i)
|
||||||
|
{
|
||||||
|
// Side plane can be built with the vertex on the edge and the plane's normal
|
||||||
|
// Plane normal = faceNormal X tangent (v2 - v1)
|
||||||
|
|
||||||
|
const int32_t V1_INDEX = REFERENCE_FACE.vertexIndices[i].index;
|
||||||
|
const int32_t V2_INDEX = REFERENCE_FACE.vertexIndices[(i + 1) % NUM_REFERENCE_VERTICES].index;
|
||||||
|
|
||||||
|
const SHVec3 V1 = referencePoly->GetVertex(V1_INDEX);
|
||||||
|
const SHVec3 V2 = referencePoly->GetVertex(V2_INDEX);
|
||||||
|
|
||||||
|
const SHVec3 TANGENT = SHVec3::Normalise(V2 - V1);
|
||||||
|
const SHPlane CLIP_PLANE { V1, SHVec3::Cross(REFERENCE_NORMAL, TANGENT) };
|
||||||
|
|
||||||
|
std::vector<ClipVertex> clipOut = clipPolygonWithPlane(clipIn, numClipIn, CLIP_PLANE, REFERENCE_FACE.vertexIndices[i].edgeIndex);
|
||||||
|
if (clipOut.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Replace the clip container's contents with the clipped points for the next clipping pass
|
||||||
|
const int32_t NUM_CLIPPED = static_cast<int32_t>(clipOut.size());
|
||||||
|
for (int32_t clippedIndex = 0; clippedIndex < NUM_CLIPPED; ++clippedIndex)
|
||||||
|
{
|
||||||
|
clipIn[clippedIndex].position = clipOut[clippedIndex].position;
|
||||||
|
clipIn[clippedIndex].featurePair.key = clipOut[clippedIndex].featurePair.key;
|
||||||
|
}
|
||||||
|
numClipIn = NUM_CLIPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the final set of clipped points, only keep the points that are below the reference plane.
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -353,5 +400,77 @@ namespace SHADE
|
||||||
return bestFace;
|
return bestFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SHCollision::ClipVertex> SHCollision::clipPolygonWithPlane(const std::vector<ClipVertex>& in, int32_t numIn, const SHPlane& plane, int32_t planeIdx) noexcept
|
||||||
|
{
|
||||||
|
std::vector<ClipVertex> out;
|
||||||
|
|
||||||
|
int32_t v1Index = numIn - 1;
|
||||||
|
int32_t v2Index = 0;
|
||||||
|
|
||||||
|
float v1Distance = plane.SignedDistance(in[v1Index].position);
|
||||||
|
float v2Distance = 0.0f;
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < numIn; ++i)
|
||||||
|
{
|
||||||
|
v2Index = i;
|
||||||
|
|
||||||
|
const SHVec3 v1Pos = in[v1Index].position;
|
||||||
|
const SHVec3 v2Pos = in[v2Index].position;
|
||||||
|
|
||||||
|
v2Distance = plane.SignedDistance(v2Pos);
|
||||||
|
|
||||||
|
// v1 in front, v2 behind
|
||||||
|
// keep the intersection point
|
||||||
|
if (v1Distance >= 0.0f && v2Distance < 0.0f)
|
||||||
|
{
|
||||||
|
ClipVertex intersection;
|
||||||
|
|
||||||
|
// In case the edge is parallel, the intersection is just the start point
|
||||||
|
const bool IS_PARALLEL = SHMath::CompareFloat(SHVec3::Dot(v2Pos - v1Pos, plane.GetNormal()), 0.0f);
|
||||||
|
const float ALPHA = IS_PARALLEL ? 0.0f : v1Distance / SHVec3::Distance(v1Pos, v2Pos);
|
||||||
|
|
||||||
|
intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA);
|
||||||
|
intersection.featurePair.inI = in[v1Index].featurePair.outI;
|
||||||
|
intersection.featurePair.outI = 0;
|
||||||
|
intersection.featurePair.inR = 0;
|
||||||
|
intersection.featurePair.outR = planeIdx;
|
||||||
|
|
||||||
|
out.emplace_back(intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// v1 behind, v2 in front
|
||||||
|
// keep intersection point & v2
|
||||||
|
if(v1Distance < 0.0f && v2Distance >= 0.0f)
|
||||||
|
{
|
||||||
|
ClipVertex intersection;
|
||||||
|
|
||||||
|
// In case the edge is parallel, the intersection is just the start point
|
||||||
|
const bool IS_PARALLEL = SHMath::CompareFloat(SHVec3::Dot(v2Pos - v1Pos, plane.GetNormal()), 0.0f);
|
||||||
|
const float ALPHA = IS_PARALLEL ? 0.0f : -v1Distance / SHVec3::Distance(v1Pos, v2Pos);
|
||||||
|
|
||||||
|
intersection.position = SHVec3::ClampedLerp(v1Pos, v2Pos, ALPHA);
|
||||||
|
intersection.featurePair.inI = 0;
|
||||||
|
intersection.featurePair.outI = in[v2Index].featurePair.inI;
|
||||||
|
intersection.featurePair.inR = planeIdx;
|
||||||
|
intersection.featurePair.outR = 0;
|
||||||
|
|
||||||
|
out.emplace_back(intersection);
|
||||||
|
out.emplace_back(in[v2Index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// both in front, keep v2
|
||||||
|
if (v1Distance >= 0.0f && v2Distance >= 0.0f)
|
||||||
|
{
|
||||||
|
out.emplace_back(in[v2Index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// v2 is the next v1
|
||||||
|
v1Index = v2Index;
|
||||||
|
v1Distance = v2Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace SHADE
|
} // namespace SHADE
|
|
@ -187,7 +187,7 @@ namespace SHADE
|
||||||
* restituion bias = restitution * (relative velocity /dot normal)
|
* restituion bias = restitution * (relative velocity /dot 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::max(0.0f, contact.penetration - SHPHYSICS_LINEAR_SLOP);
|
||||||
|
|
||||||
// Warm starting
|
// Warm starting
|
||||||
// Compute impulses
|
// Compute impulses
|
||||||
|
@ -244,6 +244,31 @@ namespace SHADE
|
||||||
SHVec3 velocityB = vB + SHVec3::Cross(wB, contact.rB);
|
SHVec3 velocityB = vB + SHVec3::Cross(wB, contact.rB);
|
||||||
SHVec3 relativeVelocity = velocityB - velocityA;
|
SHVec3 relativeVelocity = velocityB - velocityA;
|
||||||
|
|
||||||
|
// Get scalar of relative velocity along the normal
|
||||||
|
const float VN = SHVec3::Dot(relativeVelocity, constraint.normal);
|
||||||
|
|
||||||
|
// Compute true normal impulse
|
||||||
|
const float OLD_NORMAL_IMPULSE = contact.normalImpulse;
|
||||||
|
|
||||||
|
float newNormalImpulse = -(VN + contact.bias) * contact.normalMass;
|
||||||
|
contact.normalImpulse = std::max(OLD_NORMAL_IMPULSE + newNormalImpulse, 0.0f);
|
||||||
|
newNormalImpulse = contact.normalImpulse - OLD_NORMAL_IMPULSE;
|
||||||
|
|
||||||
|
const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal;
|
||||||
|
|
||||||
|
// Apply impulses
|
||||||
|
vA -= NORMAL_IMPULSE * constraint.invMassA * LINEAR_LOCK_A;
|
||||||
|
wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE) * ANGULAR_LOCK_A;
|
||||||
|
|
||||||
|
vB += NORMAL_IMPULSE * constraint.invMassB * LINEAR_LOCK_B;
|
||||||
|
wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE) * ANGULAR_LOCK_B;
|
||||||
|
|
||||||
|
// Solve normal impulse
|
||||||
|
// Re-compute relative velocity
|
||||||
|
velocityA = vA + SHVec3::Cross(wA, contact.rA);
|
||||||
|
velocityB = vB + SHVec3::Cross(wB, contact.rB);
|
||||||
|
relativeVelocity = velocityB - velocityA;
|
||||||
|
|
||||||
// Solve tangent impulse
|
// Solve tangent impulse
|
||||||
for (int j = 0; j < SHContact::NUM_TANGENTS; ++j)
|
for (int j = 0; j < SHContact::NUM_TANGENTS; ++j)
|
||||||
{
|
{
|
||||||
|
@ -269,31 +294,6 @@ namespace SHADE
|
||||||
vB += TANGENT_IMPULSE * constraint.invMassB * LINEAR_LOCK_B;
|
vB += TANGENT_IMPULSE * constraint.invMassB * LINEAR_LOCK_B;
|
||||||
wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE) * ANGULAR_LOCK_B;
|
wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, TANGENT_IMPULSE) * ANGULAR_LOCK_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solve normal impulse
|
|
||||||
// Re-compute relative velocity
|
|
||||||
velocityA = vA + SHVec3::Cross(wA, contact.rA);
|
|
||||||
velocityB = vB + SHVec3::Cross(wB, contact.rB);
|
|
||||||
relativeVelocity = velocityB - velocityA;
|
|
||||||
|
|
||||||
// Get scalar of relative velocity along the normal
|
|
||||||
const float VN = SHVec3::Dot(relativeVelocity, constraint.normal);
|
|
||||||
|
|
||||||
// Compute true normal impulse
|
|
||||||
const float OLD_NORMAL_IMPULSE = contact.normalImpulse;
|
|
||||||
|
|
||||||
float newNormalImpulse = -(VN + contact.bias) * contact.normalMass;
|
|
||||||
contact.normalImpulse = std::max(OLD_NORMAL_IMPULSE + newNormalImpulse, 0.0f);
|
|
||||||
newNormalImpulse = contact.normalImpulse - OLD_NORMAL_IMPULSE;
|
|
||||||
|
|
||||||
const SHVec3 NORMAL_IMPULSE = newNormalImpulse * constraint.normal;
|
|
||||||
|
|
||||||
// Apply impulses
|
|
||||||
vA -= NORMAL_IMPULSE * constraint.invMassA * LINEAR_LOCK_A;
|
|
||||||
wA -= constraint.invInertiaA * SHVec3::Cross(contact.rA, NORMAL_IMPULSE) * ANGULAR_LOCK_A;
|
|
||||||
|
|
||||||
vB += NORMAL_IMPULSE * constraint.invMassB * LINEAR_LOCK_B;
|
|
||||||
wB += constraint.invInertiaB * SHVec3::Cross(contact.rB, NORMAL_IMPULSE) * ANGULAR_LOCK_B;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
velocityStateA.LinearVelocity = vA;
|
velocityStateA.LinearVelocity = vA;
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace SHADE
|
||||||
* @brief
|
* @brief
|
||||||
* Linear Collision & Constraint tolerance.
|
* Linear Collision & Constraint tolerance.
|
||||||
*/
|
*/
|
||||||
static constexpr float SHPHYSICS_LINEAR_SLOP = 0.05f * SHPHYSICS_LENGTHS_PER_UNIT_METER;
|
static constexpr float SHPHYSICS_LINEAR_SLOP = 0.01f * SHPHYSICS_LENGTHS_PER_UNIT_METER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
|
|
Loading…
Reference in New Issue