[ad_1]
I am trying to add sleep optimization to my little physics engine(just for learning). I use SAT for collision detection that returns penetration normal and depth without contact points. Objects are put to sleep after 180 frames if their velocity is less then eps. When objects are stacked and in sleeping state when i add velocity to the bottom object, objects on top remain in sleep mode and just float in the air. Can sleeping be implemented without contact points at all?
This is done in 3d.
This is collision loop:
void Physics::updateReal(float dt){
auto& rbs = EntitySystem::instance()->_rigidbodies;
for (auto rb : rbs) {
if(rb->isAwake())
rb->integrate(dt);
}
for (int i = 0; i < 1; ++i) { //can be called multiple times per frame to improve stability
blackList.clear();
//std::cout << "########" << std::endl;
for (auto rb : rbs) {
if (!rb->isAwake() || rb->_inverseMass == 0.0f) continue; //skip static and sleeping rbs
//colliders c1 of current rigidbody
std::vector<Collider*> RBColliders; rb->thisEntity()->getColliders(RBColliders);
for (auto c1 : RBColliders) {
glm::vec3 o, d; c1->getAABB(o, d); std::vector<BVHTreeContainee*> colliders2;
SpatialPartitioning::instance()->queryAABB(colliders2, o, d, BVH_COLLIDERS);
for (BVHTreeContainee* c2bvh : colliders2) {
auto c2 = (Collider*)c2bvh;
if (!c2->isRigidbody()) continue;
if (c1 == c2) continue;
if (c1->getEntity() == c2->getEntity()) continue;
//std::cout << c1->getEntity()->gameObject()->name << " AND " << c2->getEntity()->gameObject()->name << std::endl;
collide(c1, c2);
}
//blackList.push_back(c1); //c1 is all tested
}
}
}
}
This is integration of rigidbody:
void Rigidbody::integrate(float dt){
if (_inverseMass == 0.0f) return;
auto trans = thisEntity()->transform();
//sleep
if (glm::length(_velocity) < 3.5f) ++_sleepStage;
else _sleepStage = 0;
if (_sleepStage > 180) { _awake = false; return; }
std::cout << "# " << glm::length(_velocity) << " " << _sleepStage << std::endl;
//euler integration of position
_velocity.y -= _gravity * dt; //rhs = ubrzanje * dt, lhs = brzina
trans->addPosition(_velocity * dt); //rhs = brzina * dt, lhs = pozicija
}
This function is called to resolve collision:
inline void Physics::collisionResolution(Collider* c1, Collider* c2, glm::vec3 mtvAxis, float mtvDist, bool flip){
auto A = c1->getRigidbody();
auto B = c2->getRigidbody();
//COLLISION RESOLUTION
if (flip) mtvAxis *= -1.f;
mtvDist /= 2.f;
if(A->_inverseMass > 0.0f && A->isAwake())
c1->getEntity()->transform()->addPosition(mtvAxis * mtvDist);
if(B->_inverseMass > 0.0f && B->isAwake())
c2->getEntity()->transform()->addPosition(-mtvAxis * mtvDist);
//LINEAR IMPULSE
glm::vec3 rv = A->_velocity - B->_velocity;
float velAlongNormal = glm::dot(rv, mtvAxis);
if (velAlongNormal > 0.0f) return;
float e = 0.2f;
float j = -(1.0f + e) * velAlongNormal;
j /= A->_inverseMass + B->_inverseMass;
glm::vec3 impulse = mtvAxis * j;
glm::vec3 impulseA = impulse * A->_inverseMass;
glm::vec3 impulseB = impulse * B->_inverseMass;
A->setAwake(); //sets _awake to true
A->_velocity += impulseA;
B->setAwake();
B->_velocity -= impulseB;
//FRICTION
glm::vec3 t = rv - (mtvAxis * velAlongNormal);
if (glm::length(t) == 0.0f) return;
t = glm::normalize(t);
float jt = -glm::dot(rv, t);
jt /= A->_inverseMass + B->_inverseMass;
if (jt == 0.0f) return;
float friction = glm::sqrt(0.03f);
if (jt > j * friction)
jt = j * friction;
else if (jt < -j * friction)
jt = -j * friction;
glm::vec3 tangentImpuse = t * jt;
A->_velocity += tangentImpuse * A->_inverseMass;
B->_velocity -= tangentImpuse * B->_inverseMass;
//ANGULAR IMPULSE
//THE DARKEST BLACK MAGIC
}
[ad_2]