Esempio n. 1
0
bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction,
        const glm::vec3& start, const glm::vec3& end, float radius, float& distance) {
    if (start == end) {
        return findRaySphereIntersection(origin, direction, start, radius, distance); // handle degenerate case
    }
    glm::vec3 relativeOrigin = origin - start;
    glm::vec3 relativeEnd = end - start;
    float capsuleLength = glm::length(relativeEnd);
    relativeEnd /= capsuleLength;
    float originProjection = glm::dot(relativeEnd, relativeOrigin);
    glm::vec3 constant = relativeOrigin - relativeEnd * originProjection;
    float c = glm::dot(constant, constant) - radius * radius;
    if (c < 0.0f) { // starts inside cylinder
        if (originProjection < 0.0f) { // below start
            return findRaySphereIntersection(origin, direction, start, radius, distance); 
            
        } else if (originProjection > capsuleLength) { // above end
            return findRaySphereIntersection(origin, direction, end, radius, distance); 
        
        } else { // between start and end
            distance = 0.0f;
            return true; 
        }
    }
    glm::vec3 coefficient = direction - relativeEnd * glm::dot(relativeEnd, direction);
    float a = glm::dot(coefficient, coefficient);
    if (a == 0.0f) {
        return false; // parallel to enclosing cylinder
    }
    float b = 2.0f * glm::dot(constant, coefficient);
    float radicand = b * b - 4.0f * a * c;
    if (radicand < 0.0f) {
        return false; // doesn't hit the enclosing cylinder
    }
    float t = (-b - sqrtf(radicand)) / (2.0f * a);
    if (t < 0.0f) {
        return false; // doesn't hit the enclosing cylinder
    }
    glm::vec3 intersection = relativeOrigin + direction * t;
    float intersectionProjection = glm::dot(relativeEnd, intersection);
    if (intersectionProjection < 0.0f) { // below start
        return findRaySphereIntersection(origin, direction, start, radius, distance);
        
    } else if (intersectionProjection > capsuleLength) { // above end
        return findRaySphereIntersection(origin, direction, end, radius, distance);
    } 
    distance = t; // between start and end
    return true;
}
Esempio n. 2
0
bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                     bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, 
                     void** intersectedObject, bool precisionPicking) const {
    // determine the ray in the frame of the entity transformed from a unit sphere
    glm::mat4 translation = glm::translate(getPosition());
    glm::mat4 rotation = glm::mat4_cast(getRotation());
    glm::mat4 scale = glm::scale(getDimensions());
    glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint());
    glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration;
    glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
    glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
    glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));

    float localDistance;
    // NOTE: unit sphere has center of 0,0,0 and radius of 0.5
    if (findRaySphereIntersection(entityFrameOrigin, entityFrameDirection, glm::vec3(0.0f), 0.5f, localDistance)) {
        // determine where on the unit sphere the hit point occured
        glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
        // then translate back to work coordinates
        glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
        distance = glm::distance(origin,hitAt);
        return true;
    }
    return false;                
}
Esempio n. 3
0
bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                                                   bool& keepSearching, OctreeElementPointer& element,
                                                   float& distance, BoxFace& face, glm::vec3& surfaceNormal,
                                                   void** intersectedObject, bool precisionPicking) const {
    // determine the ray in the frame of the entity transformed from a unit sphere
    glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
    glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
    glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
    glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));

    float localDistance;
    // NOTE: unit sphere has center of 0,0,0 and radius of 0.5
    if (findRaySphereIntersection(entityFrameOrigin, entityFrameDirection, glm::vec3(0.0f), 0.5f, localDistance)) {
        // determine where on the unit sphere the hit point occured
        glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
        // then translate back to work coordinates
        glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
        distance = glm::distance(origin, hitAt);
        bool success;
        surfaceNormal = glm::normalize(hitAt - getCenterPosition(success));
        if (!success) {
            return false;
        }
        return true;
    }
    return false;
}