Math: Rework Frustum class
This commit is contained in:
parent
b2ae2261e4
commit
2b9d8becea
|
|
@ -15,6 +15,7 @@
|
|||
#include <Nazara/Math/Plane.hpp>
|
||||
#include <Nazara/Math/Sphere.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -26,23 +27,18 @@ namespace Nz
|
|||
{
|
||||
public:
|
||||
Frustum() = default;
|
||||
explicit Frustum(const std::array<Plane<T>, FrustumPlaneCount>& planes);
|
||||
template<typename U> explicit Frustum(const Frustum<U>& frustum);
|
||||
Frustum(const Frustum& frustum) = default;
|
||||
~Frustum() = default;
|
||||
|
||||
Frustum& Build(RadianAngle<T> angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& up = Vector3<T>::Up());
|
||||
|
||||
bool Contains(const BoundingVolume<T>& volume) const;
|
||||
bool Contains(const Box<T>& box) const;
|
||||
bool Contains(const OrientedBox<T>& orientedBox) const;
|
||||
bool Contains(const Sphere<T>& sphere) const;
|
||||
bool Contains(const Vector3<T>& point) const;
|
||||
bool Contains(const Vector3<T>* points, unsigned int pointCount) const;
|
||||
bool Contains(const Vector3<T>* points, std::size_t pointCount) const;
|
||||
|
||||
Frustum& Extract(const Matrix4<T>& clipMatrix);
|
||||
Frustum& Extract(const Matrix4<T>& view, const Matrix4<T>& projection);
|
||||
|
||||
const Vector3<T>& GetCorner(BoxCorner corner) const;
|
||||
const Plane<T>& GetPlane(FrustumPlane plane) const;
|
||||
|
||||
IntersectionSide Intersect(const BoundingVolume<T>& volume) const;
|
||||
|
|
@ -51,12 +47,15 @@ namespace Nz
|
|||
IntersectionSide Intersect(const Sphere<T>& sphere) const;
|
||||
IntersectionSide Intersect(const Vector3<T>* points, std::size_t pointCount) const;
|
||||
|
||||
Frustum& operator=(const Frustum& other) = default;
|
||||
|
||||
template<typename U> Frustum& Set(const Frustum<U>& frustum);
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
Frustum& operator=(const Frustum& other) = default;
|
||||
|
||||
static Frustum Build(RadianAngle<T> angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& up = Vector3<T>::Up());
|
||||
static Frustum Extract(const Matrix4<T>& viewProjMatrix);
|
||||
|
||||
template<typename U>
|
||||
friend bool Serialize(SerializationContext& context, const Frustum<U>& frustum, TypeTag<Frustum<U>>);
|
||||
|
||||
|
|
@ -64,8 +63,7 @@ namespace Nz
|
|||
friend bool Unserialize(SerializationContext& context, Frustum<U>* frustum, TypeTag<Frustum<U>>);
|
||||
|
||||
private:
|
||||
Vector3<T> m_corners[BoxCornerCount];
|
||||
Plane<T> m_planes[FrustumPlaneCount];
|
||||
std::array<Plane<T>, FrustumPlaneCount> m_planes;
|
||||
};
|
||||
|
||||
using Frustumd = Frustum<double>;
|
||||
|
|
|
|||
|
|
@ -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<typename T>
|
||||
Frustum<T>::Frustum(const std::array<Plane<T>, 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<typename T>
|
||||
template<typename U>
|
||||
Frustum<T>::Frustum(const Frustum<U>& 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<typename T>
|
||||
Frustum<T>& Frustum<T>::Build(RadianAngle<T> angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& 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<T> f = Vector3<T>::Normalize(target - eye);
|
||||
Vector3<T> u(up.GetNormal());
|
||||
Vector3<T> s = Vector3<T>::Normalize(f.CrossProduct(u));
|
||||
u = s.CrossProduct(f);
|
||||
|
||||
Vector3<T> nc = eye + f * zNear;
|
||||
Vector3<T> 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<typename T>
|
||||
bool Frustum<T>::Contains(const BoundingVolume<T>& volume) const
|
||||
{
|
||||
|
|
@ -143,7 +100,6 @@ namespace Nz
|
|||
*
|
||||
* \param box Box to check
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
bool Frustum<T>::Contains(const Box<T>& box) const
|
||||
{
|
||||
|
|
@ -217,11 +173,11 @@ namespace Nz
|
|||
*/
|
||||
|
||||
template<typename T>
|
||||
bool Frustum<T>::Contains(const Vector3<T>* points, unsigned int pointCount) const
|
||||
bool Frustum<T>::Contains(const Vector3<T>* 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<typename T>
|
||||
Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& 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<T> invClipMatrix;
|
||||
if (clipMatrix.GetInverse(&invClipMatrix))
|
||||
{
|
||||
Vector4<T> 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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<typename T>
|
||||
Frustum<T>& Frustum<T>::Extract(const Matrix4<T>& view, const Matrix4<T>& projection)
|
||||
{
|
||||
return Extract(Matrix4<T>::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<typename T>
|
||||
const Vector3<T>& Frustum<T>::GetCorner(BoxCorner corner) const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (UnderlyingCast(corner) > BoxCornerCount)
|
||||
{
|
||||
NazaraError("Corner not handled (0x" + NumberToString(UnderlyingCast(corner), 16) + ')');
|
||||
|
||||
static Vector3<T> 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<typename T>
|
||||
const Plane<T>& Frustum<T>::GetPlane(FrustumPlane plane) const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (UnderlyingCast(plane) > FrustumPlaneCount)
|
||||
{
|
||||
NazaraError("Frustum plane not handled (0x" + NumberToString(UnderlyingCast(plane), 16) + ')');
|
||||
|
||||
static Plane<T> 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<typename T>
|
||||
template<typename U>
|
||||
Frustum<T>& Frustum<T>::Set(const Frustum<U>& 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<typename T>
|
||||
std::string Frustum<T>::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<typename T>
|
||||
Frustum<T> Frustum<T>::Build(RadianAngle<T> angle, T ratio, T zNear, T zFar, const Vector3<T>& eye, const Vector3<T>& target, const Vector3<T>& 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<T> f = Vector3<T>::Normalize(target - eye);
|
||||
Vector3<T> u(up.GetNormal());
|
||||
Vector3<T> s = Vector3<T>::Normalize(f.CrossProduct(u));
|
||||
u = s.CrossProduct(f);
|
||||
|
||||
Vector3<T> nc = eye + f * zNear;
|
||||
Vector3<T> fc = eye + f * zFar;
|
||||
|
||||
// Computing the frustum
|
||||
std::array<Vector3<T>, 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<Plane<T>, 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<typename T>
|
||||
Frustum<T> Frustum<T>::Extract(const Matrix4<T>& viewProjMatrix)
|
||||
{
|
||||
// http://www.crownandcutlass.com/features/technicaldetails/frustum.html
|
||||
T plane[4];
|
||||
T invLength;
|
||||
|
||||
std::array<Plane<T>, 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<typename T>
|
||||
bool Serialize(SerializationContext& context, const Frustum<T>& frustum, TypeTag<Frustum<T>>)
|
||||
{
|
||||
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<typename T>
|
||||
bool Unserialize(SerializationContext& context, Frustum<T>* frustum, TypeTag<Frustum<T>>)
|
||||
{
|
||||
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]))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Nz::BoxCorner>(i)) != copy.GetCorner(static_cast<Nz::BoxCorner>(i)));
|
||||
for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i)
|
||||
REQUIRE(frustum.GetPlane(static_cast<Nz::FrustumPlane>(i)) != copy.GetPlane(static_cast<Nz::FrustumPlane>(i)));
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &frustum));
|
||||
for (unsigned int i = 0; i < Nz::BoxCornerCount; ++i)
|
||||
REQUIRE(frustum.GetCorner(static_cast<Nz::BoxCorner>(i)) == copy.GetCorner(static_cast<Nz::BoxCorner>(i)));
|
||||
for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i)
|
||||
REQUIRE(frustum.GetPlane(static_cast<Nz::FrustumPlane>(i)) == copy.GetPlane(static_cast<Nz::FrustumPlane>(i)));
|
||||
}
|
||||
|
||||
THEN("Matrix4")
|
||||
|
|
|
|||
Loading…
Reference in New Issue