Made Ray into a class with checks so the direction will always be normalized.

This commit is contained in:
William Moberg
2015-12-17 13:41:34 +01:00
parent 03d5f0dd67
commit 5160a45b44
8 changed files with 66 additions and 57 deletions
+4
View File
@@ -1,6 +1,10 @@
#ifndef Collision_h__
#define Collision_h__
//NOTE: Collision.h needs to be #included before <GLFW/glfw3.h>,
//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 <vector>
#include "Core/Ray.h"
+1 -1
View File
@@ -3,7 +3,7 @@
#include "Core/AABB.h"
struct Ray;
class Ray;
class OctTree
{
+22 -3
View File
@@ -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__
+17 -16
View File
@@ -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;
}
+1 -1
View File
@@ -192,7 +192,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> 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.
+19 -34
View File
@@ -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>("RawModel");
auto unitBox = ResourceManager::Load<RawModel>(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);
}
+1 -1
View File
@@ -172,7 +172,7 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> 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.
+1 -1
View File
@@ -3,7 +3,7 @@
#include "Core/AABB.h"
struct Ray;
class Ray;
class World;
class Camera;