• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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