Example #1
0
const glm::quat& VerletCapsuleShape::getRotation() const {
    // NOTE: The "rotation" of this shape must be computed on the fly, 
    // which makes this method MUCH more more expensive than you might expect.
    glm::vec3 axis;
    computeNormalizedAxis(axis);
    VerletCapsuleShape* thisCapsule = const_cast<VerletCapsuleShape*>(this);
    thisCapsule->_rotation = computeNewRotation(axis);
    return _rotation;
}
Example #2
0
// virtual 
void VerletCapsuleShape::setHalfHeight(float halfHeight) {
    // push points along axis so they are 2*halfHeight apart
    glm::vec3 center = getTranslation();
    glm::vec3 axis;
    computeNormalizedAxis(axis);
    _startPoint->_position = center - halfHeight * axis;
    _endPoint->_position = center + halfHeight * axis;
    _boundingRadius = _radius + halfHeight;
}
Example #3
0
bool CapsuleShape::findRayIntersection(RayIntersectionInfo& intersection) const {
    // ray is U, capsule is V
    glm::vec3 axisV;
    computeNormalizedAxis(axisV);
    glm::vec3 centerV = getTranslation();

    // first handle parallel case
    float uDotV = glm::dot(axisV, intersection._rayDirection);
    glm::vec3 UV = intersection._rayStart - centerV;
    if (glm::abs(1.0f - glm::abs(uDotV)) < EPSILON) {
        // line and cylinder are parallel
        float distanceV = glm::dot(UV, intersection._rayDirection);
        if (glm::length2(UV - distanceV * intersection._rayDirection) <= _radius * _radius) {
            // ray is inside cylinder's radius and might intersect caps
            return findRayIntersectionWithCaps(centerV, intersection);
        }
        return false;
    }
    
    // Given a line with point 'U' and normalized direction 'u' and 
    // a cylinder with axial point 'V', radius 'r', and normalized direction 'v'
    // the intersection of the two is on the line at distance 't' from 'U'.
    //
    // Determining the values of t reduces to solving a quadratic equation: At^2 + Bt + C = 0 
    //
    // where:
    //
    // UV = U-V
    // w = u-(u.v)v
    // Q = UV-(UV.v)v
    //       
    // A = w^2
    // B = 2(w.Q)
    // C = Q^2 - r^2

    glm::vec3 w = intersection._rayDirection - uDotV * axisV;
    glm::vec3 Q = UV - glm::dot(UV, axisV) * axisV;

    // we save a few multiplies by storing 2*A rather than just A
    float A2 = 2.0f * glm::dot(w, w);
    float B = 2.0f * glm::dot(w, Q);

    // since C is only ever used once (in the determinant) we compute it inline
    float determinant = B * B - 2.0f * A2 * (glm::dot(Q, Q) - _radius * _radius);
    if (determinant < 0.0f) {
        return false;
    }
    float hitLow  = (-B - sqrtf(determinant)) / A2;
    float hitHigh = -(hitLow + 2.0f * B / A2);

    if (hitLow > hitHigh) {
        // re-arrange so hitLow is always the smaller value
        float temp = hitHigh;
        hitHigh = hitLow;
        hitLow = temp;
    }
    if (hitLow < 0.0f) {
        if (hitHigh < 0.0f) {
            // capsule is completely behind rayStart
            return false;
        }
        hitLow = hitHigh;
    }

    glm::vec3 p = intersection._rayStart + hitLow * intersection._rayDirection;
    float d = glm::dot(p - centerV, axisV);
    if (glm::abs(d) <= getHalfHeight()) {
        // we definitely hit the cylinder wall
        intersection._hitDistance = hitLow;
        intersection._hitNormal = glm::normalize(p - centerV - d * axisV);
        intersection._hitShape = const_cast<CapsuleShape*>(this);
        return true;
    }

    // ray still might hit the caps
    return findRayIntersectionWithCaps(centerV, intersection);
}