/* * bvhintersection.cpp * * Created on: Jul 5, 2013 * Author: gregor */ #include #include "GLTB/rng.h" #include "GLTB/geom/bvh.h" #include "GLTB/geom/intersection.h" #include "GLTB/geom/randomdir.h" struct Hitpoint { glm::vec3 position; size_t primitiveIndex; float distance; }; // brute force ray intersection routine for comparison bool intersectRay(const std::vector> &triangles, const gltb::Ray &ray, Hitpoint &hitpoint) { hitpoint.distance = -1; for (unsigned int i = 0; i < triangles.size(); i++) { gltb::Triangle triangle = triangles[i]; glm::vec3 hit; float distance; if(gltb::intersects(triangle, ray, hit, distance)) { if(distance < hitpoint.distance || hitpoint.distance == -1) { hitpoint.distance = distance; hitpoint.position = hit; hitpoint.primitiveIndex = i; } } } if(hitpoint.distance == -1) { return false; } return true; } // brute force ray intersection routine for comparison bool intersectRayAnyHit(const std::vector> &triangles, const gltb::Ray &ray, float maxDistance) { for (unsigned int j = 0; j < triangles.size(); j++) { gltb::Triangle triangle = triangles[j]; float distance; if(gltb::intersects(triangle, ray, distance)) { if(distance > 0 && distance < maxDistance) { return true; } } } return false; } glm::vec3 pointWithinBounds(const gltb::AABB &bounds, gltb::Random &rng) { glm::vec3 result; for(unsigned int i = 0; i < 3; i++) { result[i] = rng.genrandReal1(); } result = result * (bounds.max - bounds.min) + bounds.min; return result; } std::vector> generateTriangleSoup(gltb::AABB bounds, int numTriangles, gltb::Random &rng) { std::vector> triangles; for(int i = 0; i < numTriangles; i++) { triangles.push_back(gltb::Triangle(pointWithinBounds(bounds, rng), pointWithinBounds(bounds, rng), pointWithinBounds(bounds, rng))); } return triangles; } TEST(TriangleBVH, testIntersectionRandomized) { const int numSoups = 100; const int minTriangles = 100; const int maxTriangles = 10000; const int maxTrianglesPerNode = 10; const int numIntersections = 1000; gltb::AABB bounds(glm::vec3(-100, -100, -100), glm::vec3(100, 100, 100)); gltb::Random rng; for(int i = 0; i < numSoups; i++) { int numTriangles = rng.genrandInt32() % (maxTriangles - minTriangles) + minTriangles; std::vector> soup = generateTriangleSoup(bounds, numTriangles, rng); gltb::BVH bvh(new gltb::BVHTriangleSet(soup), maxTrianglesPerNode); for(int j = 0; j < numIntersections; j++) { gltb::Ray ray; ray.start = pointWithinBounds(bounds, rng); ray.direction = gltb::getRandomDir(rng); Hitpoint hitPoint; bool referenceHit = intersectRay(soup, ray, hitPoint); size_t bvhTriangleIndex; float bvhDistance; glm::vec3 bvhHitPoint; bool bvhHit = bvh.intersectNearest(ray, bvhTriangleIndex, bvhDistance, bvhHitPoint); ASSERT_EQ(bvhHit, referenceHit); if(bvhHit) { ASSERT_EQ(bvhTriangleIndex, hitPoint.primitiveIndex); ASSERT_FLOAT_EQ(bvhDistance, hitPoint.distance); ASSERT_FLOAT_EQ(bvhHitPoint.x, hitPoint.position.x); ASSERT_FLOAT_EQ(bvhHitPoint.y, hitPoint.position.y); ASSERT_FLOAT_EQ(bvhHitPoint.z, hitPoint.position.z); } } } } TEST(TriangleBVH, testIntersectionAnyHitRandomized) { const int numSoups = 100; const int minTriangles = 100; const int maxTriangles = 10000; const int maxTrianglesPerNode = 10; const int numIntersections = 1000; gltb::AABB bounds(glm::vec3(-100, -100, -100), glm::vec3(100, 100, 100)); gltb::Random rng; for(int i = 0; i < numSoups; i++) { int numTriangles = rng.genrandInt32() % (maxTriangles - minTriangles) + minTriangles; std::vector> soup = generateTriangleSoup(bounds, numTriangles, rng); gltb::BVH bvh(new gltb::BVHTriangleSet(soup), maxTrianglesPerNode); for(int j = 0; j < numIntersections; j++) { gltb::Ray ray; ray.start = pointWithinBounds(bounds, rng); ray.direction = gltb::getRandomDir(rng); float maxDistance = rng.genrandReal1() * 100; bool referenceHit = intersectRayAnyHit(soup, ray, maxDistance); bool bvhHit = bvh.intersectAny(ray, maxDistance); ASSERT_EQ(bvhHit, referenceHit); } } } int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }