base
This commit is contained in:
@@ -27,10 +27,11 @@ static constexpr float PHYSICS_LINEAR_DAMPING = 0.995f;
|
||||
static constexpr float PHYSICS_ANGULAR_DAMPING = 0.990f;
|
||||
static constexpr float PHYSICS_BAUMGARTE_FACTOR = 0.1f;
|
||||
static constexpr float PHYSICS_BAUMGARTE_SLOP = 0.02f;
|
||||
static constexpr float PHYSICS_SLEEP_LINEAR_SQ = 0.01f * 0.01f;
|
||||
static constexpr float PHYSICS_SLEEP_ANGULAR_SQ = 0.01f * 0.01f;
|
||||
static constexpr float PHYSICS_SLEEP_LINEAR_SQ = 0.05f * 0.05f; // m/s
|
||||
static constexpr float PHYSICS_SLEEP_ANGULAR_SQ = 0.08f * 0.08f; // rad/s
|
||||
static constexpr float PHYSICS_SLEEP_TIME_THRESHOLD = 0.5f;
|
||||
static constexpr float PHYSICS_RESTITUTION_THRESHOLD = 1.0f;
|
||||
static constexpr int PHYSICS_CONTACT_ITERATIONS = 8; // per step with no joints around
|
||||
static constexpr int PHYSICS_JOINT_ITERATIONS = 12;
|
||||
static constexpr float PHYSICS_JOINT_BIAS = 0.2f;
|
||||
static constexpr float PHYSICS_JOINT_MAX_BIAS_SPEED = 5.0f;
|
||||
@@ -38,6 +39,7 @@ static constexpr float PHYSICS_JOINT_DAMPING = 5.0f;
|
||||
static constexpr int PHYSICS_MAX_MESH_CONTACTS = 4;
|
||||
static constexpr float PHYSICS_MAX_MESH_DEPTH = 0.1f;
|
||||
static constexpr float PHYSICS_MESH_PAIR_FRICTION = 0.25f; // two meshes catch on each other, so they slide easier
|
||||
static constexpr float PHYSICS_MIN_IMPACT_IMPULSE = 1.0f; // newton seconds, softer contacts like resting aren't recorded
|
||||
|
||||
// ============================================================================
|
||||
// Physics body
|
||||
@@ -75,6 +77,7 @@ public:
|
||||
bool isSleeping = false;
|
||||
bool lockRotation = false;
|
||||
bool frozen = false; // parked until something touches its group
|
||||
bool isHitbox = false; // only collides with loose objects, never with other characters
|
||||
|
||||
// Set this to collide triangle by triangle, otherwise the body is its t's box
|
||||
const CollisionMesh* collisionMesh = nullptr;
|
||||
@@ -93,6 +96,18 @@ public:
|
||||
glm::mat3 invInertia = glm::mat3(0.0f); // world space, refreshed at the start of each step
|
||||
|
||||
float sleepTimer = 0.0f;
|
||||
|
||||
// For drawing it smoothly between physics ticks, see Physics::ApplyInterpolation
|
||||
glm::vec3 previousPosition = glm::vec3(0.0f);
|
||||
glm::quat previousOrientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
glm::vec3 simulatedPosition = glm::vec3(0.0f);
|
||||
glm::quat simulatedOrientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
bool hasPrevious = false; // false until its first tick, so new bodies don't slide in from nowhere
|
||||
bool interpolated = false; // t currently holds the blended pose, not the real one
|
||||
|
||||
// World bounds, kept until t changes. Most bodies sit still most of the time.
|
||||
BoundingBox bounds;
|
||||
unsigned int boundsVersion = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@@ -107,6 +122,21 @@ struct Collision {
|
||||
p* ObjA = nullptr;
|
||||
p* ObjB = nullptr;
|
||||
|
||||
// Filled in by PrepareContact, these can't change during a step's iterations
|
||||
glm::vec3 rA = glm::vec3(0.0f);
|
||||
glm::vec3 rB = glm::vec3(0.0f);
|
||||
glm::vec3 tangent1 = glm::vec3(0.0f);
|
||||
glm::vec3 tangent2 = glm::vec3(0.0f);
|
||||
float inverseDenomN = 0.0f;
|
||||
float inverseDenomT1 = 0.0f;
|
||||
float inverseDenomT2 = 0.0f;
|
||||
float targetSpeed = 0.0f; // how fast it should be separating afterwards, the bounce
|
||||
float mu = 0.0f;
|
||||
|
||||
// Running totals over the iterations
|
||||
float normalImpulse = 0.0f;
|
||||
glm::vec2 tangentImpulse = glm::vec2(0.0f);
|
||||
|
||||
Collision(p* a, p* b) : ObjA(a), ObjB(b) {}
|
||||
};
|
||||
|
||||
@@ -154,6 +184,14 @@ struct BallJoint {
|
||||
int rowCount = 0;
|
||||
};
|
||||
|
||||
// One contact pushing two bodies apart during a step. impulse is in newton seconds.
|
||||
struct Impact {
|
||||
p* a = nullptr;
|
||||
p* b = nullptr;
|
||||
glm::vec3 point = glm::vec3(0.0f);
|
||||
float impulse = 0.0f;
|
||||
};
|
||||
|
||||
struct BroadPhaseEntry {
|
||||
p* body = nullptr;
|
||||
BoundingBox bounds;
|
||||
@@ -168,18 +206,25 @@ private:
|
||||
std::vector<BallJoint*> joints;
|
||||
glm::vec3 gravity = glm::vec3(0.0f, -9.81f, 0.0f);
|
||||
|
||||
// Kept between steps so they don't get reallocated
|
||||
// Kept between steps so they don't get reallocated. The broad phase also keeps its order,
|
||||
// and is only rebuilt when bodies come or go.
|
||||
std::vector<BroadPhaseEntry> broadPhase;
|
||||
unsigned int objectsVersion = 1;
|
||||
unsigned int broadPhaseVersion = 0;
|
||||
std::vector<Collision> collisions;
|
||||
std::vector<Collision> meshContacts;
|
||||
std::vector<int> meshCandidates;
|
||||
|
||||
static glm::mat3 ComputeInvInertiaTensor(const p* body);
|
||||
static bool UpdateSleep(p* body, float dt);
|
||||
void Resolve(Collision* c, bool firstPass = true);
|
||||
void PrepareContact(Collision& c);
|
||||
void SolveContact(Collision& c);
|
||||
void CorrectContactPosition(Collision& c);
|
||||
void FindCollisions();
|
||||
void CollideTriangles(p* a, p* b);
|
||||
void CollideBoxes(p* a, p* b, const TInTInfo& info);
|
||||
void WakeGroup(int group);
|
||||
void WakeAround(p* removed);
|
||||
void PrepareJoint(BallJoint& joint, float dt);
|
||||
void SolveJoint(BallJoint& joint);
|
||||
void DampJoint(BallJoint& joint, float dt);
|
||||
@@ -191,7 +236,7 @@ public:
|
||||
void SetGravity(const glm::vec3& g) noexcept { gravity = g; }
|
||||
|
||||
int GetObjectAmount() const noexcept { return (int)objects.size(); }
|
||||
void AddObject(p* obj) { objects.push_back(obj); }
|
||||
void AddObject(p* obj) { objects.push_back(obj); objectsVersion++; }
|
||||
void AddJoint(BallJoint* joint) { joints.push_back(joint); }
|
||||
const std::vector<p*>& GetObjects() const { return objects; }
|
||||
|
||||
@@ -203,13 +248,18 @@ public:
|
||||
|
||||
void RemoveP(p* obj) {
|
||||
objects.erase(std::find(objects.begin(), objects.end(), obj));
|
||||
objectsVersion++;
|
||||
WakeAround(obj);
|
||||
}
|
||||
|
||||
void RemoveObject(t_package* pointer) {
|
||||
for (int i = 0; i < (int)objects.size(); i++) {
|
||||
if (objects[i]->pointer == pointer) {
|
||||
delete objects[i];
|
||||
p* removed = objects[i];
|
||||
objects.erase(objects.begin() + i);
|
||||
objectsVersion++;
|
||||
WakeAround(removed);
|
||||
delete removed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -217,7 +267,24 @@ public:
|
||||
|
||||
void Step(float dt);
|
||||
|
||||
// One fixed physics tick, split into substeps so fast things don't pass through each other.
|
||||
// Remembers where everything was beforehand, for ApplyInterpolation.
|
||||
void Tick(float dt, int substeps);
|
||||
|
||||
// Moves every moving body's t partway from where it was before the last tick (0) to where it is now (1),
|
||||
// so things drawn between ticks don't step along at the tick rate. Nothing may move bodies until
|
||||
// RemoveInterpolation puts the real positions back.
|
||||
void ApplyInterpolation(float alpha);
|
||||
void RemoveInterpolation();
|
||||
|
||||
void ResolveCollisions(float dt);
|
||||
|
||||
// Every contact since the last ClearImpacts, for working out what hit what and how hard
|
||||
const std::vector<Impact>& GetImpacts() const { return impacts; }
|
||||
void ClearImpacts() { impacts.clear(); }
|
||||
|
||||
private:
|
||||
std::vector<Impact> impacts;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user