| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975 |
- //
- // 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
|