Math: Reverse plane direction (to make it more standard)

This commit is contained in:
SirLynix 2023-06-21 19:50:03 +02:00
parent 9eb4c43997
commit 622b6cbec9
4 changed files with 81 additions and 103 deletions

View File

@ -140,10 +140,19 @@ namespace Nz
template<typename T> template<typename T>
constexpr bool Frustum<T>::Contains(const Box<T>& box) const constexpr bool Frustum<T>::Contains(const Box<T>& box) const
{ {
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ // https://gdbooks.gitbooks.io/3dcollisions/content/Chapter2/static_aabb_plane.html
// https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling
Vector3<T> center = box.GetCenter();
Vector3<T> extents = box.GetLengths() * T(0.5);
for (const auto& plane : m_planes) for (const auto& plane : m_planes)
{ {
if (plane.Distance(box.GetPositiveVertex(plane.normal)) < T(0.0)) Vector3<T> projectedExtents = extents * plane.normal.GetAbs();
float radius = projectedExtents.x + projectedExtents.y + projectedExtents.z;
float distance = plane.Distance(center);
if (distance < T(-radius))
return false; return false;
} }
@ -300,14 +309,23 @@ namespace Nz
template<typename T> template<typename T>
constexpr IntersectionSide Frustum<T>::Intersect(const Box<T>& box) const constexpr IntersectionSide Frustum<T>::Intersect(const Box<T>& box) const
{ {
// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/ // https://gdbooks.gitbooks.io/3dcollisions/content/Chapter2/static_aabb_plane.html
// https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling
IntersectionSide side = IntersectionSide::Inside; IntersectionSide side = IntersectionSide::Inside;
Vector3<T> center = box.GetCenter();
Vector3<T> extents = box.GetLengths() * T(0.5);
for (const auto& plane : m_planes) for (const auto& plane : m_planes)
{ {
if (plane.Distance(box.GetPositiveVertex(plane.normal)) < T(0.0)) Vector3<T> projectedExtents = extents * plane.normal.GetAbs();
float radius = projectedExtents.x + projectedExtents.y + projectedExtents.z;
float distance = plane.Distance(center);
if (distance < T(-radius))
return IntersectionSide::Outside; return IntersectionSide::Outside;
else if (plane.Distance(box.GetNegativeVertex(plane.normal)) < T(0.0)) else if (distance < T(radius))
side = IntersectionSide::Intersecting; side = IntersectionSide::Intersecting;
} }
@ -483,101 +501,39 @@ namespace Nz
template<typename T> template<typename T>
Frustum<T> Frustum<T>::Extract(const Matrix4<T>& viewProjMatrix) Frustum<T> Frustum<T>::Extract(const Matrix4<T>& viewProjMatrix)
{ {
// http://www.crownandcutlass.com/features/technicaldetails/frustum.html
T plane[4];
T invLength;
EnumArray<FrustumPlane, Plane<T>> planes; EnumArray<FrustumPlane, Plane<T>> planes;
planes[FrustumPlane::Left].normal.x = viewProjMatrix(3, 0) + viewProjMatrix(0, 0);
planes[FrustumPlane::Left].normal.y = viewProjMatrix(3, 1) + viewProjMatrix(0, 1);
planes[FrustumPlane::Left].normal.z = viewProjMatrix(3, 2) + viewProjMatrix(0, 2);
planes[FrustumPlane::Left].distance = viewProjMatrix(3, 3) + viewProjMatrix(0, 3);
// Extract the numbers for the RIGHT plane planes[FrustumPlane::Right].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(0, 0);
plane[0] = viewProjMatrix[3] - viewProjMatrix[0]; planes[FrustumPlane::Right].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(0, 1);
plane[1] = viewProjMatrix[7] - viewProjMatrix[4]; planes[FrustumPlane::Right].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(0, 2);
plane[2] = viewProjMatrix[11] - viewProjMatrix[8]; planes[FrustumPlane::Right].distance = viewProjMatrix(3, 3) - viewProjMatrix(0, 3);
plane[3] = viewProjMatrix[15] - viewProjMatrix[12];
// Normalize the result planes[FrustumPlane::Bottom].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(1, 0);
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); planes[FrustumPlane::Bottom].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(1, 1);
plane[0] *= invLength; planes[FrustumPlane::Bottom].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(1, 2);
plane[1] *= invLength; planes[FrustumPlane::Bottom].distance = viewProjMatrix(3, 3) - viewProjMatrix(1, 3);
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Right] = Plane<T>(plane); planes[FrustumPlane::Top].normal.x = viewProjMatrix(3, 0) + viewProjMatrix(1, 0);
planes[FrustumPlane::Top].normal.y = viewProjMatrix(3, 1) + viewProjMatrix(1, 1);
planes[FrustumPlane::Top].normal.z = viewProjMatrix(3, 2) + viewProjMatrix(1, 2);
planes[FrustumPlane::Top].distance = viewProjMatrix(3, 3) + viewProjMatrix(1, 3);
// Extract the numbers for the LEFT plane planes[FrustumPlane::Far].normal.x = viewProjMatrix(3, 0) + viewProjMatrix(2, 0);
plane[0] = viewProjMatrix[3] + viewProjMatrix[0]; planes[FrustumPlane::Far].normal.y = viewProjMatrix(3, 1) + viewProjMatrix(2, 1);
plane[1] = viewProjMatrix[7] + viewProjMatrix[4]; planes[FrustumPlane::Far].normal.z = viewProjMatrix(3, 2) + viewProjMatrix(2, 2);
plane[2] = viewProjMatrix[11] + viewProjMatrix[8]; planes[FrustumPlane::Far].distance = viewProjMatrix(3, 3) + viewProjMatrix(2, 3);
plane[3] = viewProjMatrix[15] + viewProjMatrix[12];
// Normalize the result planes[FrustumPlane::Near].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(2, 0);
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]); planes[FrustumPlane::Near].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(2, 1);
plane[0] *= invLength; planes[FrustumPlane::Near].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(2, 2);
plane[1] *= invLength; planes[FrustumPlane::Near].distance = viewProjMatrix(3, 3) - viewProjMatrix(2, 3);
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Left] = Plane<T>(plane); for (auto& plane : planes)
plane.Normalize();
// Extract the BOTTOM plane
plane[0] = viewProjMatrix[3] + viewProjMatrix[1];
plane[1] = viewProjMatrix[7] + viewProjMatrix[5];
plane[2] = viewProjMatrix[11] + viewProjMatrix[9];
plane[3] = viewProjMatrix[15] + viewProjMatrix[13];
// Normalize the result
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
plane[0] *= invLength;
plane[1] *= invLength;
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Bottom] = Plane<T>(plane);
// Extract the TOP plane
plane[0] = viewProjMatrix[3] - viewProjMatrix[1];
plane[1] = viewProjMatrix[7] - viewProjMatrix[5];
plane[2] = viewProjMatrix[11] - viewProjMatrix[9];
plane[3] = viewProjMatrix[15] - viewProjMatrix[13];
// Normalize the result
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
plane[0] *= invLength;
plane[1] *= invLength;
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Top] = Plane<T>(plane);
// Extract the FAR plane
plane[0] = viewProjMatrix[3] - viewProjMatrix[2];
plane[1] = viewProjMatrix[7] - viewProjMatrix[6];
plane[2] = viewProjMatrix[11] - viewProjMatrix[10];
plane[3] = viewProjMatrix[15] - viewProjMatrix[14];
// Normalize the result
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
plane[0] *= invLength;
plane[1] *= invLength;
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Far] = Plane<T>(plane);
// Extract the NEAR plane
plane[0] = viewProjMatrix[3] + viewProjMatrix[2];
plane[1] = viewProjMatrix[7] + viewProjMatrix[6];
plane[2] = viewProjMatrix[11] + viewProjMatrix[10];
plane[3] = viewProjMatrix[15] + viewProjMatrix[14];
// Normalize the result
invLength = T(1.0) / std::sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
plane[0] *= invLength;
plane[1] *= invLength;
plane[2] *= invLength;
plane[3] *= -invLength;
planes[FrustumPlane::Near] = Plane<T>(plane);
return Frustum(planes); return Frustum(planes);
} }
@ -640,4 +596,3 @@ namespace Nz
} }
#include <Nazara/Core/DebugOff.hpp> #include <Nazara/Core/DebugOff.hpp>
#include "Frustum.hpp"

View File

@ -33,6 +33,8 @@ namespace Nz
constexpr T Distance(T x, T y, T z) const; constexpr T Distance(T x, T y, T z) const;
constexpr T Distance(const Vector3<T>& point) const; constexpr T Distance(const Vector3<T>& point) const;
Plane& Normalize(T* length = nullptr);
std::string ToString() const; std::string ToString() const;
constexpr Plane& operator=(const Plane& other) = default; constexpr Plane& operator=(const Plane& other) = default;
@ -43,6 +45,7 @@ namespace Nz
static constexpr bool ApproxEqual(const Plane& lhs, const Plane& rhs, T maxDifference = std::numeric_limits<T>::epsilon()); static constexpr bool ApproxEqual(const Plane& lhs, const Plane& rhs, T maxDifference = std::numeric_limits<T>::epsilon());
static constexpr Vector3<T> Intersect(const Plane& p0, const Plane& p1, const Plane& p2); static constexpr Vector3<T> Intersect(const Plane& p0, const Plane& p1, const Plane& p2);
static constexpr Plane Lerp(const Plane& from, const Plane& to, T interpolation); static constexpr Plane Lerp(const Plane& from, const Plane& to, T interpolation);
static Plane Normalize(const Plane& plane, T* length = nullptr);
static constexpr Plane XY(); static constexpr Plane XY();
static constexpr Plane XZ(); static constexpr Plane XZ();
static constexpr Plane YZ(); static constexpr Plane YZ();

View File

@ -144,14 +144,26 @@ namespace Nz
template<typename T> template<typename T>
constexpr T Plane<T>::Distance(const Vector3<T>& point) const constexpr T Plane<T>::Distance(const Vector3<T>& point) const
{ {
return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. return normal.DotProduct(point) + distance; // ax + by + cz + d = 0.
}
template<typename T>
Plane<T>& Plane<T>::Normalize(T* length)
{
T normalLength = normal.GetLength();
normal /= normalLength;
distance /= normalLength;
if (length)
*length = normalLength;
return *this;
} }
/*! /*!
* \brief Gives a string representation * \brief Gives a string representation
* \return A string representation of the object: "Plane(Normal: Vector3(x, y, z); Distance: w)" * \return A string representation of the object: "Plane(Normal: Vector3(x, y, z); Distance: w)"
*/ */
template<typename T> template<typename T>
std::string Plane<T>::ToString() const std::string Plane<T>::ToString() const
{ {
@ -251,6 +263,15 @@ namespace Nz
return plane; return plane;
} }
template<typename T>
Plane<T> Plane<T>::Normalize(const Plane& plane, T* length)
{
Plane normalizedPlane(plane);
normalizedPlane.Normalize(length);
return normalizedPlane;
}
/*! /*!
* \brief Shorthand for the plane (0, 0, 1, 0) * \brief Shorthand for the plane (0, 0, 1, 0)
* \return A plane with components (0, 0, 1, 0) * \return A plane with components (0, 0, 1, 0)
@ -334,4 +355,3 @@ namespace Nz
} }
#include <Nazara/Core/DebugOff.hpp> #include <Nazara/Core/DebugOff.hpp>
#include "Plane.hpp"

View File

@ -259,7 +259,7 @@ namespace Nz
Vector4<T>& Vector4<T>::Normalize(T* length) Vector4<T>& Vector4<T>::Normalize(T* length)
{ {
T invLength = T(1.0) / w; T invLength = T(1.0) / w;
x *= invLength; // Warning, change this logic will break Frustum::Extract x *= invLength;
y *= invLength; y *= invLength;
z *= invLength; z *= invLength;