diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index ca8c7ef6b..82023acaf 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -140,10 +140,19 @@ namespace Nz template constexpr bool Frustum::Contains(const Box& 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 center = box.GetCenter(); + Vector3 extents = box.GetLengths() * T(0.5); + for (const auto& plane : m_planes) { - if (plane.Distance(box.GetPositiveVertex(plane.normal)) < T(0.0)) + Vector3 projectedExtents = extents * plane.normal.GetAbs(); + float radius = projectedExtents.x + projectedExtents.y + projectedExtents.z; + + float distance = plane.Distance(center); + if (distance < T(-radius)) return false; } @@ -300,14 +309,23 @@ namespace Nz template constexpr IntersectionSide Frustum::Intersect(const Box& 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; + Vector3 center = box.GetCenter(); + Vector3 extents = box.GetLengths() * T(0.5); + for (const auto& plane : m_planes) { - if (plane.Distance(box.GetPositiveVertex(plane.normal)) < T(0.0)) + Vector3 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; - else if (plane.Distance(box.GetNegativeVertex(plane.normal)) < T(0.0)) + else if (distance < T(radius)) side = IntersectionSide::Intersecting; } @@ -483,101 +501,39 @@ namespace Nz template Frustum Frustum::Extract(const Matrix4& viewProjMatrix) { - // http://www.crownandcutlass.com/features/technicaldetails/frustum.html - T plane[4]; - T invLength; - EnumArray> 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 - plane[0] = viewProjMatrix[3] - viewProjMatrix[0]; - plane[1] = viewProjMatrix[7] - viewProjMatrix[4]; - plane[2] = viewProjMatrix[11] - viewProjMatrix[8]; - plane[3] = viewProjMatrix[15] - viewProjMatrix[12]; + planes[FrustumPlane::Right].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(0, 0); + planes[FrustumPlane::Right].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(0, 1); + planes[FrustumPlane::Right].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(0, 2); + planes[FrustumPlane::Right].distance = viewProjMatrix(3, 3) - viewProjMatrix(0, 3); - // 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].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(1, 0); + planes[FrustumPlane::Bottom].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(1, 1); + planes[FrustumPlane::Bottom].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(1, 2); + planes[FrustumPlane::Bottom].distance = viewProjMatrix(3, 3) - viewProjMatrix(1, 3); - planes[FrustumPlane::Right] = Plane(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 - plane[0] = viewProjMatrix[3] + viewProjMatrix[0]; - plane[1] = viewProjMatrix[7] + viewProjMatrix[4]; - plane[2] = viewProjMatrix[11] + viewProjMatrix[8]; - plane[3] = viewProjMatrix[15] + viewProjMatrix[12]; + planes[FrustumPlane::Far].normal.x = viewProjMatrix(3, 0) + viewProjMatrix(2, 0); + planes[FrustumPlane::Far].normal.y = viewProjMatrix(3, 1) + viewProjMatrix(2, 1); + planes[FrustumPlane::Far].normal.z = viewProjMatrix(3, 2) + viewProjMatrix(2, 2); + planes[FrustumPlane::Far].distance = viewProjMatrix(3, 3) + viewProjMatrix(2, 3); - // 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].normal.x = viewProjMatrix(3, 0) - viewProjMatrix(2, 0); + planes[FrustumPlane::Near].normal.y = viewProjMatrix(3, 1) - viewProjMatrix(2, 1); + planes[FrustumPlane::Near].normal.z = viewProjMatrix(3, 2) - viewProjMatrix(2, 2); + planes[FrustumPlane::Near].distance = viewProjMatrix(3, 3) - viewProjMatrix(2, 3); - planes[FrustumPlane::Left] = Plane(plane); - - // 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(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(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(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(plane); + for (auto& plane : planes) + plane.Normalize(); return Frustum(planes); } @@ -631,13 +587,12 @@ namespace Nz std::ostream& operator<<(std::ostream& out, const Nz::Frustum& frustum) { return out << "Frustum(Bottom: " << frustum.GetPlane(Nz::FrustumPlane::Bottom) << ",\n" - << " Far: " << frustum.GetPlane(Nz::FrustumPlane::Far) << ",\n" - << " Left: " << frustum.GetPlane(Nz::FrustumPlane::Left) << ",\n" - << " Near: " << frustum.GetPlane(Nz::FrustumPlane::Near) << ",\n" - << " Right: " << frustum.GetPlane(Nz::FrustumPlane::Right) << ",\n" - << " Top: " << frustum.GetPlane(Nz::FrustumPlane::Top) << ")\n"; + << " Far: " << frustum.GetPlane(Nz::FrustumPlane::Far) << ",\n" + << " Left: " << frustum.GetPlane(Nz::FrustumPlane::Left) << ",\n" + << " Near: " << frustum.GetPlane(Nz::FrustumPlane::Near) << ",\n" + << " Right: " << frustum.GetPlane(Nz::FrustumPlane::Right) << ",\n" + << " Top: " << frustum.GetPlane(Nz::FrustumPlane::Top) << ")\n"; } } #include -#include "Frustum.hpp" diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index 0d1a4cb1d..faeae0381 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -33,6 +33,8 @@ namespace Nz constexpr T Distance(T x, T y, T z) const; constexpr T Distance(const Vector3& point) const; + Plane& Normalize(T* length = nullptr); + std::string ToString() const; 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::epsilon()); static constexpr Vector3 Intersect(const Plane& p0, const Plane& p1, const Plane& p2); 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 XZ(); static constexpr Plane YZ(); diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index dd7d5f108..808f136d7 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -144,14 +144,26 @@ namespace Nz template constexpr T Plane::Distance(const Vector3& point) const { - return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. + return normal.DotProduct(point) + distance; // ax + by + cz + d = 0. + } + + template + Plane& Plane::Normalize(T* length) + { + T normalLength = normal.GetLength(); + normal /= normalLength; + distance /= normalLength; + + if (length) + *length = normalLength; + + return *this; } /*! * \brief Gives a string representation * \return A string representation of the object: "Plane(Normal: Vector3(x, y, z); Distance: w)" */ - template std::string Plane::ToString() const { @@ -251,6 +263,15 @@ namespace Nz return plane; } + template + Plane Plane::Normalize(const Plane& plane, T* length) + { + Plane normalizedPlane(plane); + normalizedPlane.Normalize(length); + + return normalizedPlane; + } + /*! * \brief Shorthand for the plane (0, 0, 1, 0) * \return A plane with components (0, 0, 1, 0) @@ -334,4 +355,3 @@ namespace Nz } #include -#include "Plane.hpp" diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 726247f59..c1d455913 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -259,7 +259,7 @@ namespace Nz Vector4& Vector4::Normalize(T* length) { T invLength = T(1.0) / w; - x *= invLength; // Warning, change this logic will break Frustum::Extract + x *= invLength; y *= invLength; z *= invLength;