diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index f2c428bde..f3971acb1 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -37,6 +37,9 @@ class NzPlane NzString ToString() const; + bool operator==(const NzPlane& plane) const; + bool operator!=(const NzPlane& plane) const; + static NzPlane Lerp(const NzPlane& from, const NzPlane& to, T interpolation); static NzPlane XY(); static NzPlane XZ(); diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index 10ece793d..834435085 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -49,7 +49,7 @@ NzPlane::NzPlane(const NzPlane& plane) template T NzPlane::Distance(const NzVector3& point) const { - return normal.DotProduct(point) + distance; + return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. } template @@ -110,7 +110,7 @@ NzPlane& NzPlane::Set(const NzVector3& point1, const NzVector3& poin normal = edge1.CrossProduct(edge2); normal.Normalize(); - distance = -normal.DotProduct(point3); + distance = normal.DotProduct(point3); return *this; } @@ -133,6 +133,18 @@ NzString NzPlane::ToString() const return ss << "Plane(Normal: " << normal.ToString() << "; Distance: " << distance << ')'; } +template +bool NzPlane::operator==(const NzPlane& plane) const +{ + return (normal == plane.normal && NzNumberEquals(distance, plane.distance)) || (normal == -plane.normal && NzNumberEquals(distance, -plane.distance)); +} + +template +bool NzPlane::operator!=(const NzPlane& plane) const +{ + return !operator==(plane); +} + template NzPlane NzPlane::Lerp(const NzPlane& from, const NzPlane& to, T interpolation) { @@ -155,19 +167,19 @@ NzPlane NzPlane::Lerp(const NzPlane& from, const NzPlane& to, T interpolat template NzPlane NzPlane::XY() { - return NzPlane(F(0.0), F(0.0), F(1.0), F(0.0)); + return NzPlane(F(0.0), F(0.0), F(1.0), F(0.0)); } template NzPlane NzPlane::XZ() { - return NzPlane(F(0.0), F(1.0), F(0.0), F(0.0)); + return NzPlane(F(0.0), F(1.0), F(0.0), F(0.0)); } template NzPlane NzPlane::YZ() { - return NzPlane(F(1.0), F(0.0), F(0.0), F(0.0)); + return NzPlane(F(1.0), F(0.0), F(0.0), F(0.0)); } template diff --git a/include/Nazara/Math/Ray.hpp b/include/Nazara/Math/Ray.hpp index e1cc40829..24b25e110 100644 --- a/include/Nazara/Math/Ray.hpp +++ b/include/Nazara/Math/Ray.hpp @@ -34,12 +34,12 @@ class NzRay NzVector3 GetPoint(T lambda) const; - //bool Intersect(const NzBoundingVolume& volume, T* closestHit = nullptr, T* farthestHit = nullptr) const; - bool Intersect(const NzBox& box, T* closestHit = nullptr, T* farthestHit = nullptr) const; - bool Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit = nullptr, T* farthestHit = nullptr) const; - //bool Intersect(const NzOrientedBox& orientedBox, T* closestHit = nullptr, T* farthestHit = nullptr) const; + bool Intersect(const NzBoundingVolume& volume, T* closestHit = nullptr, T* furthestHit = nullptr) const; + bool Intersect(const NzBox& box, T* closestHit = nullptr, T* furthestHit = nullptr) const; + bool Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit = nullptr, T* furthestHit = nullptr) const; + bool Intersect(const NzOrientedBox& orientedBox, T* closestHit = nullptr, T* furthestHit = nullptr) const; bool Intersect(const NzPlane& plane, T* hit = nullptr) const; - bool Intersect(const NzSphere& sphere, T* closestHit = nullptr, T* farthestHit = nullptr) const; + bool Intersect(const NzSphere& sphere, T* closestHit = nullptr, T* furthestHit = nullptr) const; NzRay& MakeAxisX(); NzRay& MakeAxisY(); @@ -57,6 +57,9 @@ class NzRay NzVector3 operator*(T lambda) const; + bool operator==(const NzRay& ray) const; + bool operator!=(const NzRay& ray) const; + static NzRay AxisX(); static NzRay AxisY(); static NzRay AxisZ(); diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl index 6ee22ad4e..d0ee2d76c 100644 --- a/include/Nazara/Math/Ray.inl +++ b/include/Nazara/Math/Ray.inl @@ -59,18 +59,18 @@ T NzRay::ClosestPoint(const NzVector3& point) const template NzVector3 NzRay::GetPoint(T lambda) const { - return origin + lambda*direction; + return origin + lambda * direction; } -/* + template -bool NzRay::Intersect(const NzBoundingVolume& volume, T* closestHit, T* farthestHit) const +bool NzRay::Intersect(const NzBoundingVolume& volume, T* closestHit, T* furthestHit) const { switch (volume.extend) { case nzExtend_Finite: { if (Intersect(volume.aabb)) - return Intersect(volume.obb, closestHit, farthestHit); + return Intersect(volume.obb, closestHit, furthestHit); return false; } @@ -80,8 +80,8 @@ bool NzRay::Intersect(const NzBoundingVolume& volume, T* closestHit, T* fa if (closestHit) *closestHit = F(0.0); - if (farthestHit) - *farthestHit = std::numeric_limits::infinity(); + if (furthestHit) + *furthestHit = std::numeric_limits::infinity(); return true; } @@ -93,9 +93,9 @@ bool NzRay::Intersect(const NzBoundingVolume& volume, T* closestHit, T* fa NazaraError("Invalid extend type (0x" + NzString::Number(volume.extend, 16) + ')'); return false; } -*/ + template -bool NzRay::Intersect(const NzBox& box, T* closestHit, T* farthestHit) const +bool NzRay::Intersect(const NzBox& box, T* closestHit, T* furthestHit) const { // http://www.gamedev.net/topic/429443-obb-ray-and-obb-plane-intersection/ T tfirst = F(0.0); @@ -134,14 +134,14 @@ bool NzRay::Intersect(const NzBox& box, T* closestHit, T* farthestHit) con if (closestHit) *closestHit = tfirst; - if (farthestHit) - *farthestHit = tlast; + if (furthestHit) + *furthestHit = tlast; return true; } template -bool NzRay::Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit, T* farthestHit) const +bool NzRay::Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit, T* furthestHit) const { // http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/ // Intersection method from Real-Time Rendering and Essential Mathematics for Games @@ -192,32 +192,39 @@ bool NzRay::Intersect(const NzBox& box, const NzMatrix4& transform, T* if (closestHit) *closestHit = tMin; - if (farthestHit) - *farthestHit = tMax; + if (furthestHit) + *furthestHit = tMax; return true; } -///FIXME: Le test ci-dessous est beaucoup trop approximatif pour être vraiment utile -/// Mais le vrai problème vient certainement des OrientedBox en elles-mêmes, peut-être faut-il envisager de les refaire ? -/* template -bool NzRay::Intersect(const NzOrientedBox& orientedBox, T* closestHit, T* farthestHit) const +bool NzRay::Intersect(const NzOrientedBox& orientedBox, T* closestHit, T* furthestHit) const { - NzVector3 width = (orientedBox.GetCorner(nzBoxCorner_NearLeftBottom) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); - NzVector3 height = (orientedBox.GetCorner(nzBoxCorner_FarLeftTop) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); - NzVector3 depth = (orientedBox.GetCorner(nzBoxCorner_FarRightBottom) - orientedBox.GetCorner(nzBoxCorner_FarLeftBottom)).Normalize(); + NzVector3 corner = orientedBox.GetCorner(nzBoxCorner_FarLeftBottom); + NzVector3 oppositeCorner = orientedBox.GetCorner(nzBoxCorner_NearRightTop); + + NzVector3 width = (orientedBox.GetCorner(nzBoxCorner_NearLeftBottom) - corner); + NzVector3 height = (orientedBox.GetCorner(nzBoxCorner_FarLeftTop) - corner); + NzVector3 depth = (orientedBox.GetCorner(nzBoxCorner_FarRightBottom) - corner); // Construction de la matrice de transformation de l'OBB - NzMatrix4 matrix(width.x, height.x, depth.x, F(0.0), - width.y, height.y, depth.y, F(0.0), - width.z, height.z, depth.z, F(0.0), + NzMatrix4 matrix(width.x, height.x, depth.x, corner.x, + width.y, height.y, depth.y, corner.y, + width.z, height.z, depth.z, corner.z, F(0.0), F(0.0), F(0.0), F(1.0)); - // Test en tant qu'AABB avec une matrice de rotation - return Intersect(orientedBox.localBox, matrix, closestHit, farthestHit); + matrix.InverseAffine(); + + corner = matrix.Transform(corner); + oppositeCorner = matrix.Transform(oppositeCorner); + + NzBox tmpBox(corner, oppositeCorner); + NzRay tmpRay(matrix.Transform(origin), matrix.Transform(direction)); + + return tmpRay.Intersect(tmpBox, closestHit, furthestHit); } -*/ + template bool NzRay::Intersect(const NzPlane& plane, T* hit) const { @@ -225,9 +232,9 @@ bool NzRay::Intersect(const NzPlane& plane, T* hit) const if (NzNumberEquals(divisor, F(0.0))) return false; // perpendicular - T lambda = -(plane.normal.DotProduct(origin) + plane.distance) / divisor; // The plane is ax+by+cz=d + T lambda = -(plane.normal.DotProduct(origin) - plane.distance) / divisor; // The plane is ax + by + cz = d if (lambda < F(0.0)) - return false; // Le plan est derrière le rayon + return false; // The plane is 'behind' the ray. if (hit) *hit = lambda; @@ -236,7 +243,7 @@ bool NzRay::Intersect(const NzPlane& plane, T* hit) const } template -bool NzRay::Intersect(const NzSphere& sphere, T* closestHit, T* farthestHit) const +bool NzRay::Intersect(const NzSphere& sphere, T* closestHit, T* furthestHit) const { NzVector3 sphereRay = sphere.GetPosition() - origin; T length = sphereRay.DotProduct(direction); @@ -251,15 +258,15 @@ bool NzRay::Intersect(const NzSphere& sphere, T* closestHit, T* farthestHi return false; // if the ray is further than the radius // Calcul des points d'intersection si besoin - if (closestHit || farthestHit) + if (closestHit || furthestHit) { T deltaLambda = std::sqrt(squaredRadius - squaredDistance); if (closestHit) *closestHit = length - deltaLambda; - if (farthestHit) - *farthestHit = length + deltaLambda; + if (furthestHit) + *furthestHit = length + deltaLambda; } return true; @@ -380,6 +387,18 @@ NzVector3 NzRay::operator*(T lambda) const return GetPoint(lambda); } +template +bool NzRay::operator==(const NzRay& ray) const +{ + return direction == ray.direction && origin == ray.origin; +} + +template +bool NzRay::operator!=(const NzRay& ray) const +{ + return !operator==(ray); +} + template NzRay NzRay::AxisX() { diff --git a/tests/Nazara/Math/Plane.hpp b/tests/Nazara/Math/Plane.hpp deleted file mode 100644 index f3971acb1..000000000 --- a/tests/Nazara/Math/Plane.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Mathematics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_PLANE_HPP -#define NAZARA_PLANE_HPP - -#include -#include - -template -class NzPlane -{ - public: - NzPlane() = default; - NzPlane(T normalX, T normalY, T normalZ, T Distance); - NzPlane(const T plane[4]); - NzPlane(const NzVector3& Normal, T Distance); - NzPlane(const NzVector3& Normal, const NzVector3& point); - NzPlane(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3); - template explicit NzPlane(const NzPlane& plane); - NzPlane(const NzPlane& plane) = default; - ~NzPlane() = default; - - T Distance(const NzVector3& point) const; - T Distance(T x, T y, T z) const; - - NzPlane& Set(T normalX, T normalY, T normalZ, T Distance); - NzPlane& Set(const T plane[4]); - NzPlane& Set(const NzPlane& plane); - NzPlane& Set(const NzVector3& Normal, T Distance); - NzPlane& Set(const NzVector3& Normal, const NzVector3& point); - NzPlane& Set(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3); - template NzPlane& Set(const NzPlane& plane); - - NzString ToString() const; - - bool operator==(const NzPlane& plane) const; - bool operator!=(const NzPlane& plane) const; - - static NzPlane Lerp(const NzPlane& from, const NzPlane& to, T interpolation); - static NzPlane XY(); - static NzPlane XZ(); - static NzPlane YZ(); - - NzVector3 normal; - T distance; -}; - -template -std::ostream& operator<<(std::ostream& out, const NzPlane& plane); - -typedef NzPlane NzPlaned; -typedef NzPlane NzPlanef; - -#include - -#endif // NAZARA_PLANE_HPP diff --git a/tests/Nazara/Math/Plane.inl b/tests/Nazara/Math/Plane.inl deleted file mode 100644 index 834435085..000000000 --- a/tests/Nazara/Math/Plane.inl +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Mathematics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include - -#define F(a) static_cast(a) - -template -NzPlane::NzPlane(T normalX, T normalY, T normalZ, T D) -{ - Set(normalX, normalY, normalZ, D); -} - -template -NzPlane::NzPlane(const T plane[4]) -{ - Set(plane); -} - -template -NzPlane::NzPlane(const NzVector3& Normal, T D) -{ - Set(Normal, D); -} - -template -NzPlane::NzPlane(const NzVector3& Normal, const NzVector3& point) -{ - Set(Normal, point); -} - -template -NzPlane::NzPlane(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3) -{ - Set(point1, point2, point3); -} - -template -template -NzPlane::NzPlane(const NzPlane& plane) -{ - Set(plane); -} - -template -T NzPlane::Distance(const NzVector3& point) const -{ - return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. -} - -template -T NzPlane::Distance(T x, T y, T z) const -{ - return Distance(NzVector3(x, y, z)); -} - -template -NzPlane& NzPlane::Set(T normalX, T normalY, T normalZ, T D) -{ - distance = D; - normal.Set(normalX, normalY, normalZ); - - return *this; -} - -template -NzPlane& NzPlane::Set(const T plane[4]) -{ - normal.Set(plane[0], plane[1], plane[2]); - distance = plane[3]; - - return *this; -} - -template -NzPlane& NzPlane::Set(const NzPlane& plane) -{ - std::memcpy(this, &plane, sizeof(NzPlane)); - - return *this; -} - -template -NzPlane& NzPlane::Set(const NzVector3& Normal, T D) -{ - distance = D; - normal = Normal; - - return *this; -} - -template -NzPlane& NzPlane::Set(const NzVector3& Normal, const NzVector3& point) -{ - normal = Normal; - distance = -normal.DotProduct(point); - - return *this; -} - -template -NzPlane& NzPlane::Set(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3) -{ - NzVector3 edge1 = point2 - point1; - NzVector3 edge2 = point3 - point1; - normal = edge1.CrossProduct(edge2); - normal.Normalize(); - - distance = normal.DotProduct(point3); - - return *this; -} - -template -template -NzPlane& NzPlane::Set(const NzPlane& plane) -{ - normal.Set(plane.normal); - distance = F(plane.distance); - - return *this; -} - -template -NzString NzPlane::ToString() const -{ - NzStringStream ss; - - return ss << "Plane(Normal: " << normal.ToString() << "; Distance: " << distance << ')'; -} - -template -bool NzPlane::operator==(const NzPlane& plane) const -{ - return (normal == plane.normal && NzNumberEquals(distance, plane.distance)) || (normal == -plane.normal && NzNumberEquals(distance, -plane.distance)); -} - -template -bool NzPlane::operator!=(const NzPlane& plane) const -{ - return !operator==(plane); -} - -template -NzPlane NzPlane::Lerp(const NzPlane& from, const NzPlane& to, T interpolation) -{ - #ifdef NAZARA_DEBUG - if (interpolation < F(0.0) || interpolation > F(1.0)) - { - NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); - return NzPlane(); - } - #endif - - NzPlane plane; - plane.distance = NzLerp(from.distance, to.distance, interpolation); - plane.normal = NzVector3::Lerp(from.normal, to.normal, interpolation); - plane.normal.Normalize(); - - return plane; -} - -template -NzPlane NzPlane::XY() -{ - return NzPlane(F(0.0), F(0.0), F(1.0), F(0.0)); -} - -template -NzPlane NzPlane::XZ() -{ - return NzPlane(F(0.0), F(1.0), F(0.0), F(0.0)); -} - -template -NzPlane NzPlane::YZ() -{ - return NzPlane(F(1.0), F(0.0), F(0.0), F(0.0)); -} - -template -std::ostream& operator<<(std::ostream& out, const NzPlane& plane) -{ - return out << plane.ToString(); -} - -#undef F - -#include diff --git a/tests/Nazara/Math/Ray.hpp b/tests/Nazara/Math/Ray.hpp deleted file mode 100644 index 24b25e110..000000000 --- a/tests/Nazara/Math/Ray.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2015 Gawaboumga (https://github.com/Gawaboumga) - Jérôme Leclercq -// This file is part of the "Nazara Engine - Mathematics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_RAY_HPP -#define NAZARA_RAY_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -template -class NzRay -{ - public: - NzRay() = default; - NzRay(T X, T Y, T Z, T directionX, T directionY, T directionZ); - NzRay(const T origin[3], const T direction[3]); - NzRay(const NzPlane& planeOne, const NzPlane& planeTwo); - NzRay(const NzVector3& origin, const NzVector3& direction); - template explicit NzRay(const NzRay& ray); - template explicit NzRay(const NzVector3& origin, const NzVector3& direction); - NzRay(const NzRay& ray) = default; - ~NzRay() = default; - - T ClosestPoint(const NzVector3& point) const; - - NzVector3 GetPoint(T lambda) const; - - bool Intersect(const NzBoundingVolume& volume, T* closestHit = nullptr, T* furthestHit = nullptr) const; - bool Intersect(const NzBox& box, T* closestHit = nullptr, T* furthestHit = nullptr) const; - bool Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit = nullptr, T* furthestHit = nullptr) const; - bool Intersect(const NzOrientedBox& orientedBox, T* closestHit = nullptr, T* furthestHit = nullptr) const; - bool Intersect(const NzPlane& plane, T* hit = nullptr) const; - bool Intersect(const NzSphere& sphere, T* closestHit = nullptr, T* furthestHit = nullptr) const; - - NzRay& MakeAxisX(); - NzRay& MakeAxisY(); - NzRay& MakeAxisZ(); - - NzRay& Set(T X, T Y, T Z, T directionX, T directionY, T directionZ); - NzRay& Set(const T origin[3], const T direction[3]); - NzRay& Set(const NzPlane& planeOne, const NzPlane& planeTwo); - NzRay& Set(const NzRay& ray); - NzRay& Set(const NzVector3& origin, const NzVector3& direction); - template NzRay& Set(const NzRay& ray); - template NzRay& Set(const NzVector3& origin, const NzVector3& direction); - - NzString ToString() const; - - NzVector3 operator*(T lambda) const; - - bool operator==(const NzRay& ray) const; - bool operator!=(const NzRay& ray) const; - - static NzRay AxisX(); - static NzRay AxisY(); - static NzRay AxisZ(); - static NzRay Lerp(const NzRay& from, const NzRay& to, T interpolation); - - NzVector3 direction, origin; -}; - -template std::ostream& operator<<(std::ostream& out, const NzRay& vec); - -typedef NzRay NzRayd; -typedef NzRay NzRayf; - -#include - -#endif // NAZARA_RAY_HPP diff --git a/tests/Nazara/Math/Ray.inl b/tests/Nazara/Math/Ray.inl deleted file mode 100644 index d0ee2d76c..000000000 --- a/tests/Nazara/Math/Ray.inl +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright (C) 2015 Gawaboumga (https://github.com/Gawaboumga) - Jérôme Leclercq -// This file is part of the "Nazara Engine - Mathematics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -#define F(a) static_cast(a) - -template -NzRay::NzRay(T X, T Y, T Z, T DirectionX, T DirectionY, T DirectionZ) -{ - Set(X, Y, Z, DirectionX, DirectionY, DirectionZ); -} - -template -NzRay::NzRay(const T Origin[3], const T Direction[3]) -{ - Set(Origin, Direction); -} - -template -NzRay::NzRay(const NzPlane& planeOne, const NzPlane& planeTwo) -{ - Set(planeOne, planeTwo); -} - -template -NzRay::NzRay(const NzVector3& Origin, const NzVector3& Direction) -{ - Set(Origin, Direction); -} - -template -template -NzRay::NzRay(const NzRay& ray) -{ - Set(ray); -} - -template -template -NzRay::NzRay(const NzVector3& Origin, const NzVector3& Direction) -{ - Set(Origin, Direction); -} - -template -T NzRay::ClosestPoint(const NzVector3& point) const -{ - NzVector3 delta = point - origin; - T vsq = direction.GetSquaredLength(); - T proj = delta.DotProduct(direction); - - return proj/vsq; -} - -template -NzVector3 NzRay::GetPoint(T lambda) const -{ - return origin + lambda * direction; -} - -template -bool NzRay::Intersect(const NzBoundingVolume& volume, T* closestHit, T* furthestHit) const -{ - switch (volume.extend) - { - case nzExtend_Finite: - { - if (Intersect(volume.aabb)) - return Intersect(volume.obb, closestHit, furthestHit); - - return false; - } - - case nzExtend_Infinite: - { - if (closestHit) - *closestHit = F(0.0); - - if (furthestHit) - *furthestHit = std::numeric_limits::infinity(); - - return true; - } - - case nzExtend_Null: - return false; - } - - NazaraError("Invalid extend type (0x" + NzString::Number(volume.extend, 16) + ')'); - return false; -} - -template -bool NzRay::Intersect(const NzBox& box, T* closestHit, T* furthestHit) const -{ - // http://www.gamedev.net/topic/429443-obb-ray-and-obb-plane-intersection/ - T tfirst = F(0.0); - T tlast = std::numeric_limits::infinity(); - - NzVector3 boxMin = box.GetMinimum(); - NzVector3 boxMax = box.GetMaximum(); - - for (unsigned int i = 0; i < 3; ++i) - { - T dir = direction[i]; - T ori = origin[i]; - T max = boxMax[i]; - T min = boxMin[i]; - - if (NzNumberEquals(dir, F(0.0))) - { - if (ori < max && ori > min) - continue; - - return false; - } - - T tmin = (min - ori) / dir; - T tmax = (max - ori) / dir; - if (tmin > tmax) - std::swap(tmin, tmax); - - if (tmax < tfirst || tmin > tlast) - return false; - - tfirst = std::max(tfirst, tmin); - tlast = std::min(tlast, tmax); - } - - if (closestHit) - *closestHit = tfirst; - - if (furthestHit) - *furthestHit = tlast; - - return true; -} - -template -bool NzRay::Intersect(const NzBox& box, const NzMatrix4& transform, T* closestHit, T* furthestHit) const -{ - // http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/ - // Intersection method from Real-Time Rendering and Essential Mathematics for Games - T tMin = F(0.0); - T tMax = std::numeric_limits::infinity(); - - NzVector3 boxMin = box.GetMinimum(); - NzVector3 boxMax = box.GetMaximum(); - NzVector3 delta = transform.GetTranslation() - origin; - - // Test intersection with the 2 planes perpendicular to the OBB's X axis - for (unsigned int i = 0; i < 3; ++i) - { - NzVector3 axis(transform(0, i), transform(1, i), transform(2, i)); - T e = axis.DotProduct(delta); - T f = direction.DotProduct(axis); - - if (!NzNumberEquals(f, F(0.0))) - { - T t1 = (e + boxMin[i]) / f; // Intersection with the "left" plane - T t2 = (e + boxMax[i]) / f; // Intersection with the "right" plane - // t1 and t2 now contain distances betwen ray origin and ray-plane intersections - - // We want t1 to represent the nearest intersection, - // so if it's not the case, invert t1 and t2 - if (t1 > t2) - std::swap(t1, t2); - - // tMax is the nearest "far" intersection (amongst the X,Y and Z planes pairs) - if (t2 < tMax) - tMax = t2; - - // tMin is the farthest "near" intersection (amongst the X,Y and Z planes pairs) - if (t1 > tMin) - tMin = t1; - - // And here's the trick : - // If "far" is closer than "near", then there is NO intersection. - if (tMax < tMin) - return false; - } - else - // Rare case : the ray is almost parallel to the planes, so they don't have any "intersection" - if (-e + boxMin[i] > F(0.0) || -e + boxMax[i] < F(0.0)) - return false; - } - - if (closestHit) - *closestHit = tMin; - - if (furthestHit) - *furthestHit = tMax; - - return true; -} - -template -bool NzRay::Intersect(const NzOrientedBox& orientedBox, T* closestHit, T* furthestHit) const -{ - NzVector3 corner = orientedBox.GetCorner(nzBoxCorner_FarLeftBottom); - NzVector3 oppositeCorner = orientedBox.GetCorner(nzBoxCorner_NearRightTop); - - NzVector3 width = (orientedBox.GetCorner(nzBoxCorner_NearLeftBottom) - corner); - NzVector3 height = (orientedBox.GetCorner(nzBoxCorner_FarLeftTop) - corner); - NzVector3 depth = (orientedBox.GetCorner(nzBoxCorner_FarRightBottom) - corner); - - // Construction de la matrice de transformation de l'OBB - NzMatrix4 matrix(width.x, height.x, depth.x, corner.x, - width.y, height.y, depth.y, corner.y, - width.z, height.z, depth.z, corner.z, - F(0.0), F(0.0), F(0.0), F(1.0)); - - matrix.InverseAffine(); - - corner = matrix.Transform(corner); - oppositeCorner = matrix.Transform(oppositeCorner); - - NzBox tmpBox(corner, oppositeCorner); - NzRay tmpRay(matrix.Transform(origin), matrix.Transform(direction)); - - return tmpRay.Intersect(tmpBox, closestHit, furthestHit); -} - -template -bool NzRay::Intersect(const NzPlane& plane, T* hit) const -{ - T divisor = plane.normal.DotProduct(direction); - if (NzNumberEquals(divisor, F(0.0))) - return false; // perpendicular - - T lambda = -(plane.normal.DotProduct(origin) - plane.distance) / divisor; // The plane is ax + by + cz = d - if (lambda < F(0.0)) - return false; // The plane is 'behind' the ray. - - if (hit) - *hit = lambda; - - return true; -} - -template -bool NzRay::Intersect(const NzSphere& sphere, T* closestHit, T* furthestHit) const -{ - NzVector3 sphereRay = sphere.GetPosition() - origin; - T length = sphereRay.DotProduct(direction); - - if (length < F(0.0)) - return false; // ray is perpendicular to the vector origin - center - - T squaredDistance = sphereRay.GetSquaredLength() - length*length; - T squaredRadius = sphere.radius*sphere.radius; - - if (squaredDistance > squaredRadius) - return false; // if the ray is further than the radius - - // Calcul des points d'intersection si besoin - if (closestHit || furthestHit) - { - T deltaLambda = std::sqrt(squaredRadius - squaredDistance); - - if (closestHit) - *closestHit = length - deltaLambda; - - if (furthestHit) - *furthestHit = length + deltaLambda; - } - - return true; -} - -template -NzRay& NzRay::MakeAxisX() -{ - return Set(NzVector3::Zero(), NzVector3::UnitX()); -} - -template -NzRay& NzRay::MakeAxisY() -{ - return Set(NzVector3::Zero(), NzVector3::UnitY()); -} - -template -NzRay& NzRay::MakeAxisZ() -{ - return Set(NzVector3::Zero(), NzVector3::UnitZ()); -} - -template -NzRay& NzRay::Set(T X, T Y, T Z, T directionX, T directionY, T directionZ) -{ - direction.Set(directionX, directionY, directionZ); - origin.Set(X, Y, Z); - - return *this; -} - -template -NzRay& NzRay::Set(const T Origin[3], const T Direction[3]) -{ - direction.Set(Direction); - origin.Set(Origin); - - return *this; -} - -template -NzRay& NzRay::Set(const NzPlane& planeOne, const NzPlane& planeTwo) -{ - T termOne = planeOne.normal.GetLength(); - T termTwo = planeOne.normal.DotProduct(planeTwo.normal); - T termFour = planeTwo.normal.GetLength(); - T det = termOne * termFour - termTwo * termTwo; - - #if NAZARA_MATH_SAFE - if (NzNumberEquals(det, F(0.0))) - { - NzString error("Planes are parallel."); - - NazaraError(error); - throw std::domain_error(error); - } - #endif - - T invdet = F(1.0) / det; - T fc0 = (termFour * -planeOne.distance + termTwo * planeTwo.distance) * invdet; - T fc1 = (termOne * -planeTwo.distance + termTwo * planeOne.distance) * invdet; - - direction = planeOne.normal.CrossProduct(planeTwo.normal); - origin = planeOne.normal * fc0 + planeTwo.normal * fc1; - - return *this; -} - -template -NzRay& NzRay::Set(const NzRay& ray) -{ - std::memcpy(this, &ray, sizeof(NzRay)); - - return *this; -} - -template -NzRay& NzRay::Set(const NzVector3& Origin, const NzVector3& Direction) -{ - direction = Direction; - origin = Origin; - - return *this; -} - -template -template -NzRay& NzRay::Set(const NzRay& ray) -{ - direction.Set(ray.direction); - origin.Set(ray.origin); - - return *this; -} - -template -template -NzRay& NzRay::Set(const NzVector3& Origin, const NzVector3& Direction) -{ - direction.Set(Direction); - origin.Set(Origin); - - return *this; -} - -template -NzString NzRay::ToString() const -{ - NzStringStream ss; - - return ss << "Ray(origin: " << origin.ToString() << ", direction: " << direction.ToString() << ")"; -} - -template -NzVector3 NzRay::operator*(T lambda) const -{ - return GetPoint(lambda); -} - -template -bool NzRay::operator==(const NzRay& ray) const -{ - return direction == ray.direction && origin == ray.origin; -} - -template -bool NzRay::operator!=(const NzRay& ray) const -{ - return !operator==(ray); -} - -template -NzRay NzRay::AxisX() -{ - NzRay axis; - axis.MakeAxisX(); - - return axis; -} - -template -NzRay NzRay::AxisY() -{ - NzRay axis; - axis.MakeAxisY(); - - return axis; -} - -template -NzRay NzRay::AxisZ() -{ - NzRay axis; - axis.MakeAxisZ(); - - return axis; -} - -template -NzRay NzRay::Lerp(const NzRay& from, const NzRay& to, T interpolation) -{ - return NzRay(from.origin.Lerp(to.origin, interpolation), from.direction.Lerp(to.direction, interpolation)); -} - -template -std::ostream& operator<<(std::ostream& out, const NzRay& ray) -{ - return out << ray.ToString(); -} - -#undef F - -#include