示例#1
0
void PhysicsSimulation::resolveCollisions() {
    PerformanceTimer perfTimer("resolve");
    // walk all collisions, accumulate movement on shapes, and build a list of affected shapes
    QSet<Shape*> shapes;
    int numCollisions = _collisions.size();
    for (int i = 0; i < numCollisions; ++i) {
        CollisionInfo* collision = _collisions.getCollision(i);
        collision->apply();
        // there is always a shapeA
        shapes.insert(collision->getShapeA());
        // but need to check for valid shapeB
        if (collision->_shapeB) {
            shapes.insert(collision->getShapeB());
        }
    }
    // walk all affected shapes and apply accumulated movement
    QSet<Shape*>::const_iterator shapeItr = shapes.constBegin();
    while (shapeItr != shapes.constEnd()) {
        (*shapeItr)->applyAccumulatedDelta();
        ++shapeItr;
    }
}
示例#2
0
ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : 
        _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), 
        _offsetA(0.0f), _offsetB(0.0f), 
        _relativeMassA(0.5f), _relativeMassB(0.5f), 
        _numPointsA(0), _numPoints(0), _normal(0.0f) {

    glm::vec3 pointA = collision._contactPoint;
    glm::vec3 pointB = collision._contactPoint - collision._penetration;

    float pLength = glm::length(collision._penetration);
    if (pLength > EPSILON) {
        _normal = collision._penetration / pLength;
    }
    if (_shapeA->getID() > _shapeB->getID()) {
        // swap so that _shapeA always has lower ID
        _shapeA = collision.getShapeB();
        _shapeB = collision.getShapeA();
        _normal = - _normal;
        pointA = pointB;
        pointB = collision._contactPoint;
    }

    // bring the contact points inside the shapes to help maintain collision updates
    pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal;
    pointB += CONTACT_PENETRATION_ALLOWANCE * _normal;

    _offsetA = pointA - _shapeA->getTranslation();
    _offsetB = pointB - _shapeB->getTranslation();

    _shapeA->getVerletPoints(_points);
    _numPointsA = _points.size();
    _shapeB->getVerletPoints(_points);
    _numPoints = _points.size();

    // compute and cache relative masses
    float massA = EPSILON;
    for (int i = 0; i < _numPointsA; ++i) {
        massA += _points[i]->getMass();
    }
    float massB = EPSILON;
    for (int i = _numPointsA; i < _numPoints; ++i) {
        massB += _points[i]->getMass();
    }
    float invTotalMass = 1.0f / (massA + massB);
    _relativeMassA = massA * invTotalMass;
    _relativeMassB = massB * invTotalMass;

    // _contactPoint will be the weighted average of the two
    _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB;

    // compute offsets for shapeA
    for (int i = 0; i < _numPointsA; ++i) {
        glm::vec3 offset = _points[i]->_position - pointA;
        _offsets.push_back(offset);
        _distances.push_back(glm::length(offset));
    }
    // compute offsets for shapeB
    for (int i = _numPointsA; i < _numPoints; ++i) {
        glm::vec3 offset = _points[i]->_position - pointB;
        _offsets.push_back(offset);
        _distances.push_back(glm::length(offset));
    }
}