Home | History | Annotate | Download | only in Imath
      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 
    112     bool		orthographic() const	{ return _orthographic; }
    113     T			nearPlane() const	{ return _nearPlane;	}
    114     T			hither() const		{ return _nearPlane;	}
    115     T			farPlane() const	{ return _farPlane;	}
    116     T			yon() const		{ return _farPlane;	}
    117     T			left() const		{ return _left;		}
    118     T			right() const		{ return _right;	}
    119     T			bottom() const		{ return _bottom;	}
    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>
    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>
    196 inline Frustum<T>::Frustum(const Frustum &f)
    197 {
    198     *this = f;
    199 }
    200 
    201 template<class T>
    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>
    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>
    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>
    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>
    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>
    295 void Frustum<T>::setOrthographic(bool ortho)
    296 {
    297     _orthographic   = ortho;
    298 }
    299 
    300 template<class T>
    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>
    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>
    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>
    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>
    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>
    442 bool Frustum<T>::degenerate() const
    443 {
    444     return (_nearPlane == _farPlane) ||
    445            (_left == _right) ||
    446            (_top == _bottom);
    447 }
    448 
    449 template<class T>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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