2017-06-19 3 views
0

J'ai implémenté un algorithme qui teste une intersection Ray - AABB et fonctionne correctement. Mais quand j'essaie de transformer Ray dans l'espace local de l'AABB (ce qui en fait un test Ray-OBB), je ne peux pas obtenir de résultats corrects. J'ai étudié plusieurs forums et d'autres ressources, mais il manque toujours quelque chose. (Certaines sources suggèrent d'appliquer une transformation inversée à l'origine et à la fin du rayon, et seulement ensuite la direction du calcul, autre - pour appliquer la transformation à l'origine et à la direction). Quelqu'un peut-il pointer dans la bonne direction (sans jeu de mots)?Transformation de rayon dans un test d 'intersection Ray - OBB

va ici deux fonctions responsables de la mathématique:

1) Calcul réciproque et des autres pour effectuer des tests

bool Ray::intersectsMesh(const Mesh& mesh, const Transformation& transform) { 
     float largestNearIntersection = std::numeric_limits<float>::min(); 
     float smallestFarIntersection = std::numeric_limits<float>::max(); 
     glm::mat4 modelTransformMatrix = transform.modelMatrix(); 
     Box boundingBox = mesh.boundingBox(); 

     glm::mat4 inverse = glm::inverse(transform.modelMatrix()); 

     glm::vec4 newOrigin = inverse * glm::vec4(mOrigin, 1.0); 
     newOrigin /= newOrigin.w; 
     mOrigin = newOrigin; 
     mDirection = glm::normalize(inverse * glm::vec4(mDirection, 0.0)); 

     glm::vec3 xAxis = glm::vec3(glm::column(modelTransformMatrix, 0)); 
     glm::vec3 yAxis = glm::vec3(glm::column(modelTransformMatrix, 1)); 
     glm::vec3 zAxis = glm::vec3(glm::column(modelTransformMatrix, 2)); 

     glm::vec3 OBBTranslation = glm::vec3(glm::column(modelTransformMatrix, 3)); 
     printf("trans x %f y %f z %f\n", OBBTranslation.x, OBBTranslation.y, OBBTranslation.z); 
     glm::vec3 delta = OBBTranslation - mOrigin; 

     bool earlyFalseReturn = false; 

     calculateIntersectionDistances(xAxis, delta, boundingBox.min.x, boundingBox.max.x, &largestNearIntersection, &smallestFarIntersection, &earlyFalseReturn); 
     if (smallestFarIntersection < largestNearIntersection || earlyFalseReturn) { return false; } 

     calculateIntersectionDistances(yAxis, delta, boundingBox.min.y, boundingBox.max.y, &largestNearIntersection, &smallestFarIntersection, &earlyFalseReturn); 
     if (smallestFarIntersection < largestNearIntersection || earlyFalseReturn) { return false; } 

     calculateIntersectionDistances(zAxis, delta, boundingBox.min.z, boundingBox.max.z, &largestNearIntersection, &smallestFarIntersection, &earlyFalseReturn); 
     if (smallestFarIntersection < largestNearIntersection || earlyFalseReturn) { return false; } 

     return true; 
    } 

2) fonction d'assistance (probablement pas nécessaire ici comme ne concerne que des tests de AABB et fonctionne bien)

void Ray::calculateIntersectionDistances(const glm::vec3& axis, 
              const glm::vec3& delta, 
              float minPointOnAxis, 
              float maxPointOnAxis, 
              float *largestNearIntersection, 
              float *smallestFarIntersection, 
              bool *earlyFalseRerutn) 
    { 
     float divident = glm::dot(axis, delta); 
     float denominator = glm::dot(mDirection, axis); 

     if (fabs(denominator) > 0.001f) { 
      float t1 = (divident + minPointOnAxis)/denominator; 
      float t2 = (divident + maxPointOnAxis)/denominator; 

      if (t1 > t2) { std::swap(t1, t2); } 

      *smallestFarIntersection = std::min(t2, *smallestFarIntersection); 
      *largestNearIntersection = std::max(t1, *largestNearIntersection); 
     } else if (-divident + minPointOnAxis > 0.0 || -divident + maxPointOnAxis < 0.0) { 
      *earlyFalseRerutn = true; 
     } 
    } 

Répondre

0

Comme il s'est avéré, la transformation du monde du rayon -> était correcte. Le bug était dans le test d'intersection. J'ai dû remplacer complètement le code de l'intersection, car je n'ai malheureusement pas pu identifier le bogue dans l'ancien code.

code de transformation Ray:

glm::mat4 inverse = glm::inverse(transform.modelMatrix()); 
glm::vec4 start = inverse * glm::vec4(mOrigin, 1.0); 
glm::vec4 direction = inverse * glm::vec4(mDirection, 0.0); 
direction = glm::normalize(direction); 

Et Ray - Test AABB a été volé here