Home Game Development Physics engine and rigidbody sleep optimization

Physics engine and rigidbody sleep optimization

0
Physics engine and rigidbody sleep optimization

[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]