diff --git a/include/Nazara/Math/Frustum.hpp b/include/Nazara/Math/Frustum.hpp index 64ff5fde0..ab459eb36 100644 --- a/include/Nazara/Math/Frustum.hpp +++ b/include/Nazara/Math/Frustum.hpp @@ -32,6 +32,8 @@ namespace Nz Frustum(const Frustum& frustum) = default; ~Frustum() = default; + Vector3 ComputeCorner(BoxCorner corner) const; + bool Contains(const BoundingVolume& volume) const; bool Contains(const Box& box) const; bool Contains(const OrientedBox& orientedBox) const; @@ -47,8 +49,6 @@ namespace Nz IntersectionSide Intersect(const Sphere& sphere) const; IntersectionSide Intersect(const Vector3* points, std::size_t pointCount) const; - template Frustum& Set(const Frustum& frustum); - std::string ToString() const; Frustum& operator=(const Frustum& other) = default; diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index 867d9c327..849474201 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -49,6 +49,31 @@ namespace Nz m_planes[i].Set(frustum.m_planes[i]); } + /*! + * \brief Computes the position of a frustum corner + * \return The corner position + * + * \param corner Which corner to compute + */ + template + Vector3 Frustum::ComputeCorner(BoxCorner corner) const + { + switch (corner) + { + case BoxCorner::FarLeftBottom: return Plane::Intersect(GetPlane(FrustumPlane::Far), GetPlane(FrustumPlane::Left), GetPlane(FrustumPlane::Bottom)); + case BoxCorner::FarLeftTop: return Plane::Intersect(GetPlane(FrustumPlane::Far), GetPlane(FrustumPlane::Left), GetPlane(FrustumPlane::Top)); + case BoxCorner::FarRightBottom: return Plane::Intersect(GetPlane(FrustumPlane::Far), GetPlane(FrustumPlane::Right), GetPlane(FrustumPlane::Bottom)); + case BoxCorner::FarRightTop: return Plane::Intersect(GetPlane(FrustumPlane::Far), GetPlane(FrustumPlane::Right), GetPlane(FrustumPlane::Top)); + case BoxCorner::NearLeftBottom: return Plane::Intersect(GetPlane(FrustumPlane::Near), GetPlane(FrustumPlane::Left), GetPlane(FrustumPlane::Bottom)); + case BoxCorner::NearLeftTop: return Plane::Intersect(GetPlane(FrustumPlane::Near), GetPlane(FrustumPlane::Left), GetPlane(FrustumPlane::Top)); + case BoxCorner::NearRightBottom: return Plane::Intersect(GetPlane(FrustumPlane::Near), GetPlane(FrustumPlane::Right), GetPlane(FrustumPlane::Bottom)); + case BoxCorner::NearRightTop: return Plane::Intersect(GetPlane(FrustumPlane::Near), GetPlane(FrustumPlane::Right), GetPlane(FrustumPlane::Top)); + } + + NazaraError("invalid frustum corner"); + return Vector3(); + } + /*! * \brief Checks whether or not a bounding volume is contained in the frustum * \return true if the bounding volume is entirely in the frustum diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index c8f808322..19493f51f 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -49,6 +49,7 @@ namespace Nz bool operator==(const Plane& plane) const; bool operator!=(const Plane& plane) const; + static Vector3 Intersect(const Plane& p0, const Plane& p1, const Plane& p2); static Plane Lerp(const Plane& from, const Plane& to, T interpolation); static Plane XY(); static Plane XZ(); diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index e6552ab10..62f3bb752 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -330,6 +330,28 @@ namespace Nz return !operator==(plane); } + /*! + * \brief Intersects three planes to retrieve a single intersection point + * \return The intersection point + * + * \param p0 First plane + * \param p1 Second plane + * \param p2 Third plane + * + * \remark All three planes must have differents normals otherwise result is undefined + */ + template + Vector3 Plane::Intersect(const Plane& p0, const Plane& p1, const Plane& p2) + { + // From https://donw.io/post/frustum-point-extraction/ + Vector3f bxc = Vector3f::CrossProduct(p1.normal, p2.normal); + Vector3f cxa = Vector3f::CrossProduct(p2.normal, p0.normal); + Vector3f axb = Vector3f::CrossProduct(p0.normal, p1.normal); + Vector3f r = -p0.distance * bxc - p1.distance * cxa - p2.distance * axb; + + return r * (T(1.0) / Vector3f::DotProduct(p0.normal, bxc)); + } + /*! * \brief Interpolates the plane to other one with a factor of interpolation * \return A new plane which is the interpolation of two planes @@ -343,7 +365,6 @@ namespace Nz * * \see Lerp */ - template Plane Plane::Lerp(const Plane& from, const Plane& to, T interpolation) { diff --git a/include/Nazara/Renderer/DebugDrawer.hpp b/include/Nazara/Renderer/DebugDrawer.hpp index f2af52d65..8250f1312 100644 --- a/include/Nazara/Renderer/DebugDrawer.hpp +++ b/include/Nazara/Renderer/DebugDrawer.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ namespace Nz void Draw(CommandBufferBuilder& builder); inline void DrawBox(const Boxf& box, const Color& color); + inline void DrawFrustum(const Frustumf& frustum, const Color& color); inline void DrawLine(const Vector3f& start, const Vector3f& end, const Color& color); inline void DrawLine(const Vector3f& start, const Vector3f& end, const Color& startColor, const Color& endColor); void DrawSkeleton(const Skeleton& skeleton, const Color& color); diff --git a/include/Nazara/Renderer/DebugDrawer.inl b/include/Nazara/Renderer/DebugDrawer.inl index ba6dc1e7d..3670b9062 100644 --- a/include/Nazara/Renderer/DebugDrawer.inl +++ b/include/Nazara/Renderer/DebugDrawer.inl @@ -26,6 +26,26 @@ namespace Nz DrawLine({ max.x, min.y, min.z }, { max.x, min.y, max.z }, color); } + inline void DebugDrawer::DrawFrustum(const Frustumf& frustum, const Color& color) + { + std::array corners; + for (std::size_t i = 0; i < BoxCornerCount; ++i) + corners[i] = frustum.ComputeCorner(static_cast(i)); + + DrawLine(corners[UnderlyingCast(BoxCorner::NearLeftBottom)], corners[UnderlyingCast(BoxCorner::NearRightBottom)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearLeftBottom)], corners[UnderlyingCast(BoxCorner::NearLeftTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearLeftBottom)], corners[UnderlyingCast(BoxCorner::FarLeftBottom)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::FarRightTop)], corners[UnderlyingCast(BoxCorner::FarLeftTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::FarRightTop)], corners[UnderlyingCast(BoxCorner::FarRightBottom)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::FarRightTop)], corners[UnderlyingCast(BoxCorner::NearRightTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::FarLeftBottom)], corners[UnderlyingCast(BoxCorner::FarRightBottom)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::FarLeftBottom)], corners[UnderlyingCast(BoxCorner::FarLeftTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearLeftTop)], corners[UnderlyingCast(BoxCorner::NearRightTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearLeftTop)], corners[UnderlyingCast(BoxCorner::FarLeftTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearRightBottom)], corners[UnderlyingCast(BoxCorner::NearRightTop)], color); + DrawLine(corners[UnderlyingCast(BoxCorner::NearRightBottom)], corners[UnderlyingCast(BoxCorner::FarRightBottom)], color); + } + inline void DebugDrawer::DrawLine(const Vector3f& start, const Vector3f& end, const Color& color) { return DrawLine(start, end, color, color);