diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index 3287c0ce88..9aa0f21aa8 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -310,31 +310,66 @@ bool AABox::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& v for (int i = 0; i < 3; i++) { a = 0.5f * acceleration[i]; b = velocity[i]; - { // min - c = origin[i] - _corner[i]; - possibleDistances = { FLT_MAX, FLT_MAX }; - if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { - bool hit = false; - checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); - checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); - if (hit) { - minFace = BoxFace(2 * i); - minNormal = glm::vec3(0.0f); - minNormal[i] = -1.0f; + if (origin[i] < _corner[i]) { + // If we're below _corner, we only need to check the min face + { // min + c = origin[i] - _corner[i]; + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i); + minNormal = glm::vec3(0.0f); + minNormal[i] = -1.0f; + } } } - } - { // max - c = origin[i] - (_corner[i] + _scale[i]); - possibleDistances = { FLT_MAX, FLT_MAX }; - if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { - bool hit = false; - checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); - checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); - if (hit) { - minFace = BoxFace(2 * i + 1); - minNormal = glm::vec3(0.0f); - minNormal[i] = 1.0f; + } else if (origin[i] > _corner[i] + _scale[i]) { + // If we're above _corner + _scale, we only need to check the max face + { // max + c = origin[i] - (_corner[i] + _scale[i]); + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i + 1); + minNormal = glm::vec3(0.0f); + minNormal[i] = 1.0f; + } + } + } + } else { + // If we're inside on this axis, we could hit either face depending on our velocity and acceleration, so we need to check both + { // min + c = origin[i] - _corner[i]; + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i); + minNormal = glm::vec3(0.0f); + minNormal[i] = -1.0f; + } + } + } + { // max + c = origin[i] - (_corner[i] + _scale[i]); + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i + 1); + minNormal = glm::vec3(0.0f); + minNormal[i] = 1.0f; + } } } } diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index d1a138fcdb..24af2855de 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -306,31 +306,66 @@ bool AACube::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& for (int i = 0; i < 3; i++) { a = 0.5f * acceleration[i]; b = velocity[i]; - { // min - c = origin[i] - _corner[i]; - possibleDistances = { FLT_MAX, FLT_MAX }; - if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { - bool hit = false; - checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); - checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); - if (hit) { - minFace = BoxFace(2 * i); - minNormal = glm::vec3(0.0f); - minNormal[i] = -1.0f; + if (origin[i] < _corner[i]) { + // If we're below _corner, we only need to check the min face + { // min + c = origin[i] - _corner[i]; + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i); + minNormal = glm::vec3(0.0f); + minNormal[i] = -1.0f; + } } } - } - { // max - c = origin[i] - (_corner[i] + _scale); - possibleDistances = { FLT_MAX, FLT_MAX }; - if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { - bool hit = false; - checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); - checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); - if (hit) { - minFace = BoxFace(2 * i + 1); - minNormal = glm::vec3(0.0f); - minNormal[i] = 1.0f; + } else if (origin[i] > _corner[i] + _scale) { + // If we're above _corner + _scale, we only need to check the max face + { // max + c = origin[i] - (_corner[i] + _scale); + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i + 1); + minNormal = glm::vec3(0.0f); + minNormal[i] = 1.0f; + } + } + } + } else { + // If we're inside on this axis, we could hit either face depending on our velocity and acceleration, so we need to check both + { // min + c = origin[i] - _corner[i]; + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i); + minNormal = glm::vec3(0.0f); + minNormal[i] = -1.0f; + } + } + } + { // max + c = origin[i] - (_corner[i] + _scale); + possibleDistances = { FLT_MAX, FLT_MAX }; + if (computeRealQuadraticRoots(a, b, c, possibleDistances)) { + bool hit = false; + checkPossibleParabolicIntersection(possibleDistances.first, i, minDistance, origin, velocity, acceleration, hit); + checkPossibleParabolicIntersection(possibleDistances.second, i, minDistance, origin, velocity, acceleration, hit); + if (hit) { + minFace = BoxFace(2 * i + 1); + minNormal = glm::vec3(0.0f); + minNormal[i] = 1.0f; + } } } } diff --git a/tests/shared/src/AACubeTests.cpp b/tests/shared/src/AACubeTests.cpp index 469dcfa981..95a4d7f9f0 100644 --- a/tests/shared/src/AACubeTests.cpp +++ b/tests/shared/src/AACubeTests.cpp @@ -152,3 +152,47 @@ void AACubeTests::touchesSphere() { } } +void AACubeTests::rayVsParabolaPerformance() { + // Test performance of findRayIntersection vs. findParabolaIntersection + // 100000 cubes with scale 500 in the +x +y +z quadrant + const int NUM_CUBES = 100000; + const float MAX_POS = 1000.0f; + const float MAX_SCALE = 500.0f; + int numRayHits = 0; + int numParabolaHits = 0; + std::vector cubes; + cubes.reserve(NUM_CUBES); + for (int i = 0; i < NUM_CUBES; i++) { + cubes.emplace_back(glm::vec3(randFloatInRange(0.0f, MAX_POS), randFloatInRange(0.0f, MAX_POS), randFloatInRange(0.0f, MAX_POS)), MAX_SCALE); + } + + glm::vec3 origin(0.0f); + glm::vec3 direction = glm::normalize(glm::vec3(1.0f)); + float distance; + BoxFace face; + glm::vec3 normal; + auto start = std::chrono::high_resolution_clock::now(); + for (auto& cube : cubes) { + if (cube.findRayIntersection(origin, direction, distance, face, normal)) { + numRayHits++; + } + } + + auto rayTime = std::chrono::high_resolution_clock::now() - start; + start = std::chrono::high_resolution_clock::now(); + direction = 10.0f * direction; + glm::vec3 acceleration = glm::vec3(-0.0001f, -0.0001f, -0.0001f); + for (auto& cube : cubes) { + if (cube.findParabolaIntersection(origin, direction, acceleration, distance, face, normal)) { + numParabolaHits++; + } + } + auto parabolaTime = std::chrono::high_resolution_clock::now() - start; + + qDebug() << "Ray vs. Parabola perfomance: rayHit%:" << numRayHits / ((float)NUM_CUBES) * 100.0f << ", rayTime:" << rayTime.count() << + ", parabolaHit%:" << numParabolaHits / ((float)NUM_CUBES) * 100.0f << ", parabolaTime:" << parabolaTime.count() << ", parabolaTime/rayTime: " << (float)parabolaTime.count()/(float)rayTime.count(); +} + +void AACubeTests::cleanupTestCase() { + +} \ No newline at end of file diff --git a/tests/shared/src/AACubeTests.h b/tests/shared/src/AACubeTests.h index a2b2e08cc5..569c978929 100644 --- a/tests/shared/src/AACubeTests.h +++ b/tests/shared/src/AACubeTests.h @@ -23,6 +23,8 @@ private slots: void ctorsAndSetters(); void containsPoint(); void touchesSphere(); + void rayVsParabolaPerformance(); + void cleanupTestCase(); }; #endif // hifi_AACubeTests_h