DYT/Tool/OpenSceneGraph-3.6.5/include/Imath/ImathFrustum.h

976 lines
30 KiB
C
Raw Permalink Normal View History

2024-12-24 23:49:36 +00:00
//
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenEXR Project.
//
//
// A viewing frustum class
//
#ifndef INCLUDED_IMATHFRUSTUM_H
#define INCLUDED_IMATHFRUSTUM_H
#include "ImathExport.h"
#include "ImathNamespace.h"
#include "ImathFun.h"
#include "ImathLine.h"
#include "ImathMatrix.h"
#include "ImathPlane.h"
#include "ImathVec.h"
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
///
/// Template class `Frustum<T>`
///
/// The frustum is always located with the eye point at the origin
/// facing down -Z. This makes the Frustum class compatable with
/// OpenGL (or anything that assumes a camera looks down -Z, hence
/// with a right-handed coordinate system) but not with RenderMan
/// which assumes the camera looks down +Z. Additional functions are
/// provided for conversion from and from various camera coordinate
/// spaces.
///
/// nearPlane/farPlane: near/far are keywords used by Microsoft's
/// compiler, so we use nearPlane/farPlane instead to avoid
/// issues.
template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Frustum
{
public:
/// @{
/// @name Constructors and Assignment
///
/// Initialize with default values:
/// near=0.1, far=1000.0, left=-1.0, right=1.0, top=1.0, bottom=-1.0, ortho=false
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum() IMATH_NOEXCEPT;
/// Copy constructor
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (const Frustum&) IMATH_NOEXCEPT;
/// Initialize to specific values
IMATH_HOSTDEVICE IMATH_CONSTEXPR14
Frustum (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
/// Initialize with fov and aspect
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
/// Destructor
virtual ~Frustum() IMATH_NOEXCEPT;
/// Component-wise assignment
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Frustum& operator= (const Frustum&) IMATH_NOEXCEPT;
/// @}
/// @{
/// @name Comparison
/// Equality
IMATH_HOSTDEVICE constexpr bool operator== (const Frustum<T>& src) const IMATH_NOEXCEPT;
/// Inequality
IMATH_HOSTDEVICE constexpr bool operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT;
/// @}
/// @{
/// @name Query
/// Return true if the frustum is orthographic, false if perspective
IMATH_HOSTDEVICE constexpr bool orthographic() const IMATH_NOEXCEPT { return _orthographic; }
/// Return the near clipping plane
IMATH_HOSTDEVICE constexpr T nearPlane() const IMATH_NOEXCEPT { return _nearPlane; }
/// Return the near clipping plane
IMATH_HOSTDEVICE constexpr T hither() const IMATH_NOEXCEPT { return _nearPlane; }
/// Return the far clipping plane
IMATH_HOSTDEVICE constexpr T farPlane() const IMATH_NOEXCEPT { return _farPlane; }
/// Return the far clipping plane
IMATH_HOSTDEVICE constexpr T yon() const IMATH_NOEXCEPT { return _farPlane; }
/// Return the left of the frustum
IMATH_HOSTDEVICE constexpr T left() const IMATH_NOEXCEPT { return _left; }
/// Return the right of the frustum
IMATH_HOSTDEVICE constexpr T right() const IMATH_NOEXCEPT { return _right; }
/// Return the bottom of the frustum
IMATH_HOSTDEVICE constexpr T bottom() const IMATH_NOEXCEPT { return _bottom; }
/// Return the top of the frustum
IMATH_HOSTDEVICE constexpr T top() const IMATH_NOEXCEPT { return _top; }
/// Return the field of view in X
IMATH_HOSTDEVICE constexpr T fovx() const IMATH_NOEXCEPT;
/// Return the field of view in Y
IMATH_HOSTDEVICE constexpr T fovy() const IMATH_NOEXCEPT;
/// Return the aspect ratio
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T aspect() const IMATH_NOEXCEPT;
/// Return the aspect ratio. Throw an exception if the aspect
/// ratio is undefined.
IMATH_CONSTEXPR14 T aspectExc() const;
/// Return the project matrix that the frustum defines
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44<T> projectionMatrix() const IMATH_NOEXCEPT;
/// Return the project matrix that the frustum defines. Throw an
/// exception if the frustum is degenerate.
IMATH_CONSTEXPR14 Matrix44<T> projectionMatrixExc() const;
/// Return true if the frustum is degenerate.
IMATH_HOSTDEVICE constexpr bool degenerate() const IMATH_NOEXCEPT;
/// @}
/// @{
/// @name Set Value
/// Set functions change the entire state of the Frustum
IMATH_HOSTDEVICE void
set (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
/// Set functions change the entire state of the Frustum using
/// field of view and aspect ratio
IMATH_HOSTDEVICE void set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
/// Set functions change the entire state of the Frustum using
/// field of view and aspect ratio. Throw an exception if `fovx`
/// and/or `fovy` are invalid.
void setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect);
/// Set the near and far clipping planes
IMATH_HOSTDEVICE void modifyNearAndFar (T nearPlane, T farPlane) IMATH_NOEXCEPT;
/// Set the ortographic state
IMATH_HOSTDEVICE void setOrthographic (bool) IMATH_NOEXCEPT;
/// Set the planes in p to be the six bounding planes of the frustum, in
/// the following order: top, right, bottom, left, near, far.
/// Note that the planes have normals that point out of the frustum.
IMATH_HOSTDEVICE void planes (Plane3<T> p[6]) const IMATH_NOEXCEPT;
/// Set the planes in p to be the six bounding planes of the
/// frustum, in the following order: top, right, bottom, left,
/// near, far. Note that the planes have normals that point out
/// of the frustum. Apply the given matrix to transform the
/// frustum before setting the planes.
IMATH_HOSTDEVICE void planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT;
/// Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
/// and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
/// Frustum whose near clipping-plane window is that rectangle in local
/// space.
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 IMATH_HOSTDEVICE Frustum<T>
window (T left, T right, T top, T bottom) const IMATH_NOEXCEPT;
/// @}
/// @{
/// @name Utility Methods
/// Project a point in screen spaced to 3d ray
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Line3<T> projectScreenToRay (const Vec2<T>&) const IMATH_NOEXCEPT;
/// Project a 3D point into screen coordinates
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T> projectPointToScreen (const Vec3<T>&) const IMATH_NOEXCEPT;
/// Project a 3D point into screen coordinates. Throw an
/// exception if the point cannot be projected.
IMATH_CONSTEXPR14 Vec2<T> projectPointToScreenExc (const Vec3<T>&) const;
/// Map a z value to its depth in the frustum.
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T ZToDepth (long zval,
long min,
long max) const IMATH_NOEXCEPT;
/// Map a z value to its depth in the frustum.
IMATH_CONSTEXPR14 T ZToDepthExc (long zval, long min, long max) const;
/// Map a normalized z value to its depth in the frustum.
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T normalizedZToDepth (T zval) const IMATH_NOEXCEPT;
/// Map a normalized z value to its depth in the frustum. Throw an
/// exception on error.
IMATH_CONSTEXPR14 T normalizedZToDepthExc (T zval) const;
/// Map depth to z value.
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 long
DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT;
/// Map depth to z value. Throw an exception on error.
IMATH_CONSTEXPR14 long DepthToZExc (T depth, long zmin, long zmax) const;
/// Compute worldRadius
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
/// Compute worldRadius. Throw an exception on error.
IMATH_CONSTEXPR14 T worldRadiusExc (const Vec3<T>& p, T radius) const;
/// Compute screen radius
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
/// Compute screen radius. Throw an exception on error.
IMATH_CONSTEXPR14 T screenRadiusExc (const Vec3<T>& p, T radius) const;
/// @}
protected:
/// Map point from screen space to local space
IMATH_HOSTDEVICE constexpr Vec2<T> screenToLocal (const Vec2<T>&) const IMATH_NOEXCEPT;
/// Map point from local space to screen space
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T>
localToScreen (const Vec2<T>&) const IMATH_NOEXCEPT;
/// Map point from local space to screen space. Throw an exception
/// on error.
IMATH_CONSTEXPR14 Vec2<T> localToScreenExc (const Vec2<T>&) const;
protected:
/// @cond Doxygen_Suppress
T _nearPlane;
T _farPlane;
T _left;
T _right;
T _top;
T _bottom;
bool _orthographic;
/// @endcond
};
template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum() IMATH_NOEXCEPT
{
set (T (0.1), T (1000.0), T (-1.0), T (1.0), T (1.0), T (-1.0), false);
}
template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (const Frustum& f) IMATH_NOEXCEPT
{
*this = f;
}
template <class T>
IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
{
set (n, f, l, r, t, b, o);
}
template <class T>
IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
{
set (nearPlane, farPlane, fovx, fovy, aspect);
}
template <class T> Frustum<T>::~Frustum() IMATH_NOEXCEPT
{}
template <class T>
IMATH_CONSTEXPR14 inline const Frustum<T>&
Frustum<T>::operator= (const Frustum& f) IMATH_NOEXCEPT
{
_nearPlane = f._nearPlane;
_farPlane = f._farPlane;
_left = f._left;
_right = f._right;
_top = f._top;
_bottom = f._bottom;
_orthographic = f._orthographic;
return *this;
}
template <class T>
constexpr inline bool
Frustum<T>::operator== (const Frustum<T>& src) const IMATH_NOEXCEPT
{
return _nearPlane == src._nearPlane && _farPlane == src._farPlane && _left == src._left &&
_right == src._right && _top == src._top && _bottom == src._bottom &&
_orthographic == src._orthographic;
}
template <class T>
constexpr inline bool
Frustum<T>::operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT
{
return !operator== (src);
}
template <class T>
inline void
Frustum<T>::set (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
{
_nearPlane = n;
_farPlane = f;
_left = l;
_right = r;
_bottom = b;
_top = t;
_orthographic = o;
}
template <class T>
inline void
Frustum<T>::modifyNearAndFar (T n, T f) IMATH_NOEXCEPT
{
if (_orthographic)
{
_nearPlane = n;
}
else
{
Line3<T> lowerLeft (Vec3<T> (0, 0, 0), Vec3<T> (_left, _bottom, -_nearPlane));
Line3<T> upperRight (Vec3<T> (0, 0, 0), Vec3<T> (_right, _top, -_nearPlane));
Plane3<T> nearPlane (Vec3<T> (0, 0, -1), n);
Vec3<T> ll = Vec3<T> (0, 0, 0);
Vec3<T> ur = Vec3<T> (0, 0, 0);
nearPlane.intersect (lowerLeft, ll);
nearPlane.intersect (upperRight, ur);
_left = ll.x;
_right = ur.x;
_top = ur.y;
_bottom = ll.y;
_nearPlane = n;
_farPlane = f;
}
_farPlane = f;
}
template <class T>
inline void
Frustum<T>::setOrthographic (bool ortho) IMATH_NOEXCEPT
{
_orthographic = ortho;
}
template <class T>
inline void
Frustum<T>::setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect)
{
if (fovx != T (0) && fovy != T (0))
throw std::domain_error ("fovx and fovy cannot both be non-zero.");
const T two = static_cast<T> (2);
if (fovx != T (0))
{
_right = nearPlane * std::tan (fovx / two);
_left = -_right;
_top = ((_right - _left) / aspect) / two;
_bottom = -_top;
}
else
{
_top = nearPlane * std::tan (fovy / two);
_bottom = -_top;
_right = (_top - _bottom) * aspect / two;
_left = -_right;
}
_nearPlane = nearPlane;
_farPlane = farPlane;
_orthographic = false;
}
template <class T>
inline void
Frustum<T>::set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
{
const T two = static_cast<T> (2);
if (fovx != T (0))
{
_right = nearPlane * std::tan (fovx / two);
_left = -_right;
_top = ((_right - _left) / aspect) / two;
_bottom = -_top;
}
else
{
_top = nearPlane * std::tan (fovy / two);
_bottom = -_top;
_right = (_top - _bottom) * aspect / two;
_left = -_right;
}
_nearPlane = nearPlane;
_farPlane = farPlane;
_orthographic = false;
}
template <class T>
constexpr inline T
Frustum<T>::fovx() const IMATH_NOEXCEPT
{
return std::atan2 (_right, _nearPlane) - std::atan2 (_left, _nearPlane);
}
template <class T>
constexpr inline T
Frustum<T>::fovy() const IMATH_NOEXCEPT
{
return std::atan2 (_top, _nearPlane) - std::atan2 (_bottom, _nearPlane);
}
template <class T>
IMATH_CONSTEXPR14 inline T
Frustum<T>::aspectExc() const
{
T rightMinusLeft = _right - _left;
T topMinusBottom = _top - _bottom;
if (abs (topMinusBottom) < T (1) && abs (rightMinusLeft) > std::numeric_limits<T>::max() * abs (topMinusBottom))
{
throw std::domain_error ("Bad viewing frustum: "
"aspect ratio cannot be computed.");
}
return rightMinusLeft / topMinusBottom;
}
template <class T>
IMATH_CONSTEXPR14 inline T
Frustum<T>::aspect() const IMATH_NOEXCEPT
{
T rightMinusLeft = _right - _left;
T topMinusBottom = _top - _bottom;
return rightMinusLeft / topMinusBottom;
}
template <class T>
IMATH_CONSTEXPR14 inline Matrix44<T>
Frustum<T>::projectionMatrixExc() const
{
T rightPlusLeft = _right + _left;
T rightMinusLeft = _right - _left;
T topPlusBottom = _top + _bottom;
T topMinusBottom = _top - _bottom;
T farPlusNear = _farPlane + _nearPlane;
T farMinusNear = _farPlane - _nearPlane;
if ((abs (rightMinusLeft) < T (1) &&
abs (rightPlusLeft) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
(abs (topMinusBottom) < T (1) &&
abs (topPlusBottom) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
(abs (farMinusNear) < 1 && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear)))
{
throw std::domain_error ("Bad viewing frustum: "
"projection matrix cannot be computed.");
}
if (_orthographic)
{
T tx = -rightPlusLeft / rightMinusLeft;
T ty = -topPlusBottom / topMinusBottom;
T tz = -farPlusNear / farMinusNear;
if ((abs (rightMinusLeft) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
(abs (topMinusBottom) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
(abs (farMinusNear) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (farMinusNear)))
{
throw std::domain_error ("Bad viewing frustum: "
"projection matrix cannot be computed.");
}
T A = T (2) / rightMinusLeft;
T B = T (2) / topMinusBottom;
T C = T (-2) / farMinusNear;
return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
}
else
{
T A = rightPlusLeft / rightMinusLeft;
T B = topPlusBottom / topMinusBottom;
T C = -farPlusNear / farMinusNear;
T farTimesNear = T (-2) * _farPlane * _nearPlane;
if (abs (farMinusNear) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
{
throw std::domain_error ("Bad viewing frustum: "
"projection matrix cannot be computed.");
}
T D = farTimesNear / farMinusNear;
T twoTimesNear = T (2) * _nearPlane;
if ((abs (rightMinusLeft) < T (1) &&
abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
(abs (topMinusBottom) < T (1) &&
abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (topMinusBottom)))
{
throw std::domain_error ("Bad viewing frustum: "
"projection matrix cannot be computed.");
}
T E = twoTimesNear / rightMinusLeft;
T F = twoTimesNear / topMinusBottom;
return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
}
}
template <class T>
IMATH_CONSTEXPR14 inline Matrix44<T>
Frustum<T>::projectionMatrix() const IMATH_NOEXCEPT
{
T rightPlusLeft = _right + _left;
T rightMinusLeft = _right - _left;
T topPlusBottom = _top + _bottom;
T topMinusBottom = _top - _bottom;
T farPlusNear = _farPlane + _nearPlane;
T farMinusNear = _farPlane - _nearPlane;
if (_orthographic)
{
T tx = -rightPlusLeft / rightMinusLeft;
T ty = -topPlusBottom / topMinusBottom;
T tz = -farPlusNear / farMinusNear;
T A = T (2) / rightMinusLeft;
T B = T (2) / topMinusBottom;
T C = T (-2) / farMinusNear;
return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
}
else
{
T A = rightPlusLeft / rightMinusLeft;
T B = topPlusBottom / topMinusBottom;
T C = -farPlusNear / farMinusNear;
T farTimesNear = T (-2) * _farPlane * _nearPlane;
T D = farTimesNear / farMinusNear;
T twoTimesNear = T (2) * _nearPlane;
T E = twoTimesNear / rightMinusLeft;
T F = twoTimesNear / topMinusBottom;
return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
}
}
template <class T>
constexpr inline bool
Frustum<T>::degenerate() const IMATH_NOEXCEPT
{
return (_nearPlane == _farPlane) || (_left == _right) || (_top == _bottom);
}
template <class T>
IMATH_CONSTEXPR14 inline Frustum<T>
Frustum<T>::window (T l, T r, T t, T b) const IMATH_NOEXCEPT
{
// move it to 0->1 space
Vec2<T> bl = screenToLocal (Vec2<T> (l, b));
Vec2<T> tr = screenToLocal (Vec2<T> (r, t));
return Frustum<T> (_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
}
template <class T>
constexpr inline Vec2<T>
Frustum<T>::screenToLocal (const Vec2<T>& s) const IMATH_NOEXCEPT
{
return Vec2<T> (_left + (_right - _left) * (1.f + s.x) / 2.f,
_bottom + (_top - _bottom) * (1.f + s.y) / 2.f);
}
template <class T>
IMATH_CONSTEXPR14 inline Vec2<T>
Frustum<T>::localToScreenExc (const Vec2<T>& p) const
{
T leftPlusRight = _left - T (2) * p.x + _right;
T leftMinusRight = _left - _right;
T bottomPlusTop = _bottom - T (2) * p.y + _top;
T bottomMinusTop = _bottom - _top;
if ((abs (leftMinusRight) < T (1) &&
abs (leftPlusRight) > std::numeric_limits<T>::max() * abs (leftMinusRight)) ||
(abs (bottomMinusTop) < T (1) &&
abs (bottomPlusTop) > std::numeric_limits<T>::max() * abs (bottomMinusTop)))
{
throw std::domain_error ("Bad viewing frustum: "
"local-to-screen transformation cannot be computed");
}
return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
}
template <class T>
IMATH_CONSTEXPR14 inline Vec2<T>
Frustum<T>::localToScreen (const Vec2<T>& p) const IMATH_NOEXCEPT
{
T leftPlusRight = _left - T (2) * p.x + _right;
T leftMinusRight = _left - _right;
T bottomPlusTop = _bottom - T (2) * p.y + _top;
T bottomMinusTop = _bottom - _top;
return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
}
template <class T>
IMATH_CONSTEXPR14 inline Line3<T>
Frustum<T>::projectScreenToRay (const Vec2<T>& p) const IMATH_NOEXCEPT
{
Vec2<T> point = screenToLocal (p);
if (orthographic())
return Line3<T> (Vec3<T> (point.x, point.y, 0.0), Vec3<T> (point.x, point.y, -1.0));
else
return Line3<T> (Vec3<T> (0, 0, 0), Vec3<T> (point.x, point.y, -_nearPlane));
}
template <class T>
IMATH_CONSTEXPR14 Vec2<T>
Frustum<T>::projectPointToScreenExc (const Vec3<T>& point) const
{
if (orthographic() || point.z == T (0))
return localToScreenExc (Vec2<T> (point.x, point.y));
else
return localToScreenExc (
Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
}
template <class T>
IMATH_CONSTEXPR14 Vec2<T>
Frustum<T>::projectPointToScreen (const Vec3<T>& point) const IMATH_NOEXCEPT
{
if (orthographic() || point.z == T (0))
return localToScreen (Vec2<T> (point.x, point.y));
else
return localToScreen (
Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::ZToDepthExc (long zval, long zmin, long zmax) const
{
int zdiff = zmax - zmin;
if (zdiff == 0)
{
throw std::domain_error ("Bad call to Frustum::ZToDepth: zmax == zmin");
}
if (zval > zmax + 1)
zval -= zdiff;
T fzval = (T (zval) - T (zmin)) / T (zdiff);
return normalizedZToDepthExc (fzval);
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::ZToDepth (long zval, long zmin, long zmax) const IMATH_NOEXCEPT
{
int zdiff = zmax - zmin;
if (zval > zmax + 1)
zval -= zdiff;
T fzval = (T (zval) - T (zmin)) / T (zdiff);
return normalizedZToDepth (fzval);
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::normalizedZToDepthExc (T zval) const
{
T Zp = zval * T (2) - T (1);
if (_orthographic)
{
return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
}
else
{
T farTimesNear = 2 * _farPlane * _nearPlane;
T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
if (abs (farMinusNear) < 1 && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
{
throw std::domain_error ("Frustum::normalizedZToDepth cannot be computed: "
"near and far clipping planes of the viewing frustum "
"may be too close to each other");
}
return farTimesNear / farMinusNear;
}
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::normalizedZToDepth (T zval) const IMATH_NOEXCEPT
{
T Zp = zval * T (2) - T (1);
if (_orthographic)
{
return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
}
else
{
T farTimesNear = 2 * _farPlane * _nearPlane;
T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
return farTimesNear / farMinusNear;
}
}
template <class T>
IMATH_CONSTEXPR14 long
Frustum<T>::DepthToZExc (T depth, long zmin, long zmax) const
{
long zdiff = zmax - zmin;
T farMinusNear = _farPlane - _nearPlane;
if (_orthographic)
{
T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
{
throw std::domain_error ("Bad viewing frustum: "
"near and far clipping planes "
"are too close to each other");
}
T Zp = -farPlusNear / farMinusNear;
return long (0.5 * (Zp + 1) * zdiff) + zmin;
}
else
{
// Perspective
T farTimesNear = T (2) * _farPlane * _nearPlane;
if (abs (depth) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (depth))
{
throw std::domain_error ("Bad call to DepthToZ function: "
"value of `depth' is too small");
}
T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
{
throw std::domain_error ("Bad viewing frustum: "
"near and far clipping planes "
"are too close to each other");
}
T Zp = farPlusNear / farMinusNear;
return long (0.5 * (Zp + 1) * zdiff) + zmin;
}
}
template <class T>
IMATH_CONSTEXPR14 long
Frustum<T>::DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT
{
long zdiff = zmax - zmin;
T farMinusNear = _farPlane - _nearPlane;
if (_orthographic)
{
T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
T Zp = -farPlusNear / farMinusNear;
return long (0.5 * (Zp + 1) * zdiff) + zmin;
}
else
{
// Perspective
T farTimesNear = T (2) * _farPlane * _nearPlane;
T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
T Zp = farPlusNear / farMinusNear;
return long (0.5 * (Zp + 1) * zdiff) + zmin;
}
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::screenRadiusExc (const Vec3<T>& p, T radius) const
{
// Derivation:
// Consider X-Z plane.
// X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
// Let q be p + (radius, 0, 0).
// X coord of projection of q = xq = (p.x - radius) * (-_nearPlane / p.z)
// X coord of projection of segment from p to q = r = xp - xq
// = radius * (-_nearPlane / p.z)
// A similar analysis holds in the Y-Z plane.
// So r is the quantity we want to return.
if (abs (p.z) > T (1) || abs (-_nearPlane) < std::numeric_limits<T>::max() * abs (p.z))
{
return radius * (-_nearPlane / p.z);
}
else
{
throw std::domain_error ("Bad call to Frustum::screenRadius: "
"magnitude of `p' is too small");
}
return radius * (-_nearPlane / p.z);
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
{
// Derivation:
// Consider X-Z plane.
// X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
// Let q be p + (radius, 0, 0).
// X coord of projection of q = xq = (p.x - radius) * (-_nearPlane / p.z)
// X coord of projection of segment from p to q = r = xp - xq
// = radius * (-_nearPlane / p.z)
// A similar analysis holds in the Y-Z plane.
// So r is the quantity we want to return.
return radius * (-_nearPlane / p.z);
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::worldRadiusExc (const Vec3<T>& p, T radius) const
{
if (abs (-_nearPlane) > T (1) || abs (p.z) < std::numeric_limits<T>::max() * abs (-_nearPlane))
{
return radius * (p.z / -_nearPlane);
}
else
{
throw std::domain_error ("Bad viewing frustum: "
"near clipping plane is too close to zero");
}
}
template <class T>
IMATH_CONSTEXPR14 T
Frustum<T>::worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
{
return radius * (p.z / -_nearPlane);
}
template <class T>
void
Frustum<T>::planes (Plane3<T> p[6]) const IMATH_NOEXCEPT
{
//
// Plane order: Top, Right, Bottom, Left, Near, Far.
// Normals point outwards.
//
if (!_orthographic)
{
Vec3<T> a (_left, _bottom, -_nearPlane);
Vec3<T> b (_left, _top, -_nearPlane);
Vec3<T> c (_right, _top, -_nearPlane);
Vec3<T> d (_right, _bottom, -_nearPlane);
Vec3<T> o (0, 0, 0);
p[0].set (o, c, b);
p[1].set (o, d, c);
p[2].set (o, a, d);
p[3].set (o, b, a);
}
else
{
p[0].set (Vec3<T> (0, 1, 0), _top);
p[1].set (Vec3<T> (1, 0, 0), _right);
p[2].set (Vec3<T> (0, -1, 0), -_bottom);
p[3].set (Vec3<T> (-1, 0, 0), -_left);
}
p[4].set (Vec3<T> (0, 0, 1), -_nearPlane);
p[5].set (Vec3<T> (0, 0, -1), _farPlane);
}
template <class T>
void
Frustum<T>::planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT
{
//
// Plane order: Top, Right, Bottom, Left, Near, Far.
// Normals point outwards.
//
Vec3<T> a = Vec3<T> (_left, _bottom, -_nearPlane) * M;
Vec3<T> b = Vec3<T> (_left, _top, -_nearPlane) * M;
Vec3<T> c = Vec3<T> (_right, _top, -_nearPlane) * M;
Vec3<T> d = Vec3<T> (_right, _bottom, -_nearPlane) * M;
if (!_orthographic)
{
double s = _farPlane / double (_nearPlane);
T farLeft = (T) (s * _left);
T farRight = (T) (s * _right);
T farTop = (T) (s * _top);
T farBottom = (T) (s * _bottom);
Vec3<T> e = Vec3<T> (farLeft, farBottom, -_farPlane) * M;
Vec3<T> f = Vec3<T> (farLeft, farTop, -_farPlane) * M;
Vec3<T> g = Vec3<T> (farRight, farTop, -_farPlane) * M;
Vec3<T> o = Vec3<T> (0, 0, 0) * M;
p[0].set (o, c, b);
p[1].set (o, d, c);
p[2].set (o, a, d);
p[3].set (o, b, a);
p[4].set (a, d, c);
p[5].set (e, f, g);
}
else
{
Vec3<T> e = Vec3<T> (_left, _bottom, -_farPlane) * M;
Vec3<T> f = Vec3<T> (_left, _top, -_farPlane) * M;
Vec3<T> g = Vec3<T> (_right, _top, -_farPlane) * M;
Vec3<T> h = Vec3<T> (_right, _bottom, -_farPlane) * M;
p[0].set (c, g, f);
p[1].set (d, h, g);
p[2].set (a, e, h);
p[3].set (b, f, e);
p[4].set (a, d, c);
p[5].set (e, f, g);
}
}
/// Frustum of type float
typedef Frustum<float> Frustumf;
/// Frustum of type double
typedef Frustum<double> Frustumd;
IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
#if defined _WIN32 || defined _WIN64
# ifdef _redef_near
# define near
# endif
# ifdef _redef_far
# define far
# endif
#endif
#endif // INCLUDED_IMATHFRUSTUM_H