diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 64bf2d2c..714cee3f 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -1,6 +1,10 @@ #ifndef Collision_h__ #define Collision_h__ +//NOTE: Collision.h needs to be #included before , +//because Collision #includes "RawModel.h", which has "Texture.h", which has "OpenGL.h" which must be #included first +//or you will get "fatal error C1189: #error: gl.h included before glew.h" + #include #include "Core/Ray.h" diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/OctTree.h index c09ab63e..cdb21fbb 100644 --- a/include/Engine/Core/OctTree.h +++ b/include/Engine/Core/OctTree.h @@ -3,7 +3,7 @@ #include "Core/AABB.h" -struct Ray; +class Ray; class OctTree { diff --git a/include/Engine/Core/Ray.h b/include/Engine/Core/Ray.h index 64392cbc..2ed192a2 100644 --- a/include/Engine/Core/Ray.h +++ b/include/Engine/Core/Ray.h @@ -2,11 +2,30 @@ #define Ray_h__ #include "../GLM.h" +#include "Common.h" -struct Ray +class Ray { - glm::vec3 Origin; - glm::vec3 Direction; +public: + Ray(const glm::vec3& origin, const glm::vec3& dir) + : m_Origin(origin) + , m_Direction(glm::normalize(dir)) + { + IF_DEBUG_IS(true) { + if (glm::any(glm::isnan(m_Direction))) { + LOG_WARNING("Ray Direction was set to the zero-vector, expect unknown side effects and/or crashes."); + } + } + } + const glm::vec3& Origin() const { return m_Origin; } + const glm::vec3& Direction() const { return m_Direction; } + //Sets the ray origin at parameter. + void SetOrigin(const glm::vec3& origin) { m_Origin = origin; } + //Normalizes the parameter and sets direction to it. + void SetDirection(const glm::vec3& direction) { m_Direction = glm::normalize(direction); } +private: + glm::vec3 m_Origin; + glm::vec3 m_Direction; }; #endif // Ray_h__ diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index d9cf8a0e..ec6c471c 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -11,9 +11,9 @@ namespace Collision //note: this one hasnt been delta adjusted like RayVsAABB has bool RayAABBIntr(const Ray& ray, const AABB& box) { - glm::vec3 w = 75.0f * ray.Direction; + glm::vec3 w = 75.0f * ray.Direction(); glm::vec3 v = glm::abs(w); - glm::vec3 c = ray.Origin - box.Center() + w; + glm::vec3 c = ray.Origin() - box.Center() + w; glm::vec3 half = box.HalfSize(); if (abs(c.x) > v.x + half.x) { @@ -43,14 +43,15 @@ namespace Collision bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance) { - glm::vec3 invdir = 1.0f / ray.Direction; + glm::vec3 invdir = 1.0f / ray.Direction(); + glm::vec3 origin = ray.Origin(); - float t1 = (box.MinCorner().x - ray.Origin.x)*invdir.x; - float t2 = (box.MaxCorner().x - ray.Origin.x)*invdir.x; - float t3 = (box.MinCorner().y - ray.Origin.y)*invdir.y; - float t4 = (box.MaxCorner().y - ray.Origin.y)*invdir.y; - float t5 = (box.MinCorner().z - ray.Origin.z)*invdir.z; - float t6 = (box.MaxCorner().z - ray.Origin.z)*invdir.z; + float t1 = (box.MinCorner().x - origin.x)*invdir.x; + float t2 = (box.MaxCorner().x - origin.x)*invdir.x; + float t3 = (box.MinCorner().y - origin.y)*invdir.y; + float t4 = (box.MaxCorner().y - origin.y)*invdir.y; + float t5 = (box.MinCorner().z - origin.z)*invdir.z; + float t6 = (box.MaxCorner().z - origin.z)*invdir.z; float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6)); float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6)); @@ -123,16 +124,16 @@ namespace Collision glm::vec3 v0 = modelVertices[modelIndices[i]].Position; glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 - glm::vec3 m = ray.Origin - v0; + glm::vec3 m = ray.Origin() - v0; glm::vec3 MxE1 = glm::cross(m, e1); - glm::vec3 DxE2 = glm::cross(ray.Direction, e2); + glm::vec3 DxE2 = glm::cross(ray.Direction(), e2); float DetInv = glm::dot(e1, DxE2); if (std::abs(DetInv) < FLT_EPSILON) { continue; } DetInv = 1.0f / DetInv; float u = glm::dot(m, DxE2) * DetInv; - float v = glm::dot(ray.Direction, MxE1) * DetInv; + float v = glm::dot(ray.Direction(), MxE1) * DetInv; //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) { continue; @@ -158,9 +159,9 @@ namespace Collision glm::vec3 v0 = modelVertices[modelIndices[i]].Position; glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 - glm::vec3 m = ray.Origin - v0; + glm::vec3 m = ray.Origin() - v0; glm::vec3 MxE1 = glm::cross(m, e1); - glm::vec3 DxE2 = glm::cross(ray.Direction, e2);//pVec + glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec float DetInv = glm::dot(e1, DxE2); if (std::abs(DetInv) < FLT_EPSILON) { continue; @@ -171,7 +172,7 @@ namespace Collision continue; } float u = glm::dot(m, DxE2) * DetInv; - float v = glm::dot(ray.Direction, MxE1) * DetInv; + float v = glm::dot(ray.Direction(), MxE1) * DetInv; //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem //If u and v are positive, u+v <= 1, dist is positive, and less than closest. @@ -194,7 +195,7 @@ namespace Collision float v; float dist; bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v); - outHitPosition = ray.Origin + dist * ray.Direction; + outHitPosition = ray.Origin() + dist * ray.Direction(); return hit; } diff --git a/src/Engine/Core/OctTree.cpp b/src/Engine/Core/OctTree.cpp index 31b32cec..c1d8c64e 100644 --- a/src/Engine/Core/OctTree.cpp +++ b/src/Engine/Core/OctTree.cpp @@ -192,7 +192,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const std::vector childInfos; childInfos.reserve(8); for (int i = 0; i < 8; ++i) { - childInfos.push_back({ i, glm::distance(ray.Origin, m_Children[i]->m_Box.Center()) }); + childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) }); } std::sort(childInfos.begin(), childInfos.end(), isFirstLower); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 82e2e800..e6a29298 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -26,16 +26,14 @@ using boost::unit_test_framework::test_case; void RayTest(std::string fileName) { //simple box test - Ray ray; - ray.Origin = glm::vec3(-50, 0, 0); - ray.Direction = glm::normalize(glm::vec3(1, 0, 0)); + Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0)); //using a rawmodel here, else we have to init the renderingsystem ResourceManager::RegisterType("RawModel"); auto unitBox = ResourceManager::Load(fileName); - BOOST_CHECK(unitBox != nullptr); + BOOST_REQUIRE(unitBox != nullptr); bool hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); BOOST_CHECK(hit); - ray.Direction = glm::normalize(glm::vec3(-1, 0, 0)); + ray.SetDirection(glm::vec3(-1, 0, 0)); hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); BOOST_CHECK(!hit); } @@ -49,7 +47,6 @@ BOOST_AUTO_TEST_CASE(collisionTest) //fixed seed srand(2); - Ray ray; AABB someAABB; glm::vec3 minPos; glm::vec3 maxPos; @@ -57,12 +54,10 @@ BOOST_AUTO_TEST_CASE(collisionTest) int test = 0; for (size_t i = 0; i < 10; i++) { - ray.Origin.x = rand() % 100; - ray.Origin.y = rand() % 100; - ray.Origin.z = rand() % 100; - ray.Direction.x = rand() % 100; - ray.Direction.y = rand() % 100; - ray.Direction.z = rand() % 100; + Ray ray( + glm::vec3(rand() % 100, rand() % 100, rand() % 100), + glm::vec3(rand() % 100, rand() % 100, rand() % 100) + ); minPos.x = rand() % 100; minPos.y = rand() % 100; minPos.z = rand() % 100; @@ -83,7 +78,6 @@ BOOST_AUTO_TEST_CASE(collisionTest2) { //fixed seed srand(2); - Ray ray; AABB someAABB; glm::vec3 minPos; glm::vec3 maxPos; @@ -91,12 +85,10 @@ BOOST_AUTO_TEST_CASE(collisionTest2) int test = 0; for (size_t i = 0; i < 1000000; i++) { - ray.Origin.x = rand() % 100; - ray.Origin.y = rand() % 100; - ray.Origin.z = rand() % 100; - ray.Direction.x = rand() % 100; - ray.Direction.y = rand() % 100; - ray.Direction.z = rand() % 100; + Ray ray( + glm::vec3(rand() % 100, rand() % 100, rand() % 100), + glm::vec3(rand() % 100, rand() % 100, rand() % 100) + ); minPos.x = rand() % 100; minPos.y = rand() % 100; minPos.z = rand() % 100; @@ -114,7 +106,7 @@ BOOST_AUTO_TEST_CASE(collisionTest2) BOOST_AUTO_TEST_CASE(rayVsModelTest) { //simple box test - RayTest("Models/Core/UnitBox.obj"); + RayTest("Models/Core/UnitCube.obj"); } BOOST_AUTO_TEST_CASE(rayVsModelTest2) @@ -125,7 +117,6 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) // srand(7676462); // srand(7462); srand(72); - Ray ray; AABB someAABB; glm::vec3 minPos; glm::vec3 maxPos; @@ -142,19 +133,13 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) for (size_t i = 0; i < 1000000; i++) { - ray.Origin.x = rand() % 100; - ray.Origin.y = rand() % 100; - ray.Origin.z = rand() % 100; - ray.Direction.x = rand() % 100; - ray.Direction.y = rand() % 100; - ray.Direction.z = rand() % 100; - ray.Origin /= 100; - ray.Origin = glm::vec3(-2, 0, 0); - ray.Direction /= 100; + Ray ray( + glm::vec3(-2, 0, 0), + glm::vec3(rand() % 100, rand() % 100, rand() % 100) + ); //if we normalize the ray.direction when its 0,0,0 then we get nan,nan,nan - thus we have this check to prevent that - if (ray.Direction.x < 0.0001f && ray.Direction.y < 0.0001f && ray.Direction.z < 0.0001f) + if (glm::any(glm::isnan(ray.Direction()))) continue; - ray.Direction = glm::normalize(ray.Direction); z = Collision::RayVsAABB(ray, someAABB); if (z) { @@ -224,10 +209,10 @@ BOOST_AUTO_TEST_CASE(octTest) tree.AddDynamicObject(AABB(mini, -0.9f*maxi)); OctTree::Output data; glm::vec3 origin = 3.0f * mini; - bool rayIntersected = tree.RayCollides({ origin , glm::normalize(mini - origin) }, data); + bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data); BOOST_CHECK(rayIntersected); tree.ClearDynamicObjects(); - rayIntersected = tree.RayCollides({ origin , glm::normalize(mini - origin) }, data); + rayIntersected = tree.RayCollides(Ray(origin, mini - origin), data); BOOST_CHECK(!rayIntersected); } diff --git a/src/Tests/OldOctTree.cpp b/src/Tests/OldOctTree.cpp index 4aabf9ed..d3738ee6 100644 --- a/src/Tests/OldOctTree.cpp +++ b/src/Tests/OldOctTree.cpp @@ -172,7 +172,7 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const std::vector childInfos; childInfos.reserve(8); for (int i = 0; i < 8; ++i) { - childInfos.push_back({ i, glm::distance(ray.Origin, m_Children[i]->m_Box.Center()) }); + childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) }); } std::sort(childInfos.begin(), childInfos.end(), isFirstLower); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. diff --git a/src/Tests/OldOctTree.h b/src/Tests/OldOctTree.h index 316b9545..3b0eefdc 100644 --- a/src/Tests/OldOctTree.h +++ b/src/Tests/OldOctTree.h @@ -3,7 +3,7 @@ #include "Core/AABB.h" -struct Ray; +class Ray; class World; class Camera;