ImathFrustum.h 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright Contributors to the OpenEXR Project.
  4. //
  5. //
  6. // A viewing frustum class
  7. //
  8. #ifndef INCLUDED_IMATHFRUSTUM_H
  9. #define INCLUDED_IMATHFRUSTUM_H
  10. #include "ImathExport.h"
  11. #include "ImathNamespace.h"
  12. #include "ImathFun.h"
  13. #include "ImathLine.h"
  14. #include "ImathMatrix.h"
  15. #include "ImathPlane.h"
  16. #include "ImathVec.h"
  17. IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
  18. ///
  19. /// Template class `Frustum<T>`
  20. ///
  21. /// The frustum is always located with the eye point at the origin
  22. /// facing down -Z. This makes the Frustum class compatable with
  23. /// OpenGL (or anything that assumes a camera looks down -Z, hence
  24. /// with a right-handed coordinate system) but not with RenderMan
  25. /// which assumes the camera looks down +Z. Additional functions are
  26. /// provided for conversion from and from various camera coordinate
  27. /// spaces.
  28. ///
  29. /// nearPlane/farPlane: near/far are keywords used by Microsoft's
  30. /// compiler, so we use nearPlane/farPlane instead to avoid
  31. /// issues.
  32. template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Frustum
  33. {
  34. public:
  35. /// @{
  36. /// @name Constructors and Assignment
  37. ///
  38. /// Initialize with default values:
  39. /// near=0.1, far=1000.0, left=-1.0, right=1.0, top=1.0, bottom=-1.0, ortho=false
  40. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum() IMATH_NOEXCEPT;
  41. /// Copy constructor
  42. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (const Frustum&) IMATH_NOEXCEPT;
  43. /// Initialize to specific values
  44. IMATH_HOSTDEVICE IMATH_CONSTEXPR14
  45. Frustum (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
  46. /// Initialize with fov and aspect
  47. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
  48. /// Destructor
  49. virtual ~Frustum() IMATH_NOEXCEPT;
  50. /// Component-wise assignment
  51. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Frustum& operator= (const Frustum&) IMATH_NOEXCEPT;
  52. /// @}
  53. /// @{
  54. /// @name Comparison
  55. /// Equality
  56. IMATH_HOSTDEVICE constexpr bool operator== (const Frustum<T>& src) const IMATH_NOEXCEPT;
  57. /// Inequality
  58. IMATH_HOSTDEVICE constexpr bool operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT;
  59. /// @}
  60. /// @{
  61. /// @name Query
  62. /// Return true if the frustum is orthographic, false if perspective
  63. IMATH_HOSTDEVICE constexpr bool orthographic() const IMATH_NOEXCEPT { return _orthographic; }
  64. /// Return the near clipping plane
  65. IMATH_HOSTDEVICE constexpr T nearPlane() const IMATH_NOEXCEPT { return _nearPlane; }
  66. /// Return the near clipping plane
  67. IMATH_HOSTDEVICE constexpr T hither() const IMATH_NOEXCEPT { return _nearPlane; }
  68. /// Return the far clipping plane
  69. IMATH_HOSTDEVICE constexpr T farPlane() const IMATH_NOEXCEPT { return _farPlane; }
  70. /// Return the far clipping plane
  71. IMATH_HOSTDEVICE constexpr T yon() const IMATH_NOEXCEPT { return _farPlane; }
  72. /// Return the left of the frustum
  73. IMATH_HOSTDEVICE constexpr T left() const IMATH_NOEXCEPT { return _left; }
  74. /// Return the right of the frustum
  75. IMATH_HOSTDEVICE constexpr T right() const IMATH_NOEXCEPT { return _right; }
  76. /// Return the bottom of the frustum
  77. IMATH_HOSTDEVICE constexpr T bottom() const IMATH_NOEXCEPT { return _bottom; }
  78. /// Return the top of the frustum
  79. IMATH_HOSTDEVICE constexpr T top() const IMATH_NOEXCEPT { return _top; }
  80. /// Return the field of view in X
  81. IMATH_HOSTDEVICE constexpr T fovx() const IMATH_NOEXCEPT;
  82. /// Return the field of view in Y
  83. IMATH_HOSTDEVICE constexpr T fovy() const IMATH_NOEXCEPT;
  84. /// Return the aspect ratio
  85. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T aspect() const IMATH_NOEXCEPT;
  86. /// Return the aspect ratio. Throw an exception if the aspect
  87. /// ratio is undefined.
  88. IMATH_CONSTEXPR14 T aspectExc() const;
  89. /// Return the project matrix that the frustum defines
  90. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Matrix44<T> projectionMatrix() const IMATH_NOEXCEPT;
  91. /// Return the project matrix that the frustum defines. Throw an
  92. /// exception if the frustum is degenerate.
  93. IMATH_CONSTEXPR14 Matrix44<T> projectionMatrixExc() const;
  94. /// Return true if the frustum is degenerate.
  95. IMATH_HOSTDEVICE constexpr bool degenerate() const IMATH_NOEXCEPT;
  96. /// @}
  97. /// @{
  98. /// @name Set Value
  99. /// Set functions change the entire state of the Frustum
  100. IMATH_HOSTDEVICE void
  101. set (T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho = false) IMATH_NOEXCEPT;
  102. /// Set functions change the entire state of the Frustum using
  103. /// field of view and aspect ratio
  104. IMATH_HOSTDEVICE void set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT;
  105. /// Set functions change the entire state of the Frustum using
  106. /// field of view and aspect ratio. Throw an exception if `fovx`
  107. /// and/or `fovy` are invalid.
  108. void setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect);
  109. /// Set the near and far clipping planes
  110. IMATH_HOSTDEVICE void modifyNearAndFar (T nearPlane, T farPlane) IMATH_NOEXCEPT;
  111. /// Set the ortographic state
  112. IMATH_HOSTDEVICE void setOrthographic (bool) IMATH_NOEXCEPT;
  113. /// Set the planes in p to be the six bounding planes of the frustum, in
  114. /// the following order: top, right, bottom, left, near, far.
  115. /// Note that the planes have normals that point out of the frustum.
  116. IMATH_HOSTDEVICE void planes (Plane3<T> p[6]) const IMATH_NOEXCEPT;
  117. /// Set the planes in p to be the six bounding planes of the
  118. /// frustum, in the following order: top, right, bottom, left,
  119. /// near, far. Note that the planes have normals that point out
  120. /// of the frustum. Apply the given matrix to transform the
  121. /// frustum before setting the planes.
  122. IMATH_HOSTDEVICE void planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT;
  123. /// Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
  124. /// and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
  125. /// Frustum whose near clipping-plane window is that rectangle in local
  126. /// space.
  127. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 IMATH_HOSTDEVICE Frustum<T>
  128. window (T left, T right, T top, T bottom) const IMATH_NOEXCEPT;
  129. /// @}
  130. /// @{
  131. /// @name Utility Methods
  132. /// Project a point in screen spaced to 3d ray
  133. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Line3<T> projectScreenToRay (const Vec2<T>&) const IMATH_NOEXCEPT;
  134. /// Project a 3D point into screen coordinates
  135. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T> projectPointToScreen (const Vec3<T>&) const IMATH_NOEXCEPT;
  136. /// Project a 3D point into screen coordinates. Throw an
  137. /// exception if the point cannot be projected.
  138. IMATH_CONSTEXPR14 Vec2<T> projectPointToScreenExc (const Vec3<T>&) const;
  139. /// Map a z value to its depth in the frustum.
  140. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T ZToDepth (long zval,
  141. long min,
  142. long max) const IMATH_NOEXCEPT;
  143. /// Map a z value to its depth in the frustum.
  144. IMATH_CONSTEXPR14 T ZToDepthExc (long zval, long min, long max) const;
  145. /// Map a normalized z value to its depth in the frustum.
  146. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T normalizedZToDepth (T zval) const IMATH_NOEXCEPT;
  147. /// Map a normalized z value to its depth in the frustum. Throw an
  148. /// exception on error.
  149. IMATH_CONSTEXPR14 T normalizedZToDepthExc (T zval) const;
  150. /// Map depth to z value.
  151. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 long
  152. DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT;
  153. /// Map depth to z value. Throw an exception on error.
  154. IMATH_CONSTEXPR14 long DepthToZExc (T depth, long zmin, long zmax) const;
  155. /// Compute worldRadius
  156. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
  157. /// Compute worldRadius. Throw an exception on error.
  158. IMATH_CONSTEXPR14 T worldRadiusExc (const Vec3<T>& p, T radius) const;
  159. /// Compute screen radius
  160. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT;
  161. /// Compute screen radius. Throw an exception on error.
  162. IMATH_CONSTEXPR14 T screenRadiusExc (const Vec3<T>& p, T radius) const;
  163. /// @}
  164. protected:
  165. /// Map point from screen space to local space
  166. IMATH_HOSTDEVICE constexpr Vec2<T> screenToLocal (const Vec2<T>&) const IMATH_NOEXCEPT;
  167. /// Map point from local space to screen space
  168. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec2<T>
  169. localToScreen (const Vec2<T>&) const IMATH_NOEXCEPT;
  170. /// Map point from local space to screen space. Throw an exception
  171. /// on error.
  172. IMATH_CONSTEXPR14 Vec2<T> localToScreenExc (const Vec2<T>&) const;
  173. protected:
  174. /// @cond Doxygen_Suppress
  175. T _nearPlane;
  176. T _farPlane;
  177. T _left;
  178. T _right;
  179. T _top;
  180. T _bottom;
  181. bool _orthographic;
  182. /// @endcond
  183. };
  184. template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum() IMATH_NOEXCEPT
  185. {
  186. set (T (0.1), T (1000.0), T (-1.0), T (1.0), T (1.0), T (-1.0), false);
  187. }
  188. template <class T> IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (const Frustum& f) IMATH_NOEXCEPT
  189. {
  190. *this = f;
  191. }
  192. template <class T>
  193. IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
  194. {
  195. set (n, f, l, r, t, b, o);
  196. }
  197. template <class T>
  198. IMATH_CONSTEXPR14 inline Frustum<T>::Frustum (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
  199. {
  200. set (nearPlane, farPlane, fovx, fovy, aspect);
  201. }
  202. template <class T> Frustum<T>::~Frustum() IMATH_NOEXCEPT
  203. {}
  204. template <class T>
  205. IMATH_CONSTEXPR14 inline const Frustum<T>&
  206. Frustum<T>::operator= (const Frustum& f) IMATH_NOEXCEPT
  207. {
  208. _nearPlane = f._nearPlane;
  209. _farPlane = f._farPlane;
  210. _left = f._left;
  211. _right = f._right;
  212. _top = f._top;
  213. _bottom = f._bottom;
  214. _orthographic = f._orthographic;
  215. return *this;
  216. }
  217. template <class T>
  218. constexpr inline bool
  219. Frustum<T>::operator== (const Frustum<T>& src) const IMATH_NOEXCEPT
  220. {
  221. return _nearPlane == src._nearPlane && _farPlane == src._farPlane && _left == src._left &&
  222. _right == src._right && _top == src._top && _bottom == src._bottom &&
  223. _orthographic == src._orthographic;
  224. }
  225. template <class T>
  226. constexpr inline bool
  227. Frustum<T>::operator!= (const Frustum<T>& src) const IMATH_NOEXCEPT
  228. {
  229. return !operator== (src);
  230. }
  231. template <class T>
  232. inline void
  233. Frustum<T>::set (T n, T f, T l, T r, T t, T b, bool o) IMATH_NOEXCEPT
  234. {
  235. _nearPlane = n;
  236. _farPlane = f;
  237. _left = l;
  238. _right = r;
  239. _bottom = b;
  240. _top = t;
  241. _orthographic = o;
  242. }
  243. template <class T>
  244. inline void
  245. Frustum<T>::modifyNearAndFar (T n, T f) IMATH_NOEXCEPT
  246. {
  247. if (_orthographic)
  248. {
  249. _nearPlane = n;
  250. }
  251. else
  252. {
  253. Line3<T> lowerLeft (Vec3<T> (0, 0, 0), Vec3<T> (_left, _bottom, -_nearPlane));
  254. Line3<T> upperRight (Vec3<T> (0, 0, 0), Vec3<T> (_right, _top, -_nearPlane));
  255. Plane3<T> nearPlane (Vec3<T> (0, 0, -1), n);
  256. Vec3<T> ll = Vec3<T> (0, 0, 0);
  257. Vec3<T> ur = Vec3<T> (0, 0, 0);
  258. nearPlane.intersect (lowerLeft, ll);
  259. nearPlane.intersect (upperRight, ur);
  260. _left = ll.x;
  261. _right = ur.x;
  262. _top = ur.y;
  263. _bottom = ll.y;
  264. _nearPlane = n;
  265. _farPlane = f;
  266. }
  267. _farPlane = f;
  268. }
  269. template <class T>
  270. inline void
  271. Frustum<T>::setOrthographic (bool ortho) IMATH_NOEXCEPT
  272. {
  273. _orthographic = ortho;
  274. }
  275. template <class T>
  276. inline void
  277. Frustum<T>::setExc (T nearPlane, T farPlane, T fovx, T fovy, T aspect)
  278. {
  279. if (fovx != T (0) && fovy != T (0))
  280. throw std::domain_error ("fovx and fovy cannot both be non-zero.");
  281. const T two = static_cast<T> (2);
  282. if (fovx != T (0))
  283. {
  284. _right = nearPlane * std::tan (fovx / two);
  285. _left = -_right;
  286. _top = ((_right - _left) / aspect) / two;
  287. _bottom = -_top;
  288. }
  289. else
  290. {
  291. _top = nearPlane * std::tan (fovy / two);
  292. _bottom = -_top;
  293. _right = (_top - _bottom) * aspect / two;
  294. _left = -_right;
  295. }
  296. _nearPlane = nearPlane;
  297. _farPlane = farPlane;
  298. _orthographic = false;
  299. }
  300. template <class T>
  301. inline void
  302. Frustum<T>::set (T nearPlane, T farPlane, T fovx, T fovy, T aspect) IMATH_NOEXCEPT
  303. {
  304. const T two = static_cast<T> (2);
  305. if (fovx != T (0))
  306. {
  307. _right = nearPlane * std::tan (fovx / two);
  308. _left = -_right;
  309. _top = ((_right - _left) / aspect) / two;
  310. _bottom = -_top;
  311. }
  312. else
  313. {
  314. _top = nearPlane * std::tan (fovy / two);
  315. _bottom = -_top;
  316. _right = (_top - _bottom) * aspect / two;
  317. _left = -_right;
  318. }
  319. _nearPlane = nearPlane;
  320. _farPlane = farPlane;
  321. _orthographic = false;
  322. }
  323. template <class T>
  324. constexpr inline T
  325. Frustum<T>::fovx() const IMATH_NOEXCEPT
  326. {
  327. return std::atan2 (_right, _nearPlane) - std::atan2 (_left, _nearPlane);
  328. }
  329. template <class T>
  330. constexpr inline T
  331. Frustum<T>::fovy() const IMATH_NOEXCEPT
  332. {
  333. return std::atan2 (_top, _nearPlane) - std::atan2 (_bottom, _nearPlane);
  334. }
  335. template <class T>
  336. IMATH_CONSTEXPR14 inline T
  337. Frustum<T>::aspectExc() const
  338. {
  339. T rightMinusLeft = _right - _left;
  340. T topMinusBottom = _top - _bottom;
  341. if (abs (topMinusBottom) < T (1) && abs (rightMinusLeft) > std::numeric_limits<T>::max() * abs (topMinusBottom))
  342. {
  343. throw std::domain_error ("Bad viewing frustum: "
  344. "aspect ratio cannot be computed.");
  345. }
  346. return rightMinusLeft / topMinusBottom;
  347. }
  348. template <class T>
  349. IMATH_CONSTEXPR14 inline T
  350. Frustum<T>::aspect() const IMATH_NOEXCEPT
  351. {
  352. T rightMinusLeft = _right - _left;
  353. T topMinusBottom = _top - _bottom;
  354. return rightMinusLeft / topMinusBottom;
  355. }
  356. template <class T>
  357. IMATH_CONSTEXPR14 inline Matrix44<T>
  358. Frustum<T>::projectionMatrixExc() const
  359. {
  360. T rightPlusLeft = _right + _left;
  361. T rightMinusLeft = _right - _left;
  362. T topPlusBottom = _top + _bottom;
  363. T topMinusBottom = _top - _bottom;
  364. T farPlusNear = _farPlane + _nearPlane;
  365. T farMinusNear = _farPlane - _nearPlane;
  366. if ((abs (rightMinusLeft) < T (1) &&
  367. abs (rightPlusLeft) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
  368. (abs (topMinusBottom) < T (1) &&
  369. abs (topPlusBottom) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
  370. (abs (farMinusNear) < 1 && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear)))
  371. {
  372. throw std::domain_error ("Bad viewing frustum: "
  373. "projection matrix cannot be computed.");
  374. }
  375. if (_orthographic)
  376. {
  377. T tx = -rightPlusLeft / rightMinusLeft;
  378. T ty = -topPlusBottom / topMinusBottom;
  379. T tz = -farPlusNear / farMinusNear;
  380. if ((abs (rightMinusLeft) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
  381. (abs (topMinusBottom) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (topMinusBottom)) ||
  382. (abs (farMinusNear) < T (1) && T (2) > std::numeric_limits<T>::max() * abs (farMinusNear)))
  383. {
  384. throw std::domain_error ("Bad viewing frustum: "
  385. "projection matrix cannot be computed.");
  386. }
  387. T A = T (2) / rightMinusLeft;
  388. T B = T (2) / topMinusBottom;
  389. T C = T (-2) / farMinusNear;
  390. return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
  391. }
  392. else
  393. {
  394. T A = rightPlusLeft / rightMinusLeft;
  395. T B = topPlusBottom / topMinusBottom;
  396. T C = -farPlusNear / farMinusNear;
  397. T farTimesNear = T (-2) * _farPlane * _nearPlane;
  398. if (abs (farMinusNear) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
  399. {
  400. throw std::domain_error ("Bad viewing frustum: "
  401. "projection matrix cannot be computed.");
  402. }
  403. T D = farTimesNear / farMinusNear;
  404. T twoTimesNear = T (2) * _nearPlane;
  405. if ((abs (rightMinusLeft) < T (1) &&
  406. abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (rightMinusLeft)) ||
  407. (abs (topMinusBottom) < T (1) &&
  408. abs (twoTimesNear) > std::numeric_limits<T>::max() * abs (topMinusBottom)))
  409. {
  410. throw std::domain_error ("Bad viewing frustum: "
  411. "projection matrix cannot be computed.");
  412. }
  413. T E = twoTimesNear / rightMinusLeft;
  414. T F = twoTimesNear / topMinusBottom;
  415. return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
  416. }
  417. }
  418. template <class T>
  419. IMATH_CONSTEXPR14 inline Matrix44<T>
  420. Frustum<T>::projectionMatrix() const IMATH_NOEXCEPT
  421. {
  422. T rightPlusLeft = _right + _left;
  423. T rightMinusLeft = _right - _left;
  424. T topPlusBottom = _top + _bottom;
  425. T topMinusBottom = _top - _bottom;
  426. T farPlusNear = _farPlane + _nearPlane;
  427. T farMinusNear = _farPlane - _nearPlane;
  428. if (_orthographic)
  429. {
  430. T tx = -rightPlusLeft / rightMinusLeft;
  431. T ty = -topPlusBottom / topMinusBottom;
  432. T tz = -farPlusNear / farMinusNear;
  433. T A = T (2) / rightMinusLeft;
  434. T B = T (2) / topMinusBottom;
  435. T C = T (-2) / farMinusNear;
  436. return Matrix44<T> (A, 0, 0, 0, 0, B, 0, 0, 0, 0, C, 0, tx, ty, tz, 1.f);
  437. }
  438. else
  439. {
  440. T A = rightPlusLeft / rightMinusLeft;
  441. T B = topPlusBottom / topMinusBottom;
  442. T C = -farPlusNear / farMinusNear;
  443. T farTimesNear = T (-2) * _farPlane * _nearPlane;
  444. T D = farTimesNear / farMinusNear;
  445. T twoTimesNear = T (2) * _nearPlane;
  446. T E = twoTimesNear / rightMinusLeft;
  447. T F = twoTimesNear / topMinusBottom;
  448. return Matrix44<T> (E, 0, 0, 0, 0, F, 0, 0, A, B, C, -1, 0, 0, D, 0);
  449. }
  450. }
  451. template <class T>
  452. constexpr inline bool
  453. Frustum<T>::degenerate() const IMATH_NOEXCEPT
  454. {
  455. return (_nearPlane == _farPlane) || (_left == _right) || (_top == _bottom);
  456. }
  457. template <class T>
  458. IMATH_CONSTEXPR14 inline Frustum<T>
  459. Frustum<T>::window (T l, T r, T t, T b) const IMATH_NOEXCEPT
  460. {
  461. // move it to 0->1 space
  462. Vec2<T> bl = screenToLocal (Vec2<T> (l, b));
  463. Vec2<T> tr = screenToLocal (Vec2<T> (r, t));
  464. return Frustum<T> (_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
  465. }
  466. template <class T>
  467. constexpr inline Vec2<T>
  468. Frustum<T>::screenToLocal (const Vec2<T>& s) const IMATH_NOEXCEPT
  469. {
  470. return Vec2<T> (_left + (_right - _left) * (1.f + s.x) / 2.f,
  471. _bottom + (_top - _bottom) * (1.f + s.y) / 2.f);
  472. }
  473. template <class T>
  474. IMATH_CONSTEXPR14 inline Vec2<T>
  475. Frustum<T>::localToScreenExc (const Vec2<T>& p) const
  476. {
  477. T leftPlusRight = _left - T (2) * p.x + _right;
  478. T leftMinusRight = _left - _right;
  479. T bottomPlusTop = _bottom - T (2) * p.y + _top;
  480. T bottomMinusTop = _bottom - _top;
  481. if ((abs (leftMinusRight) < T (1) &&
  482. abs (leftPlusRight) > std::numeric_limits<T>::max() * abs (leftMinusRight)) ||
  483. (abs (bottomMinusTop) < T (1) &&
  484. abs (bottomPlusTop) > std::numeric_limits<T>::max() * abs (bottomMinusTop)))
  485. {
  486. throw std::domain_error ("Bad viewing frustum: "
  487. "local-to-screen transformation cannot be computed");
  488. }
  489. return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
  490. }
  491. template <class T>
  492. IMATH_CONSTEXPR14 inline Vec2<T>
  493. Frustum<T>::localToScreen (const Vec2<T>& p) const IMATH_NOEXCEPT
  494. {
  495. T leftPlusRight = _left - T (2) * p.x + _right;
  496. T leftMinusRight = _left - _right;
  497. T bottomPlusTop = _bottom - T (2) * p.y + _top;
  498. T bottomMinusTop = _bottom - _top;
  499. return Vec2<T> (leftPlusRight / leftMinusRight, bottomPlusTop / bottomMinusTop);
  500. }
  501. template <class T>
  502. IMATH_CONSTEXPR14 inline Line3<T>
  503. Frustum<T>::projectScreenToRay (const Vec2<T>& p) const IMATH_NOEXCEPT
  504. {
  505. Vec2<T> point = screenToLocal (p);
  506. if (orthographic())
  507. return Line3<T> (Vec3<T> (point.x, point.y, 0.0), Vec3<T> (point.x, point.y, -1.0));
  508. else
  509. return Line3<T> (Vec3<T> (0, 0, 0), Vec3<T> (point.x, point.y, -_nearPlane));
  510. }
  511. template <class T>
  512. IMATH_CONSTEXPR14 Vec2<T>
  513. Frustum<T>::projectPointToScreenExc (const Vec3<T>& point) const
  514. {
  515. if (orthographic() || point.z == T (0))
  516. return localToScreenExc (Vec2<T> (point.x, point.y));
  517. else
  518. return localToScreenExc (
  519. Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
  520. }
  521. template <class T>
  522. IMATH_CONSTEXPR14 Vec2<T>
  523. Frustum<T>::projectPointToScreen (const Vec3<T>& point) const IMATH_NOEXCEPT
  524. {
  525. if (orthographic() || point.z == T (0))
  526. return localToScreen (Vec2<T> (point.x, point.y));
  527. else
  528. return localToScreen (
  529. Vec2<T> (point.x * _nearPlane / -point.z, point.y * _nearPlane / -point.z));
  530. }
  531. template <class T>
  532. IMATH_CONSTEXPR14 T
  533. Frustum<T>::ZToDepthExc (long zval, long zmin, long zmax) const
  534. {
  535. int zdiff = zmax - zmin;
  536. if (zdiff == 0)
  537. {
  538. throw std::domain_error ("Bad call to Frustum::ZToDepth: zmax == zmin");
  539. }
  540. if (zval > zmax + 1)
  541. zval -= zdiff;
  542. T fzval = (T (zval) - T (zmin)) / T (zdiff);
  543. return normalizedZToDepthExc (fzval);
  544. }
  545. template <class T>
  546. IMATH_CONSTEXPR14 T
  547. Frustum<T>::ZToDepth (long zval, long zmin, long zmax) const IMATH_NOEXCEPT
  548. {
  549. int zdiff = zmax - zmin;
  550. if (zval > zmax + 1)
  551. zval -= zdiff;
  552. T fzval = (T (zval) - T (zmin)) / T (zdiff);
  553. return normalizedZToDepth (fzval);
  554. }
  555. template <class T>
  556. IMATH_CONSTEXPR14 T
  557. Frustum<T>::normalizedZToDepthExc (T zval) const
  558. {
  559. T Zp = zval * T (2) - T (1);
  560. if (_orthographic)
  561. {
  562. return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
  563. }
  564. else
  565. {
  566. T farTimesNear = 2 * _farPlane * _nearPlane;
  567. T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
  568. if (abs (farMinusNear) < 1 && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
  569. {
  570. throw std::domain_error ("Frustum::normalizedZToDepth cannot be computed: "
  571. "near and far clipping planes of the viewing frustum "
  572. "may be too close to each other");
  573. }
  574. return farTimesNear / farMinusNear;
  575. }
  576. }
  577. template <class T>
  578. IMATH_CONSTEXPR14 T
  579. Frustum<T>::normalizedZToDepth (T zval) const IMATH_NOEXCEPT
  580. {
  581. T Zp = zval * T (2) - T (1);
  582. if (_orthographic)
  583. {
  584. return -(Zp * (_farPlane - _nearPlane) + (_farPlane + _nearPlane)) / T (2);
  585. }
  586. else
  587. {
  588. T farTimesNear = 2 * _farPlane * _nearPlane;
  589. T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
  590. return farTimesNear / farMinusNear;
  591. }
  592. }
  593. template <class T>
  594. IMATH_CONSTEXPR14 long
  595. Frustum<T>::DepthToZExc (T depth, long zmin, long zmax) const
  596. {
  597. long zdiff = zmax - zmin;
  598. T farMinusNear = _farPlane - _nearPlane;
  599. if (_orthographic)
  600. {
  601. T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
  602. if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
  603. {
  604. throw std::domain_error ("Bad viewing frustum: "
  605. "near and far clipping planes "
  606. "are too close to each other");
  607. }
  608. T Zp = -farPlusNear / farMinusNear;
  609. return long (0.5 * (Zp + 1) * zdiff) + zmin;
  610. }
  611. else
  612. {
  613. // Perspective
  614. T farTimesNear = T (2) * _farPlane * _nearPlane;
  615. if (abs (depth) < T (1) && abs (farTimesNear) > std::numeric_limits<T>::max() * abs (depth))
  616. {
  617. throw std::domain_error ("Bad call to DepthToZ function: "
  618. "value of `depth' is too small");
  619. }
  620. T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
  621. if (abs (farMinusNear) < T (1) && abs (farPlusNear) > std::numeric_limits<T>::max() * abs (farMinusNear))
  622. {
  623. throw std::domain_error ("Bad viewing frustum: "
  624. "near and far clipping planes "
  625. "are too close to each other");
  626. }
  627. T Zp = farPlusNear / farMinusNear;
  628. return long (0.5 * (Zp + 1) * zdiff) + zmin;
  629. }
  630. }
  631. template <class T>
  632. IMATH_CONSTEXPR14 long
  633. Frustum<T>::DepthToZ (T depth, long zmin, long zmax) const IMATH_NOEXCEPT
  634. {
  635. long zdiff = zmax - zmin;
  636. T farMinusNear = _farPlane - _nearPlane;
  637. if (_orthographic)
  638. {
  639. T farPlusNear = T (2) * depth + _farPlane + _nearPlane;
  640. T Zp = -farPlusNear / farMinusNear;
  641. return long (0.5 * (Zp + 1) * zdiff) + zmin;
  642. }
  643. else
  644. {
  645. // Perspective
  646. T farTimesNear = T (2) * _farPlane * _nearPlane;
  647. T farPlusNear = farTimesNear / depth + _farPlane + _nearPlane;
  648. T Zp = farPlusNear / farMinusNear;
  649. return long (0.5 * (Zp + 1) * zdiff) + zmin;
  650. }
  651. }
  652. template <class T>
  653. IMATH_CONSTEXPR14 T
  654. Frustum<T>::screenRadiusExc (const Vec3<T>& p, T radius) const
  655. {
  656. // Derivation:
  657. // Consider X-Z plane.
  658. // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
  659. // Let q be p + (radius, 0, 0).
  660. // X coord of projection of q = xq = (p.x - radius) * (-_nearPlane / p.z)
  661. // X coord of projection of segment from p to q = r = xp - xq
  662. // = radius * (-_nearPlane / p.z)
  663. // A similar analysis holds in the Y-Z plane.
  664. // So r is the quantity we want to return.
  665. if (abs (p.z) > T (1) || abs (-_nearPlane) < std::numeric_limits<T>::max() * abs (p.z))
  666. {
  667. return radius * (-_nearPlane / p.z);
  668. }
  669. else
  670. {
  671. throw std::domain_error ("Bad call to Frustum::screenRadius: "
  672. "magnitude of `p' is too small");
  673. }
  674. return radius * (-_nearPlane / p.z);
  675. }
  676. template <class T>
  677. IMATH_CONSTEXPR14 T
  678. Frustum<T>::screenRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
  679. {
  680. // Derivation:
  681. // Consider X-Z plane.
  682. // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
  683. // Let q be p + (radius, 0, 0).
  684. // X coord of projection of q = xq = (p.x - radius) * (-_nearPlane / p.z)
  685. // X coord of projection of segment from p to q = r = xp - xq
  686. // = radius * (-_nearPlane / p.z)
  687. // A similar analysis holds in the Y-Z plane.
  688. // So r is the quantity we want to return.
  689. return radius * (-_nearPlane / p.z);
  690. }
  691. template <class T>
  692. IMATH_CONSTEXPR14 T
  693. Frustum<T>::worldRadiusExc (const Vec3<T>& p, T radius) const
  694. {
  695. if (abs (-_nearPlane) > T (1) || abs (p.z) < std::numeric_limits<T>::max() * abs (-_nearPlane))
  696. {
  697. return radius * (p.z / -_nearPlane);
  698. }
  699. else
  700. {
  701. throw std::domain_error ("Bad viewing frustum: "
  702. "near clipping plane is too close to zero");
  703. }
  704. }
  705. template <class T>
  706. IMATH_CONSTEXPR14 T
  707. Frustum<T>::worldRadius (const Vec3<T>& p, T radius) const IMATH_NOEXCEPT
  708. {
  709. return radius * (p.z / -_nearPlane);
  710. }
  711. template <class T>
  712. void
  713. Frustum<T>::planes (Plane3<T> p[6]) const IMATH_NOEXCEPT
  714. {
  715. //
  716. // Plane order: Top, Right, Bottom, Left, Near, Far.
  717. // Normals point outwards.
  718. //
  719. if (!_orthographic)
  720. {
  721. Vec3<T> a (_left, _bottom, -_nearPlane);
  722. Vec3<T> b (_left, _top, -_nearPlane);
  723. Vec3<T> c (_right, _top, -_nearPlane);
  724. Vec3<T> d (_right, _bottom, -_nearPlane);
  725. Vec3<T> o (0, 0, 0);
  726. p[0].set (o, c, b);
  727. p[1].set (o, d, c);
  728. p[2].set (o, a, d);
  729. p[3].set (o, b, a);
  730. }
  731. else
  732. {
  733. p[0].set (Vec3<T> (0, 1, 0), _top);
  734. p[1].set (Vec3<T> (1, 0, 0), _right);
  735. p[2].set (Vec3<T> (0, -1, 0), -_bottom);
  736. p[3].set (Vec3<T> (-1, 0, 0), -_left);
  737. }
  738. p[4].set (Vec3<T> (0, 0, 1), -_nearPlane);
  739. p[5].set (Vec3<T> (0, 0, -1), _farPlane);
  740. }
  741. template <class T>
  742. void
  743. Frustum<T>::planes (Plane3<T> p[6], const Matrix44<T>& M) const IMATH_NOEXCEPT
  744. {
  745. //
  746. // Plane order: Top, Right, Bottom, Left, Near, Far.
  747. // Normals point outwards.
  748. //
  749. Vec3<T> a = Vec3<T> (_left, _bottom, -_nearPlane) * M;
  750. Vec3<T> b = Vec3<T> (_left, _top, -_nearPlane) * M;
  751. Vec3<T> c = Vec3<T> (_right, _top, -_nearPlane) * M;
  752. Vec3<T> d = Vec3<T> (_right, _bottom, -_nearPlane) * M;
  753. if (!_orthographic)
  754. {
  755. double s = _farPlane / double (_nearPlane);
  756. T farLeft = (T) (s * _left);
  757. T farRight = (T) (s * _right);
  758. T farTop = (T) (s * _top);
  759. T farBottom = (T) (s * _bottom);
  760. Vec3<T> e = Vec3<T> (farLeft, farBottom, -_farPlane) * M;
  761. Vec3<T> f = Vec3<T> (farLeft, farTop, -_farPlane) * M;
  762. Vec3<T> g = Vec3<T> (farRight, farTop, -_farPlane) * M;
  763. Vec3<T> o = Vec3<T> (0, 0, 0) * M;
  764. p[0].set (o, c, b);
  765. p[1].set (o, d, c);
  766. p[2].set (o, a, d);
  767. p[3].set (o, b, a);
  768. p[4].set (a, d, c);
  769. p[5].set (e, f, g);
  770. }
  771. else
  772. {
  773. Vec3<T> e = Vec3<T> (_left, _bottom, -_farPlane) * M;
  774. Vec3<T> f = Vec3<T> (_left, _top, -_farPlane) * M;
  775. Vec3<T> g = Vec3<T> (_right, _top, -_farPlane) * M;
  776. Vec3<T> h = Vec3<T> (_right, _bottom, -_farPlane) * M;
  777. p[0].set (c, g, f);
  778. p[1].set (d, h, g);
  779. p[2].set (a, e, h);
  780. p[3].set (b, f, e);
  781. p[4].set (a, d, c);
  782. p[5].set (e, f, g);
  783. }
  784. }
  785. /// Frustum of type float
  786. typedef Frustum<float> Frustumf;
  787. /// Frustum of type double
  788. typedef Frustum<double> Frustumd;
  789. IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
  790. #if defined _WIN32 || defined _WIN64
  791. # ifdef _redef_near
  792. # define near
  793. # endif
  794. # ifdef _redef_far
  795. # define far
  796. # endif
  797. #endif
  798. #endif // INCLUDED_IMATHFRUSTUM_H