app/Unit_Testing/TestTriangle.cpp
#include "MobileRT/Intersection.hpp"
#include "MobileRT/Ray.hpp"
#include "MobileRT/Shapes/Triangle.hpp"
#include "MobileRT/Utils/Utils.hpp"
#include <gtest/gtest.h>
using ::MobileRT::AABB;
using ::MobileRT::Intersection;
using ::MobileRT::Ray;
using ::MobileRT::Triangle;
class TestTriangle : public testing::Test {
protected:
Triangle *triangle {};
void SetUp () final {
triangle = new Triangle(
Triangle::Builder(
::glm::vec3 {0, 0, 0},
::glm::vec3 {0, 1, 0},
::glm::vec3 {0, 0, 1}
)
.build()
);
}
void TearDown () final {
}
~TestTriangle () override;
};
TestTriangle::~TestTriangle () {
delete triangle;
}
namespace {
const Triangle triangle2 {
Triangle::Builder(
::glm::vec3 {10.0F, 0.0F, 10.0F},
::glm::vec3 {0.0F, 0.0F, 10.0F},
::glm::vec3 {0.0F, 10.0F, 10.0F}
)
.build()
};
const Triangle triangle3 {
Triangle::Builder(
::glm::vec3 {1, 1.59000003F, -1.03999996F},
::glm::vec3 {-1.01999998F, 1.59000003F, -1.03999996F},
::glm::vec3 {-0.990000009F, 0, -1.03999996F}
)
.build()
};
}//namespace
/**
* Helper method that checks if an AABB intersects a Triangle.
*
* @param min The minimum point of the AABB.
* @param max The maximum point of the AABB.
* @param triangle The triangle to check the intersection.
*/
inline void assertBoxIntersectsTriangle (const ::glm::vec3 &min,
const ::glm::vec3 &max,
const Triangle &triangle) {
const AABB box {min, max};
const bool intersected {triangle.intersect(box)};
ASSERT_EQ(true, intersected);
}
/**
* Helper method that checks if a Ray intersects a Triangle.
*
* @param orig The origin of the ray.
* @param dir The direction of the ray.
* @param triangle The triangle to check the intersection.
* @param expectedInt Whether its expected to intersect or not.
* @param primitive The primitive where the ray was casted from (default is null).
*/
inline void assertRayTriangle (const ::glm::vec3 &orig,
const ::glm::vec3 &dir,
const Triangle &triangle,
const bool expectedInt,
const void *const primitive = nullptr) {
Ray ray {dir, orig, 1, true, primitive};
Intersection intersection {::std::move(ray)};
const float lastDist {intersection.length_};
intersection = triangle.intersect(intersection);
ASSERT_EQ(expectedInt, intersection.length_ < lastDist);
}
/**
* Tests the Triangle constructor with invalid parameters.
*/
TEST_F(TestTriangle, TestInvalidConstructor) {
const ::glm::vec3 A {::glm::vec3 {0.0F, 0.0F, 0.0F}};
const ::glm::vec3 B {::glm::vec3 {0.0F, 0.0F, 0.0F}};
const ::glm::vec3 C {::glm::vec3 {0.0F, 0.0F, 0.0F}};
ASSERT_DEBUG_DEATH(Triangle::Builder(A, B, C).build();, "");
}
/**
* Tests the Triangle constructor with invalid parameters.
*/
TEST_F(TestTriangle, TestInvalidConstructor2) {
const ::glm::vec3 A {::glm::vec3 {10.0F, 0.0F, 10.0F}};
const ::glm::vec3 B {::glm::vec3 {0.0F, 0.0F, 10.0F}};
const ::glm::vec3 C {::glm::vec3 {0.0F, 10.0F, 10.0F}};
const ::glm::vec3 normalA {::glm::vec3 {0, 0, 0}};
const ::glm::vec3 normalB {::glm::vec3 {0, 0, 0}};
const ::glm::vec3 normalC {::glm::vec3 {0, 0, 0}};
ASSERT_DEBUG_DEATH(
Triangle::Builder(A, B, C)
.withNormals(normalA, normalB, normalC)
.build();,
""
);
}
/**
* Tests the Triangle constructor.
*/
TEST_F(TestTriangle, TestConstructor) {
const ::glm::vec3 A {::glm::vec3 {10.0F, 0.0F, 10.0F}};
const ::glm::vec3 B {::glm::vec3 {0.0F, 0.0F, 10.0F}};
const ::glm::vec3 C {::glm::vec3 {0.0F, 10.0F, 10.0F}};
const ::glm::vec3 normalA {::glm::vec3 {1, 2, 3}};
const ::glm::vec3 normalB {::glm::vec3 {4, 5, 6}};
const ::glm::vec3 normalC {::glm::vec3 {7, 8, 9}};
const ::glm::vec2 texCoordsA {::glm::vec2 {1, 2}};
const ::glm::vec2 texCoordsB {::glm::vec2 {4, 5}};
const ::glm::vec2 texCoordsC {::glm::vec2 {7, 8}};
const ::std::int32_t materialIndex {19};
const Triangle triangle4 {
Triangle::Builder(A, B, C)
.withNormals(normalA, normalB, normalC)
.withTexCoords(texCoordsA, texCoordsB, texCoordsC)
.withMaterialIndex(materialIndex)
.build()
};
const ::glm::vec3 pointA {triangle4.getA()};
const ::glm::vec3 pointB {pointA + triangle4.getAB()};
const ::glm::vec3 pointC {pointA + triangle4.getAC()};
const ::glm::vec3 normalA2 {::glm::normalize(normalA)};
const ::glm::vec3 normalB2 {::glm::normalize(normalB)};
const ::glm::vec3 normalC2 {::glm::normalize(normalC)};
ASSERT_EQ(materialIndex, triangle4.getMaterialIndex());
for (int i {0}; i < ::MobileRT::NumberOfAxes; ++i) {
ASSERT_FLOAT_EQ(A[i], pointA[i]);
ASSERT_FLOAT_EQ(B[i], pointB[i]);
ASSERT_FLOAT_EQ(C[i], pointC[i]);
ASSERT_FLOAT_EQ(normalA2[i], triangle4.getNormalA()[i]);
ASSERT_FLOAT_EQ(normalB2[i], triangle4.getNormalB()[i]);
ASSERT_FLOAT_EQ(normalC2[i], triangle4.getNormalC()[i]);
}
for (int i {0}; i < 2; ++i) {
ASSERT_FLOAT_EQ(texCoordsA[i], triangle4.getTexCoordA()[i]);
ASSERT_FLOAT_EQ(texCoordsB[i], triangle4.getTexCoordB()[i]);
ASSERT_FLOAT_EQ(texCoordsC[i], triangle4.getTexCoordC()[i]);
}
}
/**
* Tests the Triangle constructor.
*/
TEST_F(TestTriangle, ConstructorVALUES) {
const ::glm::vec3 pointA {triangle->getA()};
const ::glm::vec3 AC {triangle->getAC()};
const ::glm::vec3 AB {triangle->getAB()};
ASSERT_EQ(0.0F, pointA[0]);
ASSERT_EQ(0.0F, pointA[1]);
ASSERT_EQ(0.0F, pointA[2]);
const ::glm::vec3 pointB {pointA + AB};
const ::glm::vec3 pointC {pointA + AC};
ASSERT_EQ(0.0F, pointB[0]);
ASSERT_EQ(1.0F, pointB[1]);
ASSERT_EQ(0.0F, pointB[2]);
ASSERT_EQ(0.0F, pointC[0]);
ASSERT_EQ(0.0F, pointC[1]);
ASSERT_EQ(1.0F, pointC[2]);
ASSERT_EQ(0.0F, AC[0]);
ASSERT_EQ(0.0F, AC[1]);
ASSERT_EQ(1.0F, AC[2]);
ASSERT_EQ(0.0F, AB[0]);
ASSERT_EQ(1.0F, AB[1]);
ASSERT_EQ(0.0F, AB[2]);
const ::glm::vec3 bc {pointC - pointB};
ASSERT_EQ(0.0F, bc[0]);
ASSERT_EQ(-1.0F, bc[1]);
ASSERT_EQ(1.0F, bc[2]);
}
/**
* Tests the calculation of an AABB of a triangle.
*/
TEST_F(TestTriangle, AABB) {
const AABB box {triangle->getAABB()};
ASSERT_EQ(0.0F, box.getPointMin()[0]);
ASSERT_EQ(0.0F, box.getPointMin()[1]);
ASSERT_EQ(0.0F, box.getPointMin()[2]);
ASSERT_EQ(0.0F, box.getPointMax()[0]);
ASSERT_EQ(1.0F, box.getPointMax()[1]);
ASSERT_EQ(1.0F, box.getPointMax()[2]);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside01) {
const ::glm::vec3 min {-1, -1, -1};
const ::glm::vec3 max {2, 2, 2};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside02) {
const ::glm::vec3 min {0, 0, 0};
const ::glm::vec3 max {3, 3, 3};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside03) {
const ::glm::vec3 min {0, 0, 0};
const ::glm::vec3 max {0, 1, 1};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside04) {
const ::glm::vec3 min {0, 0, 0};
const ::glm::vec3 max {0, 0.5, 0.5};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside05) {
const ::glm::vec3 min {-1, -1, -1};
const ::glm::vec3 max {0.1F, 0.1F, 0.1F};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
TEST_F(TestTriangle, intersectBoxInside06) {
const ::glm::vec3 min {-1, 0.4F, 0.4F};
const ::glm::vec3 max {1, 1.4F, 1.4F};
assertBoxIntersectsTriangle(min, max, *this->triangle);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside07) {
const ::glm::vec3 min {-1, 0.4F, 0.7F};
const ::glm::vec3 max {1, 1.4F, 1.4F};
const AABB box {min, max};
const bool intersected {triangle->intersect(box)};
ASSERT_EQ(false, intersected);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside08) {
const ::glm::vec3 min {1.25F, 1.25F, 10};
const ::glm::vec3 max {2.5F, 2.5F, 10};
assertBoxIntersectsTriangle(min, max, triangle3);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside09) {
const ::glm::vec3 min {-1, -1, 10};
const ::glm::vec3 max {11, 11, 10};
assertBoxIntersectsTriangle(min, max, triangle2);
}
/**
* Tests intersecting an AABB with a Triangle.
*/
TEST_F(TestTriangle, intersectBoxInside10) {
const ::glm::vec3 min {-11.0200005F, 0.794949531F, -11.04F};
const ::glm::vec3 max {-0.0100002289F, 11.5899992F, -0.0250005722F};
assertBoxIntersectsTriangle(min, max, triangle3);
}
/**
* Tests the copy constructor of a ::glm::vector.
*/
TEST_F(TestTriangle, ConstructorCOPY) {
const ::glm::vec3 point1 {1.0F, 2.0F, 3.0F};
ASSERT_EQ(1.0F, point1[0]);
ASSERT_EQ(2.0F, point1[1]);
ASSERT_EQ(3.0F, point1[2]);
}
/**
* Tests the operator less of a ::glm::vector.
*/
TEST_F(TestTriangle, OperatorLESS) {
const ::glm::vec3 point1 {3.0F, 2.0F, 1.0F};
const ::glm::vec3 point2 {1.0F, 2.0F, 3.0F};
const ::glm::vec3 vector {point2 - point1};
ASSERT_EQ(-2.0F, vector[0]);
ASSERT_EQ(0.0F, vector[1]);
ASSERT_EQ(2.0F, vector[2]);
}
/**
* Tests the operator plus of a ::glm::vector.
*/
TEST_F(TestTriangle, OperatorMORE) {
const ::glm::vec3 vector {3.0F, 2.0F, 1.0F};
const ::glm::vec3 point {1.0F, 2.0F, 3.0F};
const ::glm::vec3 dest {point + vector};
ASSERT_EQ(4.0F, dest[0]);
ASSERT_EQ(4.0F, dest[1]);
ASSERT_EQ(4.0F, dest[2]);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayInside01) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 0, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, true);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayInside02) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 1, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, true);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayInside03) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 0, 1} - orig};
assertRayTriangle(orig, dir, *this->triangle, true);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside01) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 1.000001, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside02) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 0, 1.000001} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside03) {
const ::glm::vec3 orig {2, 2, 2};
const ::glm::vec3 dir {::glm::vec3 {0.000001, 0, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside04) {
const ::glm::vec3 orig {2, 2, 2};
const ::glm::vec3 dir {::glm::vec3 {-1, 0, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside05) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, -0.000001, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests the intersection of a Ray with a Triangle.
*/
TEST_F(TestTriangle, intersectRayOutside06) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 0, -0.000001} - orig};
assertRayTriangle(orig, dir, *this->triangle, false);
}
/**
* Tests intersecting a Ray with a Triangle and that Ray has the origin from the same Triangle,
* so it shouldn't intersect.
*/
TEST_F(TestTriangle, intersectRayFromPrimitive) {
const ::glm::vec3 orig {2, 0, 0};
const ::glm::vec3 dir {::glm::vec3 {0, 0, 0} - orig};
assertRayTriangle(orig, dir, *this->triangle, false, this->triangle);
}