diff --git a/include/Nazara/Math/Frustum.hpp b/include/Nazara/Math/Frustum.hpp index eb72a0efe..32ea2405f 100644 --- a/include/Nazara/Math/Frustum.hpp +++ b/include/Nazara/Math/Frustum.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace Nz @@ -26,23 +27,18 @@ namespace Nz { public: Frustum() = default; + explicit Frustum(const std::array, FrustumPlaneCount>& planes); template explicit Frustum(const Frustum& frustum); Frustum(const Frustum& frustum) = default; ~Frustum() = default; - Frustum& Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); - bool Contains(const BoundingVolume& volume) const; bool Contains(const Box& box) const; bool Contains(const OrientedBox& orientedBox) const; bool Contains(const Sphere& sphere) const; bool Contains(const Vector3& point) const; - bool Contains(const Vector3* points, unsigned int pointCount) const; + bool Contains(const Vector3* points, std::size_t pointCount) const; - Frustum& Extract(const Matrix4& clipMatrix); - Frustum& Extract(const Matrix4& view, const Matrix4& projection); - - const Vector3& GetCorner(BoxCorner corner) const; const Plane& GetPlane(FrustumPlane plane) const; IntersectionSide Intersect(const BoundingVolume& volume) const; @@ -51,12 +47,15 @@ namespace Nz IntersectionSide Intersect(const Sphere& sphere) const; IntersectionSide Intersect(const Vector3* points, std::size_t pointCount) const; - Frustum& operator=(const Frustum& other) = default; - template Frustum& Set(const Frustum& frustum); std::string ToString() const; + Frustum& operator=(const Frustum& other) = default; + + static Frustum Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up = Vector3::Up()); + static Frustum Extract(const Matrix4& viewProjMatrix); + template friend bool Serialize(SerializationContext& context, const Frustum& frustum, TypeTag>); @@ -64,8 +63,7 @@ namespace Nz friend bool Unserialize(SerializationContext& context, Frustum* frustum, TypeTag>); private: - Vector3 m_corners[BoxCornerCount]; - Plane m_planes[FrustumPlaneCount]; + std::array, FrustumPlaneCount> m_planes; }; using Frustumd = Frustum; diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index 59b0bfbe9..15bbed833 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -23,71 +23,29 @@ namespace Nz * Frustums are used to determine what is inside the camera's field of view. They help speed up the rendering process */ + /*! + * \brief Constructs a Frustum by specifying its planes + * + * \param corners Corners + * \param planes Frustum of type U to convert to type T + */ + template + Frustum::Frustum(const std::array, FrustumPlaneCount>& planes) : + m_planes(planes) + { + } + /*! * \brief Constructs a Frustum object from another type of Frustum * * \param frustum Frustum of type U to convert to type T */ - template template Frustum::Frustum(const Frustum& frustum) { - Set(frustum); - } - - /*! - * \brief Builds the frustum object - * \return A reference to this frustum which is the build up camera's field of view - * - * \param angle FOV angle - * \param ratio Rendering ratio (typically 16/9 or 4/3) - * \param zNear Distance where 'vision' begins - * \param zFar Distance where 'vision' ends - * \param eye Position of the camera - * \param target Position of the target of the camera - * \param up Direction of up vector according to the orientation of camera - */ - - template - Frustum& Frustum::Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up) - { - angle /= T(2.0); - - T tangent = angle.GetTan(); - T nearH = zNear * tangent; - T nearW = nearH * ratio; - T farH = zFar * tangent; - T farW = farH * ratio; - - Vector3 f = Vector3::Normalize(target - eye); - Vector3 u(up.GetNormal()); - Vector3 s = Vector3::Normalize(f.CrossProduct(u)); - u = s.CrossProduct(f); - - Vector3 nc = eye + f * zNear; - Vector3 fc = eye + f * zFar; - - // Computing the frustum - m_corners[UnderlyingCast(BoxCorner::FarLeftBottom)] = fc - u * farH - s * farW; - m_corners[UnderlyingCast(BoxCorner::FarLeftTop)] = fc + u * farH - s * farW; - m_corners[UnderlyingCast(BoxCorner::FarRightTop)] = fc + u * farH + s * farW; - m_corners[UnderlyingCast(BoxCorner::FarRightBottom)] = fc - u * farH + s * farW; - - m_corners[UnderlyingCast(BoxCorner::NearLeftBottom)] = nc - u * nearH - s * nearW; - m_corners[UnderlyingCast(BoxCorner::NearLeftTop)] = nc + u * nearH - s * nearW; - m_corners[UnderlyingCast(BoxCorner::NearRightTop)] = nc + u * nearH + s * nearW; - m_corners[UnderlyingCast(BoxCorner::NearRightBottom)] = nc - u * nearH + s * nearW; - - // Construction of frustum's planes - m_planes[UnderlyingCast(FrustumPlane::Bottom)].Set(m_corners[UnderlyingCast(BoxCorner::NearLeftBottom)], m_corners[UnderlyingCast(BoxCorner::NearRightBottom)], m_corners[UnderlyingCast(BoxCorner::FarRightBottom)]); - m_planes[UnderlyingCast(FrustumPlane::Far)].Set(m_corners[UnderlyingCast(BoxCorner::FarRightTop)], m_corners[UnderlyingCast(BoxCorner::FarLeftTop)], m_corners[UnderlyingCast(BoxCorner::FarLeftBottom)]); - m_planes[UnderlyingCast(FrustumPlane::Left)].Set(m_corners[UnderlyingCast(BoxCorner::NearLeftTop)], m_corners[UnderlyingCast(BoxCorner::NearLeftBottom)], m_corners[UnderlyingCast(BoxCorner::FarLeftBottom)]); - m_planes[UnderlyingCast(FrustumPlane::Near)].Set(m_corners[UnderlyingCast(BoxCorner::NearLeftTop)], m_corners[UnderlyingCast(BoxCorner::NearRightTop)], m_corners[UnderlyingCast(BoxCorner::NearRightBottom)]); - m_planes[UnderlyingCast(FrustumPlane::Right)].Set(m_corners[UnderlyingCast(BoxCorner::NearRightBottom)], m_corners[UnderlyingCast(BoxCorner::NearRightTop)], m_corners[UnderlyingCast(BoxCorner::FarRightBottom)]); - m_planes[UnderlyingCast(FrustumPlane::Top)].Set(m_corners[UnderlyingCast(BoxCorner::NearRightTop)], m_corners[UnderlyingCast(BoxCorner::NearLeftTop)], m_corners[UnderlyingCast(BoxCorner::FarLeftTop)]); - - return *this; + for (std::size_t i = 0; i < FrustumPlaneCount; ++i) + m_planes[i].Set(frustum.m_planes[i]); } /*! @@ -101,7 +59,6 @@ namespace Nz * \remark If enumeration of the volume is not defined in Extend, a NazaraError is thrown and false is returned * \remark If enumeration of the intersection is not defined in IntersectionSide, a NazaraError is thrown and false is returned. This should not never happen for a user of the library */ - template bool Frustum::Contains(const BoundingVolume& volume) const { @@ -143,7 +100,6 @@ namespace Nz * * \param box Box to check */ - template bool Frustum::Contains(const Box& box) const { @@ -217,11 +173,11 @@ namespace Nz */ template - bool Frustum::Contains(const Vector3* points, unsigned int pointCount) const + bool Frustum::Contains(const Vector3* points, std::size_t pointCount) const { - for (unsigned int i = 0; i < FrustumPlaneCount; ++i) + for (std::size_t i = 0; i < FrustumPlaneCount; ++i) { - unsigned int j; + std::size_t j; for (j = 0; j < pointCount; j++ ) { if (m_planes[i].Distance(points[j]) > T(0.0)) @@ -235,223 +191,6 @@ namespace Nz return true; } - /*! - * \brief Constructs the frustum from a Matrix4 - * \return A reference to this frustum which is the build up of projective matrix - * - * \param clipMatrix Matrix which represents the transformation of the frustum - * - * \remark A NazaraWarning is produced if clipMatrix is not inversible and corners are unchanged - */ - - template - Frustum& Frustum::Extract(const Matrix4& clipMatrix) - { - // http://www.crownandcutlass.com/features/technicaldetails/frustum.html - T plane[4]; - T invLength; - - // Extract the numbers for the RIGHT plane - plane[0] = clipMatrix[ 3] - clipMatrix[ 0]; - plane[1] = clipMatrix[ 7] - clipMatrix[ 4]; - plane[2] = clipMatrix[11] - clipMatrix[ 8]; - plane[3] = clipMatrix[15] - clipMatrix[12]; - - // 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; - - m_planes[UnderlyingCast(FrustumPlane::Right)].Set(plane); - - // Extract the numbers for the LEFT plane - plane[0] = clipMatrix[ 3] + clipMatrix[ 0]; - plane[1] = clipMatrix[ 7] + clipMatrix[ 4]; - plane[2] = clipMatrix[11] + clipMatrix[ 8]; - plane[3] = clipMatrix[15] + clipMatrix[12]; - - // 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; - - m_planes[UnderlyingCast(FrustumPlane::Left)].Set(plane); - - // Extract the BOTTOM plane - plane[0] = clipMatrix[ 3] + clipMatrix[ 1]; - plane[1] = clipMatrix[ 7] + clipMatrix[ 5]; - plane[2] = clipMatrix[11] + clipMatrix[ 9]; - plane[3] = clipMatrix[15] + clipMatrix[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; - - m_planes[UnderlyingCast(FrustumPlane::Bottom)].Set(plane); - - // Extract the TOP plane - plane[0] = clipMatrix[ 3] - clipMatrix[ 1]; - plane[1] = clipMatrix[ 7] - clipMatrix[ 5]; - plane[2] = clipMatrix[11] - clipMatrix[ 9]; - plane[3] = clipMatrix[15] - clipMatrix[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; - - m_planes[UnderlyingCast(FrustumPlane::Top)].Set(plane); - - // Extract the FAR plane - plane[0] = clipMatrix[ 3] - clipMatrix[ 2]; - plane[1] = clipMatrix[ 7] - clipMatrix[ 6]; - plane[2] = clipMatrix[11] - clipMatrix[10]; - plane[3] = clipMatrix[15] - clipMatrix[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; - - m_planes[UnderlyingCast(FrustumPlane::Far)].Set(plane); - - // Extract the NEAR plane - plane[0] = clipMatrix[ 3] + clipMatrix[ 2]; - plane[1] = clipMatrix[ 7] + clipMatrix[ 6]; - plane[2] = clipMatrix[11] + clipMatrix[10]; - plane[3] = clipMatrix[15] + clipMatrix[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; - - m_planes[UnderlyingCast(FrustumPlane::Near)].Set(plane); - - // Once planes have been extracted, we must extract points of the frustum - // Based on: http://www.gamedev.net/topic/393309-calculating-the-view-frustums-vertices/ - - Matrix4 invClipMatrix; - if (clipMatrix.GetInverse(&invClipMatrix)) - { - Vector4 corner; - - // FarLeftBottom - corner.Set(T(-1.0), T(-1.0), T(1.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::FarLeftBottom)] = Vector3(corner.x, corner.y, corner.z); - - // FarLeftTop - corner.Set(T(-1.0), T(1.0), T(1.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::FarLeftTop)] = Vector3(corner.x, corner.y, corner.z); - - // FarRightBottom - corner.Set(T(1.0), T(-1.0), T(1.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::FarRightBottom)] = Vector3(corner.x, corner.y, corner.z); - - // FarRightTop - corner.Set(T(1.0), T(1.0), T(1.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::FarRightTop)] = Vector3(corner.x, corner.y, corner.z); - - // NearLeftBottom - corner.Set(T(-1.0), T(-1.0), T(0.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::NearLeftBottom)] = Vector3(corner.x, corner.y, corner.z); - - // NearLeftTop - corner.Set(T(-1.0), T(1.0), T(0.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::NearLeftTop)] = Vector3(corner.x, corner.y, corner.z); - - // NearRightBottom - corner.Set(T(1.0), T(-1.0), T(0.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::NearRightBottom)] = Vector3(corner.x, corner.y, corner.z); - - // NearRightTop - corner.Set(T(1.0), T(1.0), T(0.0)); - corner = invClipMatrix.Transform(corner); - corner.Normalize(); - - m_corners[UnderlyingCast(BoxCorner::NearRightTop)] = Vector3(corner.x, corner.y, corner.z); - } - else - NazaraWarning("Clip matrix is not invertible, failed to compute frustum corners"); - - return *this; - } - - /*! - * \brief Constructs the frustum from the view matrix and the projection matrix - * \return A reference to this frustum which is the build up of projective matrix - * - * \param view Matrix which represents the view - * \param projection Matrix which represents the projection (the perspective) - * - * \remark A NazaraWarning is produced if the product of these matrices is not inversible and corners are unchanged - */ - - template - Frustum& Frustum::Extract(const Matrix4& view, const Matrix4& projection) - { - return Extract(Matrix4::Concatenate(view, projection)); - } - - /*! - * \brief Gets the Vector3 for the corner - * \return The position of the corner of the frustum according to enum BoxCorner - * - * \param corner Enumeration of type BoxCorner - * - * \remark If enumeration is not defined in BoxCorner and NAZARA_DEBUG defined, a NazaraError is thrown and a Vector3 uninitialised is returned - */ - - template - const Vector3& Frustum::GetCorner(BoxCorner corner) const - { - #ifdef NAZARA_DEBUG - if (UnderlyingCast(corner) > BoxCornerCount) - { - NazaraError("Corner not handled (0x" + NumberToString(UnderlyingCast(corner), 16) + ')'); - - static Vector3 dummy; - return dummy; - } - #endif - - return m_corners[UnderlyingCast(corner)]; - } - /*! * \brief Gets the Plane for the face * \return The face of the frustum according to enum FrustumPlane @@ -464,16 +203,7 @@ namespace Nz template const Plane& Frustum::GetPlane(FrustumPlane plane) const { - #ifdef NAZARA_DEBUG - if (UnderlyingCast(plane) > FrustumPlaneCount) - { - NazaraError("Frustum plane not handled (0x" + NumberToString(UnderlyingCast(plane), 16) + ')'); - - static Plane dummy; - return dummy; - } - #endif - + NazaraAssert(UnderlyingCast(plane) < FrustumPlaneCount, "invalid plane"); return m_planes[UnderlyingCast(plane)]; } @@ -617,31 +347,10 @@ namespace Nz return (c == 6) ? IntersectionSide::Inside : IntersectionSide::Intersecting; } - /*! - * \brief Sets the components of the frustum from another type of Frustum - * \return A reference to this frustum - * - * \param frustum Frustum of type U to convert its components - */ - - template - template - Frustum& Frustum::Set(const Frustum& frustum) - { - for (unsigned int i = 0; i < BoxCornerCount; ++i) - m_corners[i].Set(frustum.m_corners[i]); - - for (unsigned int i = 0; i < FrustumPlaneCount; ++i) - m_planes[i].Set(frustum.m_planes[i]); - - return *this; - } - /*! * \brief Gives a string representation * \return A string representation of the object: "Frustum(Plane ...)" */ - template std::string Frustum::ToString() const { @@ -651,6 +360,170 @@ namespace Nz return ss.str(); } + + /*! + * \brief Builds the frustum object + * \return A reference to this frustum which is the build up camera's field of view + * + * \param angle FOV angle + * \param ratio Rendering ratio (typically 16/9 or 4/3) + * \param zNear Distance where 'vision' begins + * \param zFar Distance where 'vision' ends + * \param eye Position of the camera + * \param target Position of the target of the camera + * \param up Direction of up vector according to the orientation of camera + */ + template + Frustum Frustum::Build(RadianAngle angle, T ratio, T zNear, T zFar, const Vector3& eye, const Vector3& target, const Vector3& up) + { + angle /= T(2.0); + + T tangent = angle.GetTan(); + T nearH = zNear * tangent; + T nearW = nearH * ratio; + T farH = zFar * tangent; + T farW = farH * ratio; + + Vector3 f = Vector3::Normalize(target - eye); + Vector3 u(up.GetNormal()); + Vector3 s = Vector3::Normalize(f.CrossProduct(u)); + u = s.CrossProduct(f); + + Vector3 nc = eye + f * zNear; + Vector3 fc = eye + f * zFar; + + // Computing the frustum + std::array, BoxCornerCount> corners; + corners[UnderlyingCast(BoxCorner::FarLeftBottom)] = fc - u * farH - s * farW; + corners[UnderlyingCast(BoxCorner::FarLeftTop)] = fc + u * farH - s * farW; + corners[UnderlyingCast(BoxCorner::FarRightTop)] = fc + u * farH + s * farW; + corners[UnderlyingCast(BoxCorner::FarRightBottom)] = fc - u * farH + s * farW; + + corners[UnderlyingCast(BoxCorner::NearLeftBottom)] = nc - u * nearH - s * nearW; + corners[UnderlyingCast(BoxCorner::NearLeftTop)] = nc + u * nearH - s * nearW; + corners[UnderlyingCast(BoxCorner::NearRightTop)] = nc + u * nearH + s * nearW; + corners[UnderlyingCast(BoxCorner::NearRightBottom)] = nc - u * nearH + s * nearW; + + // Construction of frustum's planes + std::array, FrustumPlaneCount> planes; + planes[UnderlyingCast(FrustumPlane::Bottom)] = Plane(corners[UnderlyingCast(BoxCorner::NearLeftBottom)], corners[UnderlyingCast(BoxCorner::NearRightBottom)], corners[UnderlyingCast(BoxCorner::FarRightBottom)]); + planes[UnderlyingCast(FrustumPlane::Far)] = Plane(corners[UnderlyingCast(BoxCorner::FarRightTop)], corners[UnderlyingCast(BoxCorner::FarLeftTop)], corners[UnderlyingCast(BoxCorner::FarLeftBottom)]); + planes[UnderlyingCast(FrustumPlane::Left)] = Plane(corners[UnderlyingCast(BoxCorner::NearLeftTop)], corners[UnderlyingCast(BoxCorner::NearLeftBottom)], corners[UnderlyingCast(BoxCorner::FarLeftBottom)]); + planes[UnderlyingCast(FrustumPlane::Near)] = Plane(corners[UnderlyingCast(BoxCorner::NearLeftTop)], corners[UnderlyingCast(BoxCorner::NearRightTop)], corners[UnderlyingCast(BoxCorner::NearRightBottom)]); + planes[UnderlyingCast(FrustumPlane::Right)] = Plane(corners[UnderlyingCast(BoxCorner::NearRightBottom)], corners[UnderlyingCast(BoxCorner::NearRightTop)], corners[UnderlyingCast(BoxCorner::FarRightBottom)]); + planes[UnderlyingCast(FrustumPlane::Top)] = Plane(corners[UnderlyingCast(BoxCorner::NearRightTop)], corners[UnderlyingCast(BoxCorner::NearLeftTop)], corners[UnderlyingCast(BoxCorner::FarLeftTop)]); + + return Frustum(planes); + } + + /*! + * \brief Constructs the frustum from a Matrix4 + * \return A reference to this frustum which is the build up of projective matrix + * + * \param viewProjMatrix Matrix which represents the transformation of the frustum + */ + template + Frustum Frustum::Extract(const Matrix4& viewProjMatrix) + { + // http://www.crownandcutlass.com/features/technicaldetails/frustum.html + T plane[4]; + T invLength; + + std::array, FrustumPlaneCount> planes; + + // 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]; + + // 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[UnderlyingCast(FrustumPlane::Right)] = Plane(plane); + + // 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]; + + // 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[UnderlyingCast(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[UnderlyingCast(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[UnderlyingCast(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[UnderlyingCast(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[UnderlyingCast(FrustumPlane::Near)] = Plane(plane); + + return Frustum(planes); + } + /*! * \brief Serializes a Frustum * \return true if successfully serialized @@ -661,12 +534,6 @@ namespace Nz template bool Serialize(SerializationContext& context, const Frustum& frustum, TypeTag>) { - for (unsigned int i = 0; i < BoxCornerCount; ++i) - { - if (!Serialize(context, frustum.m_corners[i])) - return false; - } - for (unsigned int i = 0; i < FrustumPlaneCount; ++i) { if (!Serialize(context, frustum.m_planes[i])) @@ -686,12 +553,6 @@ namespace Nz template bool Unserialize(SerializationContext& context, Frustum* frustum, TypeTag>) { - for (unsigned int i = 0; i < BoxCornerCount; ++i) - { - if (!Unserialize(context, &frustum->m_corners[i])) - return false; - } - for (unsigned int i = 0; i < FrustumPlaneCount; ++i) { if (!Unserialize(context, &frustum->m_planes[i])) diff --git a/src/Nazara/Graphics/ForwardFramePipeline.cpp b/src/Nazara/Graphics/ForwardFramePipeline.cpp index f60c6aef8..14023c3cb 100644 --- a/src/Nazara/Graphics/ForwardFramePipeline.cpp +++ b/src/Nazara/Graphics/ForwardFramePipeline.cpp @@ -174,8 +174,7 @@ namespace Nz // Frustum culling const Matrix4f& viewProjMatrix = viewer->GetViewerInstance().GetViewProjMatrix(); - Frustumf frustum; - frustum.Extract(viewProjMatrix); + Frustumf frustum = Frustumf::Extract(viewProjMatrix); std::size_t visibilityHash = 5U; diff --git a/tests/Engine/Core/SerializationTest.cpp b/tests/Engine/Core/SerializationTest.cpp index 5e86c575d..fa7c80f27 100644 --- a/tests/Engine/Core/SerializationTest.cpp +++ b/tests/Engine/Core/SerializationTest.cpp @@ -92,12 +92,12 @@ SCENARIO("Serialization", "[CORE][SERIALIZATION]") Nz::Frustumf copy(frustum); REQUIRE(Serialize(context, frustum)); frustum.Build(50, 40, 20, 100, Nz::Vector3f::UnitX(), Nz::Vector3f::UnitZ()); - for (unsigned int i = 0; i < Nz::BoxCornerCount; ++i) - REQUIRE(frustum.GetCorner(static_cast(i)) != copy.GetCorner(static_cast(i))); + for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i) + REQUIRE(frustum.GetPlane(static_cast(i)) != copy.GetPlane(static_cast(i))); context.stream->SetCursorPos(0); REQUIRE(Unserialize(context, &frustum)); - for (unsigned int i = 0; i < Nz::BoxCornerCount; ++i) - REQUIRE(frustum.GetCorner(static_cast(i)) == copy.GetCorner(static_cast(i))); + for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i) + REQUIRE(frustum.GetPlane(static_cast(i)) == copy.GetPlane(static_cast(i))); } THEN("Matrix4")