also add unit tests for indRayRectangleIntersection()
Showing the changes to libraries/shared/src/GeometryUtil.cpp (1 of 3 files). Show all
Unified · Split
| @@ -11,10 +11,10 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <cstring> |
| 13 | 13 | #include <cmath> |
| 14 | +#include <glm/gtx/quaternion.hpp> | |
| 14 | 15 | |
| 15 | 16 | #include "GeometryUtil.h" |
| 16 | 17 | #include "NumericalConstants.h" |
| 17 | −#include "PlaneShape.h" | |
| 18 | 18 | #include "RayIntersectionInfo.h" |
| 19 | 19 | |
| 20 | 20 | glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) { |
| @@ -496,31 +496,45 @@ void PolygonClip::copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& len · 475 unmodified lines | ||
| 496 | 496 | |
| 497 | 497 | bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::quat& rotation, |
| 498 | 498 | const glm::vec3& position, const glm::vec2& dimensions, float& distance) { |
| 499 | − RayIntersectionInfo rayInfo; | |
| 500 | − rayInfo._rayStart = origin; | |
| 501 | − rayInfo._rayDirection = direction; | |
| 502 | − rayInfo._rayLength = std::numeric_limits<float>::max(); | |
| 503 | − | |
| 504 | − PlaneShape plane; | |
| 505 | − | |
| 506 | 499 | const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); |
| 507 | 500 | glm::vec3 normal = rotation * UNROTATED_NORMAL; |
| 508 | − plane.setNormal(normal); | |
| 509 | − plane.setPoint(position); // the position is definitely a point on our plane | |
| 510 | − | |
| 511 | − bool intersects = plane.findRayIntersection(rayInfo); | |
| 512 | 501 | |
| 513 | − if (intersects) { | |
| 514 | − distance = rayInfo._hitDistance; | |
| 502 | + bool maybeIntersects = false; | |
| 503 | + float denominator = glm::dot(normal, direction); | |
| 504 | + glm::vec3 offset = origin - position; | |
| 505 | + float normDotOffset = glm::dot(offset, normal); | |
| 506 | + float d = 0.0f; | |
| 507 | + if (fabsf(denominator) < EPSILON) { | |
| 508 | + // line is perpendicular to plane | |
| 509 | + if (fabsf(normDotOffset) < EPSILON) { | |
| 510 | + // ray starts on the plane | |
| 511 | + maybeIntersects = true; | |
| 512 | + | |
| 513 | + // compute distance to closest approach | |
| 514 | + d = - glm::dot(offset, direction); // distance to closest approach of center of rectangle | |
| 515 | + if (d < 0.0f) { | |
| 516 | + // ray points away from center of rectangle, so ray's start is the closest approach | |
| 517 | + d = 0.0f; | |
| 518 | + } | |
| 519 | + } | |
| 520 | + } else { | |
| 521 | + d = - normDotOffset / denominator; | |
| 522 | + if (d > 0.0f) { | |
| 523 | + // ray points toward plane | |
| 524 | + maybeIntersects = true; | |
| 525 | + } | |
| 526 | + } | |
| 515 | 527 | |
| 516 | − glm::vec3 hitPosition = origin + (distance * direction); | |
| 528 | + if (maybeIntersects) { | |
| 529 | + glm::vec3 hitPosition = origin + (d * direction); | |
| 517 | 530 | glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - position); |
| 518 | − | |
| 519 | 531 | glm::vec2 halfDimensions = 0.5f * dimensions; |
| 520 | − | |
| 521 | − intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x | |
| 522 | − && -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y; | |
| 532 | + if (fabsf(localHitPosition.x) < halfDimensions.x && fabsf(localHitPosition.y) < halfDimensions.y) { | |
| 533 | + // only update distance on intersection | |
| 534 | + distance = d; | |
| 535 | + return true; | |
| 536 | + } | |
| 523 | 537 | } |
| 524 | 538 | |
| 525 | − return intersects; | |
| 539 | + return false; | |
| 526 | 540 | } |