1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // * Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34
35
36
37 #ifndef INCLUDED_IMATHFRUSTUM_H
38 #define INCLUDED_IMATHFRUSTUM_H
39
40
41 #include "ImathVec.h"
42 #include "ImathPlane.h"
43 #include "ImathLine.h"
44 #include "ImathMatrix.h"
45 #include "ImathLimits.h"
46 #include "ImathFun.h"
47 #include "IexMathExc.h"
48
49 namespace Imath {
50
51 //
52 // template class Frustum<T>
53 //
54 // The frustum is always located with the eye point at the
55 // origin facing down -Z. This makes the Frustum class
56 // compatable with OpenGL (or anything that assumes a camera
57 // looks down -Z, hence with a right-handed coordinate system)
58 // but not with RenderMan which assumes the camera looks down
59 // +Z. Additional functions are provided for conversion from
60 // and from various camera coordinate spaces.
61 //
62 // nearPlane/farPlane: near/far are keywords used by Microsoft's
63 // compiler, so we use nearPlane/farPlane instead to avoid
64 // issues.
65
66
67 template<class T>
68 class Frustum
69 {
70 public:
71 Frustum();
72 Frustum(const Frustum &);
73 Frustum(T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho=false);
74 Frustum(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
75 virtual ~Frustum();
76
77 //--------------------
78 // Assignment operator
79 //--------------------
80
81 const Frustum &operator = (const Frustum &);
82
83 //--------------------
84 // Operators: ==, !=
85 //--------------------
86
87 bool operator == (const Frustum<T> &src) const;
88 bool operator != (const Frustum<T> &src) const;
89
90 //--------------------------------------------------------
91 // Set functions change the entire state of the Frustum
92 //--------------------------------------------------------
93
94 void set(T nearPlane, T farPlane,
95 T left, T right,
96 T top, T bottom,
97 bool ortho=false);
98
99 void set(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
100
101 //------------------------------------------------------
102 // These functions modify an already valid frustum state
103 //------------------------------------------------------
104
105 void modifyNearAndFar(T nearPlane, T farPlane);
106 void setOrthographic(bool);
107
108 //--------------
109 // Access
110 //--------------
111
orthographic()112 bool orthographic() const { return _orthographic; }
nearPlane()113 T nearPlane() const { return _nearPlane; }
hither()114 T hither() const { return _nearPlane; }
farPlane()115 T farPlane() const { return _farPlane; }
yon()116 T yon() const { return _farPlane; }
left()117 T left() const { return _left; }
right()118 T right() const { return _right; }
bottom()119 T bottom() const { return _bottom; }
top()120 T top() const { return _top; }
121
122 //-----------------------------------------------------------------------
123 // Sets the planes in p to be the six bounding planes of the frustum, in
124 // the following order: top, right, bottom, left, near, far.
125 // Note that the planes have normals that point out of the frustum.
126 // The version of this routine that takes a matrix applies that matrix
127 // to transform the frustum before setting the planes.
128 //-----------------------------------------------------------------------
129
130 void planes(Plane3<T> p[6]);
131 void planes(Plane3<T> p[6], const Matrix44<T> &M);
132
133 //----------------------
134 // Derived Quantities
135 //----------------------
136
137 T fovx() const;
138 T fovy() const;
139 T aspect() const;
140 Matrix44<T> projectionMatrix() const;
141 bool degenerate() const;
142
143 //-----------------------------------------------------------------------
144 // Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
145 // and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
146 // Frustum whose near clipping-plane window is that rectangle in local
147 // space.
148 //-----------------------------------------------------------------------
149
150 Frustum<T> window(T left, T right, T top, T bottom) const;
151
152 //----------------------------------------------------------
153 // Projection is in screen space / Conversion from Z-Buffer
154 //----------------------------------------------------------
155
156 Line3<T> projectScreenToRay( const Vec2<T> & ) const;
157 Vec2<T> projectPointToScreen( const Vec3<T> & ) const;
158
159 T ZToDepth(long zval, long min, long max) const;
160 T normalizedZToDepth(T zval) const;
161 long DepthToZ(T depth, long zmin, long zmax) const;
162
163 T worldRadius(const Vec3<T> &p, T radius) const;
164 T screenRadius(const Vec3<T> &p, T radius) const;
165
166
167 protected:
168
169 Vec2<T> screenToLocal( const Vec2<T> & ) const;
170 Vec2<T> localToScreen( const Vec2<T> & ) const;
171
172 protected:
173 T _nearPlane;
174 T _farPlane;
175 T _left;
176 T _right;
177 T _top;
178 T _bottom;
179 bool _orthographic;
180 };
181
182
183 template<class T>
Frustum()184 inline Frustum<T>::Frustum()
185 {
186 set(T (0.1),
187 T (1000.0),
188 T (-1.0),
189 T (1.0),
190 T (1.0),
191 T (-1.0),
192 false);
193 }
194
195 template<class T>
Frustum(const Frustum & f)196 inline Frustum<T>::Frustum(const Frustum &f)
197 {
198 *this = f;
199 }
200
201 template<class T>
Frustum(T n,T f,T l,T r,T t,T b,bool o)202 inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
203 {
204 set(n,f,l,r,t,b,o);
205 }
206
207 template<class T>
Frustum(T nearPlane,T farPlane,T fovx,T fovy,T aspect)208 inline Frustum<T>::Frustum(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
209 {
210 set(nearPlane,farPlane,fovx,fovy,aspect);
211 }
212
213 template<class T>
~Frustum()214 Frustum<T>::~Frustum()
215 {
216 }
217
218 template<class T>
219 const Frustum<T> &
220 Frustum<T>::operator = (const Frustum &f)
221 {
222 _nearPlane = f._nearPlane;
223 _farPlane = f._farPlane;
224 _left = f._left;
225 _right = f._right;
226 _top = f._top;
227 _bottom = f._bottom;
228 _orthographic = f._orthographic;
229
230 return *this;
231 }
232
233 template <class T>
234 bool
235 Frustum<T>::operator == (const Frustum<T> &src) const
236 {
237 return
238 _nearPlane == src._nearPlane &&
239 _farPlane == src._farPlane &&
240 _left == src._left &&
241 _right == src._right &&
242 _top == src._top &&
243 _bottom == src._bottom &&
244 _orthographic == src._orthographic;
245 }
246
247 template <class T>
248 inline bool
249 Frustum<T>::operator != (const Frustum<T> &src) const
250 {
251 return !operator== (src);
252 }
253
254 template<class T>
set(T n,T f,T l,T r,T t,T b,bool o)255 void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
256 {
257 _nearPlane = n;
258 _farPlane = f;
259 _left = l;
260 _right = r;
261 _bottom = b;
262 _top = t;
263 _orthographic = o;
264 }
265
266 template<class T>
modifyNearAndFar(T n,T f)267 void Frustum<T>::modifyNearAndFar(T n, T f)
268 {
269 if ( _orthographic )
270 {
271 _nearPlane = n;
272 }
273 else
274 {
275 Line3<T> lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_nearPlane) );
276 Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_nearPlane) );
277 Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
278
279 Vec3<T> ll,ur;
280 nearPlane.intersect(lowerLeft,ll);
281 nearPlane.intersect(upperRight,ur);
282
283 _left = ll.x;
284 _right = ur.x;
285 _top = ur.y;
286 _bottom = ll.y;
287 _nearPlane = n;
288 _farPlane = f;
289 }
290
291 _farPlane = f;
292 }
293
294 template<class T>
setOrthographic(bool ortho)295 void Frustum<T>::setOrthographic(bool ortho)
296 {
297 _orthographic = ortho;
298 }
299
300 template<class T>
set(T nearPlane,T farPlane,T fovx,T fovy,T aspect)301 void Frustum<T>::set(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
302 {
303 if (fovx != 0 && fovy != 0)
304 throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
305
306 const T two = static_cast<T>(2);
307
308 if (fovx != 0)
309 {
310 _right = nearPlane * Math<T>::tan(fovx / two);
311 _left = -_right;
312 _top = ((_right - _left) / aspect) / two;
313 _bottom = -_top;
314 }
315 else
316 {
317 _top = nearPlane * Math<T>::tan(fovy / two);
318 _bottom = -_top;
319 _right = (_top - _bottom) * aspect / two;
320 _left = -_right;
321 }
322 _nearPlane = nearPlane;
323 _farPlane = farPlane;
324 _orthographic = false;
325 }
326
327 template<class T>
fovx()328 T Frustum<T>::fovx() const
329 {
330 return Math<T>::atan2(_right,_nearPlane) - Math<T>::atan2(_left,_nearPlane);
331 }
332
333 template<class T>
fovy()334 T Frustum<T>::fovy() const
335 {
336 return Math<T>::atan2(_top,_nearPlane) - Math<T>::atan2(_bottom,_nearPlane);
337 }
338
339 template<class T>
aspect()340 T Frustum<T>::aspect() const
341 {
342 T rightMinusLeft = _right-_left;
343 T topMinusBottom = _top-_bottom;
344
345 if (abs(topMinusBottom) < 1 &&
346 abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
347 {
348 throw Iex::DivzeroExc ("Bad viewing frustum: "
349 "aspect ratio cannot be computed.");
350 }
351
352 return rightMinusLeft / topMinusBottom;
353 }
354
355 template<class T>
projectionMatrix()356 Matrix44<T> Frustum<T>::projectionMatrix() const
357 {
358 T rightPlusLeft = _right+_left;
359 T rightMinusLeft = _right-_left;
360
361 T topPlusBottom = _top+_bottom;
362 T topMinusBottom = _top-_bottom;
363
364 T farPlusNear = _farPlane+_nearPlane;
365 T farMinusNear = _farPlane-_nearPlane;
366
367 if ((abs(rightMinusLeft) < 1 &&
368 abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
369 (abs(topMinusBottom) < 1 &&
370 abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
371 (abs(farMinusNear) < 1 &&
372 abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
373 {
374 throw Iex::DivzeroExc ("Bad viewing frustum: "
375 "projection matrix cannot be computed.");
376 }
377
378 if ( _orthographic )
379 {
380 T tx = -rightPlusLeft / rightMinusLeft;
381 T ty = -topPlusBottom / topMinusBottom;
382 T tz = -farPlusNear / farMinusNear;
383
384 if ((abs(rightMinusLeft) < 1 &&
385 2 > limits<T>::max() * abs(rightMinusLeft)) ||
386 (abs(topMinusBottom) < 1 &&
387 2 > limits<T>::max() * abs(topMinusBottom)) ||
388 (abs(farMinusNear) < 1 &&
389 2 > limits<T>::max() * abs(farMinusNear)))
390 {
391 throw Iex::DivzeroExc ("Bad viewing frustum: "
392 "projection matrix cannot be computed.");
393 }
394
395 T A = 2 / rightMinusLeft;
396 T B = 2 / topMinusBottom;
397 T C = -2 / farMinusNear;
398
399 return Matrix44<T>( A, 0, 0, 0,
400 0, B, 0, 0,
401 0, 0, C, 0,
402 tx, ty, tz, 1.f );
403 }
404 else
405 {
406 T A = rightPlusLeft / rightMinusLeft;
407 T B = topPlusBottom / topMinusBottom;
408 T C = -farPlusNear / farMinusNear;
409
410 T farTimesNear = -2 * _farPlane * _nearPlane;
411 if (abs(farMinusNear) < 1 &&
412 abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
413 {
414 throw Iex::DivzeroExc ("Bad viewing frustum: "
415 "projection matrix cannot be computed.");
416 }
417
418 T D = farTimesNear / farMinusNear;
419
420 T twoTimesNear = 2 * _nearPlane;
421
422 if ((abs(rightMinusLeft) < 1 &&
423 abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
424 (abs(topMinusBottom) < 1 &&
425 abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
426 {
427 throw Iex::DivzeroExc ("Bad viewing frustum: "
428 "projection matrix cannot be computed.");
429 }
430
431 T E = twoTimesNear / rightMinusLeft;
432 T F = twoTimesNear / topMinusBottom;
433
434 return Matrix44<T>( E, 0, 0, 0,
435 0, F, 0, 0,
436 A, B, C, -1,
437 0, 0, D, 0 );
438 }
439 }
440
441 template<class T>
degenerate()442 bool Frustum<T>::degenerate() const
443 {
444 return (_nearPlane == _farPlane) ||
445 (_left == _right) ||
446 (_top == _bottom);
447 }
448
449 template<class T>
window(T l,T r,T t,T b)450 Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
451 {
452 // move it to 0->1 space
453
454 Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
455 Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
456
457 return Frustum<T>(_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
458 }
459
460
461 template<class T>
screenToLocal(const Vec2<T> & s)462 Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
463 {
464 return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
465 _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
466 }
467
468 template<class T>
localToScreen(const Vec2<T> & p)469 Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
470 {
471 T leftPlusRight = _left - T (2) * p.x + _right;
472 T leftMinusRight = _left-_right;
473 T bottomPlusTop = _bottom - T (2) * p.y + _top;
474 T bottomMinusTop = _bottom-_top;
475
476 if ((abs(leftMinusRight) < T (1) &&
477 abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
478 (abs(bottomMinusTop) < T (1) &&
479 abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
480 {
481 throw Iex::DivzeroExc
482 ("Bad viewing frustum: "
483 "local-to-screen transformation cannot be computed");
484 }
485
486 return Vec2<T>( leftPlusRight / leftMinusRight,
487 bottomPlusTop / bottomMinusTop );
488 }
489
490 template<class T>
projectScreenToRay(const Vec2<T> & p)491 Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
492 {
493 Vec2<T> point = screenToLocal(p);
494 if (orthographic())
495 return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
496 Vec3<T>(point.x,point.y,-_nearPlane));
497 else
498 return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_nearPlane));
499 }
500
501 template<class T>
projectPointToScreen(const Vec3<T> & point)502 Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
503 {
504 if (orthographic() || point.z == T (0))
505 return localToScreen( Vec2<T>( point.x, point.y ) );
506 else
507 return localToScreen( Vec2<T>( point.x * _nearPlane / -point.z,
508 point.y * _nearPlane / -point.z ) );
509 }
510
511 template<class T>
ZToDepth(long zval,long zmin,long zmax)512 T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
513 {
514 int zdiff = zmax - zmin;
515
516 if (zdiff == 0)
517 {
518 throw Iex::DivzeroExc
519 ("Bad call to Frustum::ZToDepth: zmax == zmin");
520 }
521
522 if ( zval > zmax+1 ) zval -= zdiff;
523
524 T fzval = (T(zval) - T(zmin)) / T(zdiff);
525 return normalizedZToDepth(fzval);
526 }
527
528 template<class T>
normalizedZToDepth(T zval)529 T Frustum<T>::normalizedZToDepth(T zval) const
530 {
531 T Zp = zval * 2.0 - 1;
532
533 if ( _orthographic )
534 {
535 return -(Zp*(_farPlane-_nearPlane) + (_farPlane+_nearPlane))/2;
536 }
537 else
538 {
539 T farTimesNear = 2 * _farPlane * _nearPlane;
540 T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
541
542 if (abs(farMinusNear) < 1 &&
543 abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
544 {
545 throw Iex::DivzeroExc
546 ("Frustum::normalizedZToDepth cannot be computed. The "
547 "near and far clipping planes of the viewing frustum "
548 "may be too close to each other");
549 }
550
551 return farTimesNear / farMinusNear;
552 }
553 }
554
555 template<class T>
DepthToZ(T depth,long zmin,long zmax)556 long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
557 {
558 long zdiff = zmax - zmin;
559 T farMinusNear = _farPlane-_nearPlane;
560
561 if ( _orthographic )
562 {
563 T farPlusNear = 2*depth + _farPlane + _nearPlane;
564
565 if (abs(farMinusNear) < 1 &&
566 abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
567 {
568 throw Iex::DivzeroExc
569 ("Bad viewing frustum: near and far clipping planes "
570 "are too close to each other");
571 }
572
573 T Zp = -farPlusNear/farMinusNear;
574 return long(0.5*(Zp+1)*zdiff) + zmin;
575 }
576 else
577 {
578 // Perspective
579
580 T farTimesNear = 2*_farPlane*_nearPlane;
581 if (abs(depth) < 1 &&
582 abs(farTimesNear) > limits<T>::max() * abs(depth))
583 {
584 throw Iex::DivzeroExc
585 ("Bad call to DepthToZ function: value of `depth' "
586 "is too small");
587 }
588
589 T farPlusNear = farTimesNear/depth + _farPlane + _nearPlane;
590 if (abs(farMinusNear) < 1 &&
591 abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
592 {
593 throw Iex::DivzeroExc
594 ("Bad viewing frustum: near and far clipping planes "
595 "are too close to each other");
596 }
597
598 T Zp = farPlusNear/farMinusNear;
599 return long(0.5*(Zp+1)*zdiff) + zmin;
600 }
601 }
602
603 template<class T>
screenRadius(const Vec3<T> & p,T radius)604 T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
605 {
606 // Derivation:
607 // Consider X-Z plane.
608 // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
609 // Let q be p + (radius, 0, 0).
610 // X coord of projection of q = xq = (p.x - radius) * (-_nearPlane / p.z)
611 // X coord of projection of segment from p to q = r = xp - xq
612 // = radius * (-_nearPlane / p.z)
613 // A similar analysis holds in the Y-Z plane.
614 // So r is the quantity we want to return.
615
616 if (abs(p.z) > 1 || abs(-_nearPlane) < limits<T>::max() * abs(p.z))
617 {
618 return radius * (-_nearPlane / p.z);
619 }
620 else
621 {
622 throw Iex::DivzeroExc
623 ("Bad call to Frustum::screenRadius: the magnitude of `p' "
624 "is too small");
625 }
626
627 return radius * (-_nearPlane / p.z);
628 }
629
630 template<class T>
worldRadius(const Vec3<T> & p,T radius)631 T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
632 {
633 if (abs(-_nearPlane) > 1 || abs(p.z) < limits<T>::max() * abs(-_nearPlane))
634 {
635 return radius * (p.z / -_nearPlane);
636 }
637 else
638 {
639 throw Iex::DivzeroExc
640 ("Bad viewing frustum: the near clipping plane is too "
641 "close to zero");
642 }
643 }
644
645 template<class T>
planes(Plane3<T> p[6])646 void Frustum<T>::planes(Plane3<T> p[6])
647 {
648 //
649 // Plane order: Top, Right, Bottom, Left, Near, Far.
650 // Normals point outwards.
651 //
652
653 if (! _orthographic)
654 {
655 Vec3<T> a( _left, _bottom, -_nearPlane);
656 Vec3<T> b( _left, _top, -_nearPlane);
657 Vec3<T> c( _right, _top, -_nearPlane);
658 Vec3<T> d( _right, _bottom, -_nearPlane);
659 Vec3<T> o(0,0,0);
660
661 p[0].set( o, c, b );
662 p[1].set( o, d, c );
663 p[2].set( o, a, d );
664 p[3].set( o, b, a );
665 }
666 else
667 {
668 p[0].set( Vec3<T>( 0, 1, 0), _top );
669 p[1].set( Vec3<T>( 1, 0, 0), _right );
670 p[2].set( Vec3<T>( 0,-1, 0),-_bottom );
671 p[3].set( Vec3<T>(-1, 0, 0),-_left );
672 }
673 p[4].set( Vec3<T>(0, 0, 1), -_nearPlane );
674 p[5].set( Vec3<T>(0, 0,-1), _farPlane );
675 }
676
677
678 template<class T>
planes(Plane3<T> p[6],const Matrix44<T> & M)679 void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
680 {
681 //
682 // Plane order: Top, Right, Bottom, Left, Near, Far.
683 // Normals point outwards.
684 //
685
686 Vec3<T> a = Vec3<T>( _left, _bottom, -_nearPlane) * M;
687 Vec3<T> b = Vec3<T>( _left, _top, -_nearPlane) * M;
688 Vec3<T> c = Vec3<T>( _right, _top, -_nearPlane) * M;
689 Vec3<T> d = Vec3<T>( _right, _bottom, -_nearPlane) * M;
690 if (! _orthographic)
691 {
692 double s = _farPlane / double(_nearPlane);
693 T farLeft = (T) (s * _left);
694 T farRight = (T) (s * _right);
695 T farTop = (T) (s * _top);
696 T farBottom = (T) (s * _bottom);
697 Vec3<T> e = Vec3<T>( farLeft, farBottom, -_farPlane) * M;
698 Vec3<T> f = Vec3<T>( farLeft, farTop, -_farPlane) * M;
699 Vec3<T> g = Vec3<T>( farRight, farTop, -_farPlane) * M;
700 Vec3<T> o = Vec3<T>(0,0,0) * M;
701 p[0].set( o, c, b );
702 p[1].set( o, d, c );
703 p[2].set( o, a, d );
704 p[3].set( o, b, a );
705 p[4].set( a, d, c );
706 p[5].set( e, f, g );
707 }
708 else
709 {
710 Vec3<T> e = Vec3<T>( _left, _bottom, -_farPlane) * M;
711 Vec3<T> f = Vec3<T>( _left, _top, -_farPlane) * M;
712 Vec3<T> g = Vec3<T>( _right, _top, -_farPlane) * M;
713 Vec3<T> h = Vec3<T>( _right, _bottom, -_farPlane) * M;
714 p[0].set( c, g, f );
715 p[1].set( d, h, g );
716 p[2].set( a, e, h );
717 p[3].set( b, f, e );
718 p[4].set( a, d, c );
719 p[5].set( e, f, g );
720 }
721 }
722
723 typedef Frustum<float> Frustumf;
724 typedef Frustum<double> Frustumd;
725
726
727 } // namespace Imath
728
729
730 #if defined _WIN32 || defined _WIN64
731 #ifdef _redef_near
732 #define near
733 #endif
734 #ifdef _redef_far
735 #define far
736 #endif
737 #endif
738
739 #endif
740