1
///////////////////////////////////////////////////////////////////////////
3
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
6
// All rights reserved.
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions are
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
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.
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.
33
///////////////////////////////////////////////////////////////////////////
37
#ifndef INCLUDED_IMATHFRUSTUM_H
38
#define INCLUDED_IMATHFRUSTUM_H
42
#include "ImathPlane.h"
43
#include "ImathLine.h"
44
#include "ImathMatrix.h"
45
#include "ImathLimits.h"
47
#include "IexMathExc.h"
49
#if defined _WIN32 || defined _WIN64
63
// template class Frustum<T>
65
// The frustum is always located with the eye point at the
66
// origin facing down -Z. This makes the Frustum class
67
// compatable with OpenGL (or anything that assumes a camera
68
// looks down -Z, hence with a right-handed coordinate system)
69
// but not with RenderMan which assumes the camera looks down
70
// +Z. Additional functions are provided for conversion from
71
// and from various camera coordinate spaces.
80
Frustum(const Frustum &);
81
Frustum(T near, T far, T left, T right, T top, T bottom, bool ortho=false);
82
Frustum(T near, T far, T fovx, T fovy, T aspect);
85
//--------------------
86
// Assignment operator
87
//--------------------
89
const Frustum &operator = (const Frustum &);
91
//--------------------
93
//--------------------
95
bool operator == (const Frustum<T> &src) const;
96
bool operator != (const Frustum<T> &src) const;
98
//--------------------------------------------------------
99
// Set functions change the entire state of the Frustum
100
//--------------------------------------------------------
102
void set(T near, T far,
107
void set(T near, T far, T fovx, T fovy, T aspect);
109
//------------------------------------------------------
110
// These functions modify an already valid frustum state
111
//------------------------------------------------------
113
void modifyNearAndFar(T near, T far);
114
void setOrthographic(bool);
120
bool orthographic() const { return _orthographic; }
121
T near() const { return _near; }
122
T hither() const { return _near; }
123
T far() const { return _far; }
124
T yon() const { return _far; }
125
T left() const { return _left; }
126
T right() const { return _right; }
127
T bottom() const { return _bottom; }
128
T top() const { return _top; }
130
//-----------------------------------------------------------------------
131
// Sets the planes in p to be the six bounding planes of the frustum, in
132
// the following order: top, right, bottom, left, near, far.
133
// Note that the planes have normals that point out of the frustum.
134
// The version of this routine that takes a matrix applies that matrix
135
// to transform the frustum before setting the planes.
136
//-----------------------------------------------------------------------
138
void planes(Plane3<T> p[6]);
139
void planes(Plane3<T> p[6], const Matrix44<T> &M);
141
//----------------------
142
// Derived Quantities
143
//----------------------
148
Matrix44<T> projectionMatrix() const;
150
//-----------------------------------------------------------------------
151
// Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1
152
// and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
153
// Frustum whose near clipping-plane window is that rectangle in local
155
//-----------------------------------------------------------------------
157
Frustum<T> window(T left, T right, T top, T bottom) const;
159
//----------------------------------------------------------
160
// Projection is in screen space / Conversion from Z-Buffer
161
//----------------------------------------------------------
163
Line3<T> projectScreenToRay( const Vec2<T> & ) const;
164
Vec2<T> projectPointToScreen( const Vec3<T> & ) const;
166
T ZToDepth(long zval, long min, long max) const;
167
T normalizedZToDepth(T zval) const;
168
long DepthToZ(T depth, long zmin, long zmax) const;
170
T worldRadius(const Vec3<T> &p, T radius) const;
171
T screenRadius(const Vec3<T> &p, T radius) const;
176
Vec2<T> screenToLocal( const Vec2<T> & ) const;
177
Vec2<T> localToScreen( const Vec2<T> & ) const;
191
inline Frustum<T>::Frustum()
203
inline Frustum<T>::Frustum(const Frustum &f)
209
inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
215
inline Frustum<T>::Frustum(T near, T far, T fovx, T fovy, T aspect)
217
set(near,far,fovx,fovy,aspect);
221
Frustum<T>::~Frustum()
227
Frustum<T>::operator = (const Frustum &f)
235
_orthographic = f._orthographic;
242
Frustum<T>::operator == (const Frustum<T> &src) const
245
_near == src._near &&
247
_left == src._left &&
248
_right == src._right &&
250
_bottom == src._bottom &&
251
_orthographic == src._orthographic;
256
Frustum<T>::operator != (const Frustum<T> &src) const
258
return !operator== (src);
262
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
274
void Frustum<T>::modifyNearAndFar(T n, T f)
282
Line3<T> lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_near) );
283
Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_near) );
284
Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
287
nearPlane.intersect(lowerLeft,ll);
288
nearPlane.intersect(upperRight,ur);
302
void Frustum<T>::setOrthographic(bool ortho)
304
_orthographic = ortho;
308
void Frustum<T>::set(T near, T far, T fovx, T fovy, T aspect)
310
if (fovx != 0 && fovy != 0)
311
throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
315
_right = near * Math<T>::tan (fovx / 2);
317
_top = ((_right - _left) / aspect) / 2;
322
_top = near * Math<T>::tan (fovy / 2);
324
_right = (_top - _bottom) * aspect / 2;
329
_orthographic = false;
333
T Frustum<T>::fovx() const
335
return Math<T>::atan2(_right,_near) - Math<T>::atan2(_left,_near);
339
T Frustum<T>::fovy() const
341
return Math<T>::atan2(_top,_near) - Math<T>::atan2(_bottom,_near);
345
T Frustum<T>::aspect() const
347
T rightMinusLeft = _right-_left;
348
T topMinusBottom = _top-_bottom;
350
if (abs(topMinusBottom) < 1 &&
351
abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
353
throw Iex::DivzeroExc ("Bad viewing frustum: "
354
"aspect ratio cannot be computed.");
357
return rightMinusLeft / topMinusBottom;
361
Matrix44<T> Frustum<T>::projectionMatrix() const
363
T rightPlusLeft = _right+_left;
364
T rightMinusLeft = _right-_left;
366
T topPlusBottom = _top+_bottom;
367
T topMinusBottom = _top-_bottom;
369
T farPlusNear = _far+_near;
370
T farMinusNear = _far-_near;
372
if ((abs(rightMinusLeft) < 1 &&
373
abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
374
(abs(topMinusBottom) < 1 &&
375
abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
376
(abs(farMinusNear) < 1 &&
377
abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
379
throw Iex::DivzeroExc ("Bad viewing frustum: "
380
"projection matrix cannot be computed.");
385
T tx = -rightPlusLeft / rightMinusLeft;
386
T ty = -topPlusBottom / topMinusBottom;
387
T tz = -farPlusNear / farMinusNear;
389
if ((abs(rightMinusLeft) < 1 &&
390
2 > limits<T>::max() * abs(rightMinusLeft)) ||
391
(abs(topMinusBottom) < 1 &&
392
2 > limits<T>::max() * abs(topMinusBottom)) ||
393
(abs(farMinusNear) < 1 &&
394
2 > limits<T>::max() * abs(farMinusNear)))
396
throw Iex::DivzeroExc ("Bad viewing frustum: "
397
"projection matrix cannot be computed.");
400
T A = 2 / rightMinusLeft;
401
T B = 2 / topMinusBottom;
402
T C = -2 / farMinusNear;
404
return Matrix44<T>( A, 0, 0, 0,
411
T A = rightPlusLeft / rightMinusLeft;
412
T B = topPlusBottom / topMinusBottom;
413
T C = -farPlusNear / farMinusNear;
415
T farTimesNear = -2 * _far * _near;
416
if (abs(farMinusNear) < 1 &&
417
abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
419
throw Iex::DivzeroExc ("Bad viewing frustum: "
420
"projection matrix cannot be computed.");
423
T D = farTimesNear / farMinusNear;
425
T twoTimesNear = 2 * _near;
427
if ((abs(rightMinusLeft) < 1 &&
428
abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
429
(abs(topMinusBottom) < 1 &&
430
abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
432
throw Iex::DivzeroExc ("Bad viewing frustum: "
433
"projection matrix cannot be computed.");
436
T E = twoTimesNear / rightMinusLeft;
437
T F = twoTimesNear / topMinusBottom;
439
return Matrix44<T>( E, 0, 0, 0,
447
Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
449
// move it to 0->1 space
451
Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
452
Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
454
return Frustum<T>(_near, _far, bl.x, tr.x, tr.y, bl.y, _orthographic);
459
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
461
return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
462
_bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
466
Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
468
T leftPlusRight = _left - 2 * p.x + _right;
469
T leftMinusRight = _left-_right;
470
T bottomPlusTop = _bottom - 2 * p.y + _top;
471
T bottomMinusTop = _bottom-_top;
473
if ((abs(leftMinusRight) < 1 &&
474
abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
475
(abs(bottomMinusTop) < 1 &&
476
abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
478
throw Iex::DivzeroExc
479
("Bad viewing frustum: "
480
"local-to-screen transformation cannot be computed");
483
return Vec2<T>( leftPlusRight / leftMinusRight,
484
bottomPlusTop / bottomMinusTop );
488
Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
490
Vec2<T> point = screenToLocal(p);
492
return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
493
Vec3<T>(point.x,point.y,-_near));
495
return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_near));
499
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
501
if (orthographic() || point.z == 0)
502
return localToScreen( Vec2<T>( point.x, point.y ) );
504
return localToScreen( Vec2<T>( point.x * _near / -point.z,
505
point.y * _near / -point.z ) );
509
T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
511
int zdiff = zmax - zmin;
515
throw Iex::DivzeroExc
516
("Bad call to Frustum::ZToDepth: zmax == zmin");
519
if ( zval > zmax+1 ) zval -= zdiff;
521
T fzval = (T(zval) - T(zmin)) / T(zdiff);
522
return normalizedZToDepth(fzval);
526
T Frustum<T>::normalizedZToDepth(T zval) const
528
T Zp = zval * 2.0 - 1;
532
return -(Zp*(_far-_near) + (_far+_near))/2;
536
T farTimesNear = 2 * _far * _near;
537
T farMinusNear = Zp * (_far - _near) - _far - _near;
539
if (abs(farMinusNear) < 1 &&
540
abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
542
throw Iex::DivzeroExc
543
("Frustum::normalizedZToDepth cannot be computed. The "
544
"near and far clipping planes of the viewing frustum "
545
"may be too close to each other");
548
return farTimesNear / farMinusNear;
553
long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
555
long zdiff = zmax - zmin;
556
T farMinusNear = _far-_near;
560
T farPlusNear = 2*depth + _far + _near;
562
if (abs(farMinusNear) < 1 &&
563
abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
565
throw Iex::DivzeroExc
566
("Bad viewing frustum: near and far clipping planes "
567
"are too close to each other");
570
T Zp = -farPlusNear/farMinusNear;
571
return long(0.5*(Zp+1)*zdiff) + zmin;
577
T farTimesNear = 2*_far*_near;
578
if (abs(depth) < 1 &&
579
abs(farTimesNear) > limits<T>::max() * abs(depth))
581
throw Iex::DivzeroExc
582
("Bad call to DepthToZ function: value of `depth' "
586
T farPlusNear = farTimesNear/depth + _far + _near;
587
if (abs(farMinusNear) < 1 &&
588
abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
590
throw Iex::DivzeroExc
591
("Bad viewing frustum: near and far clipping planes "
592
"are too close to each other");
595
T Zp = farPlusNear/farMinusNear;
596
return long(0.5*(Zp+1)*zdiff) + zmin;
601
T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
604
// Consider X-Z plane.
605
// X coord of projection of p = xp = p.x * (-_near / p.z)
606
// Let q be p + (radius, 0, 0).
607
// X coord of projection of q = xq = (p.x - radius) * (-_near / p.z)
608
// X coord of projection of segment from p to q = r = xp - xq
609
// = radius * (-_near / p.z)
610
// A similar analysis holds in the Y-Z plane.
611
// So r is the quantity we want to return.
613
if (abs(p.z) > 1 || abs(-_near) < limits<T>::max() * abs(p.z))
615
return radius * (-_near / p.z);
619
throw Iex::DivzeroExc
620
("Bad call to Frustum::screenRadius: the magnitude of `p' "
624
return radius * (-_near / p.z);
628
T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
630
if (abs(-_near) > 1 || abs(p.z) < limits<T>::max() * abs(-_near))
632
return radius * (p.z / -_near);
636
throw Iex::DivzeroExc
637
("Bad viewing frustum: the near clipping plane is too "
643
void Frustum<T>::planes(Plane3<T> p[6])
646
// Plane order: Top, Right, Bottom, Left, Near, Far.
647
// Normals point outwards.
652
Vec3<T> a( _left, _bottom, -_near);
653
Vec3<T> b( _left, _top, -_near);
654
Vec3<T> c( _right, _top, -_near);
655
Vec3<T> d( _right, _bottom, -_near);
665
p[0].set( Vec3<T>( 0, 1, 0), _top );
666
p[1].set( Vec3<T>( 1, 0, 0), _right );
667
p[2].set( Vec3<T>( 0,-1, 0),-_bottom );
668
p[3].set( Vec3<T>(-1, 0, 0),-_left );
670
p[4].set( Vec3<T>(0, 0, 1), -_near );
671
p[5].set( Vec3<T>(0, 0,-1), _far );
676
void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
679
// Plane order: Top, Right, Bottom, Left, Near, Far.
680
// Normals point outwards.
683
Vec3<T> a = Vec3<T>( _left, _bottom, -_near) * M;
684
Vec3<T> b = Vec3<T>( _left, _top, -_near) * M;
685
Vec3<T> c = Vec3<T>( _right, _top, -_near) * M;
686
Vec3<T> d = Vec3<T>( _right, _bottom, -_near) * M;
689
double s = _far / double(_near);
690
T farLeft = (T) (s * _left);
691
T farRight = (T) (s * _right);
692
T farTop = (T) (s * _top);
693
T farBottom = (T) (s * _bottom);
694
Vec3<T> e = Vec3<T>( farLeft, farBottom, -_far) * M;
695
Vec3<T> f = Vec3<T>( farLeft, farTop, -_far) * M;
696
Vec3<T> g = Vec3<T>( farRight, farTop, -_far) * M;
697
Vec3<T> o = Vec3<T>(0,0,0) * M;
707
Vec3<T> e = Vec3<T>( _left, _bottom, -_far) * M;
708
Vec3<T> f = Vec3<T>( _left, _top, -_far) * M;
709
Vec3<T> g = Vec3<T>( _right, _top, -_far) * M;
710
Vec3<T> h = Vec3<T>( _right, _bottom, -_far) * M;
720
typedef Frustum<float> Frustumf;
721
typedef Frustum<double> Frustumd;
727
#if defined _WIN32 || defined _WIN64
1
///////////////////////////////////////////////////////////////////////////
3
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
6
// All rights reserved.
8
// Redistribution and use in source and binary forms, with or without
9
// modification, are permitted provided that the following conditions are
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
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.
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.
33
///////////////////////////////////////////////////////////////////////////
37
#ifndef INCLUDED_IMATHFRUSTUM_H
38
#define INCLUDED_IMATHFRUSTUM_H
42
#include "ImathPlane.h"
43
#include "ImathLine.h"
44
#include "ImathMatrix.h"
45
#include "ImathLimits.h"
47
#include "IexMathExc.h"
52
// template class Frustum<T>
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.
62
// nearPlane/farPlane: near/far are keywords used by Microsoft's
63
// compiler, so we use nearPlane/farPlane instead to avoid
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);
77
//--------------------
78
// Assignment operator
79
//--------------------
81
const Frustum &operator = (const Frustum &);
83
//--------------------
85
//--------------------
87
bool operator == (const Frustum<T> &src) const;
88
bool operator != (const Frustum<T> &src) const;
90
//--------------------------------------------------------
91
// Set functions change the entire state of the Frustum
92
//--------------------------------------------------------
94
void set(T nearPlane, T farPlane,
99
void set(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
101
//------------------------------------------------------
102
// These functions modify an already valid frustum state
103
//------------------------------------------------------
105
void modifyNearAndFar(T nearPlane, T farPlane);
106
void setOrthographic(bool);
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; }
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
//-----------------------------------------------------------------------
130
void planes(Plane3<T> p[6]);
131
void planes(Plane3<T> p[6], const Matrix44<T> &M);
133
//----------------------
134
// Derived Quantities
135
//----------------------
140
Matrix44<T> projectionMatrix() const;
141
bool degenerate() const;
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
148
//-----------------------------------------------------------------------
150
Frustum<T> window(T left, T right, T top, T bottom) const;
152
//----------------------------------------------------------
153
// Projection is in screen space / Conversion from Z-Buffer
154
//----------------------------------------------------------
156
Line3<T> projectScreenToRay( const Vec2<T> & ) const;
157
Vec2<T> projectPointToScreen( const Vec3<T> & ) const;
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;
163
T worldRadius(const Vec3<T> &p, T radius) const;
164
T screenRadius(const Vec3<T> &p, T radius) const;
169
Vec2<T> screenToLocal( const Vec2<T> & ) const;
170
Vec2<T> localToScreen( const Vec2<T> & ) const;
184
inline Frustum<T>::Frustum()
196
inline Frustum<T>::Frustum(const Frustum &f)
202
inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
208
inline Frustum<T>::Frustum(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
210
set(nearPlane,farPlane,fovx,fovy,aspect);
214
Frustum<T>::~Frustum()
220
Frustum<T>::operator = (const Frustum &f)
222
_nearPlane = f._nearPlane;
223
_farPlane = f._farPlane;
228
_orthographic = f._orthographic;
235
Frustum<T>::operator == (const Frustum<T> &src) const
238
_nearPlane == src._nearPlane &&
239
_farPlane == src._farPlane &&
240
_left == src._left &&
241
_right == src._right &&
243
_bottom == src._bottom &&
244
_orthographic == src._orthographic;
249
Frustum<T>::operator != (const Frustum<T> &src) const
251
return !operator== (src);
255
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
267
void Frustum<T>::modifyNearAndFar(T n, T f)
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 );
280
nearPlane.intersect(lowerLeft,ll);
281
nearPlane.intersect(upperRight,ur);
295
void Frustum<T>::setOrthographic(bool ortho)
297
_orthographic = ortho;
301
void Frustum<T>::set(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
303
if (fovx != 0 && fovy != 0)
304
throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
306
const T two = static_cast<T>(2);
310
_right = nearPlane * Math<T>::tan(fovx / two);
312
_top = ((_right - _left) / aspect) / two;
317
_top = nearPlane * Math<T>::tan(fovy / two);
319
_right = (_top - _bottom) * aspect / two;
322
_nearPlane = nearPlane;
323
_farPlane = farPlane;
324
_orthographic = false;
328
T Frustum<T>::fovx() const
330
return Math<T>::atan2(_right,_nearPlane) - Math<T>::atan2(_left,_nearPlane);
334
T Frustum<T>::fovy() const
336
return Math<T>::atan2(_top,_nearPlane) - Math<T>::atan2(_bottom,_nearPlane);
340
T Frustum<T>::aspect() const
342
T rightMinusLeft = _right-_left;
343
T topMinusBottom = _top-_bottom;
345
if (abs(topMinusBottom) < 1 &&
346
abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
348
throw Iex::DivzeroExc ("Bad viewing frustum: "
349
"aspect ratio cannot be computed.");
352
return rightMinusLeft / topMinusBottom;
356
Matrix44<T> Frustum<T>::projectionMatrix() const
358
T rightPlusLeft = _right+_left;
359
T rightMinusLeft = _right-_left;
361
T topPlusBottom = _top+_bottom;
362
T topMinusBottom = _top-_bottom;
364
T farPlusNear = _farPlane+_nearPlane;
365
T farMinusNear = _farPlane-_nearPlane;
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)))
374
throw Iex::DivzeroExc ("Bad viewing frustum: "
375
"projection matrix cannot be computed.");
380
T tx = -rightPlusLeft / rightMinusLeft;
381
T ty = -topPlusBottom / topMinusBottom;
382
T tz = -farPlusNear / farMinusNear;
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)))
391
throw Iex::DivzeroExc ("Bad viewing frustum: "
392
"projection matrix cannot be computed.");
395
T A = 2 / rightMinusLeft;
396
T B = 2 / topMinusBottom;
397
T C = -2 / farMinusNear;
399
return Matrix44<T>( A, 0, 0, 0,
406
T A = rightPlusLeft / rightMinusLeft;
407
T B = topPlusBottom / topMinusBottom;
408
T C = -farPlusNear / farMinusNear;
410
T farTimesNear = -2 * _farPlane * _nearPlane;
411
if (abs(farMinusNear) < 1 &&
412
abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
414
throw Iex::DivzeroExc ("Bad viewing frustum: "
415
"projection matrix cannot be computed.");
418
T D = farTimesNear / farMinusNear;
420
T twoTimesNear = 2 * _nearPlane;
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)))
427
throw Iex::DivzeroExc ("Bad viewing frustum: "
428
"projection matrix cannot be computed.");
431
T E = twoTimesNear / rightMinusLeft;
432
T F = twoTimesNear / topMinusBottom;
434
return Matrix44<T>( E, 0, 0, 0,
442
bool Frustum<T>::degenerate() const
444
return (_nearPlane == _farPlane) ||
450
Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
452
// move it to 0->1 space
454
Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
455
Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
457
return Frustum<T>(_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
462
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
464
return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
465
_bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
469
Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
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;
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)))
481
throw Iex::DivzeroExc
482
("Bad viewing frustum: "
483
"local-to-screen transformation cannot be computed");
486
return Vec2<T>( leftPlusRight / leftMinusRight,
487
bottomPlusTop / bottomMinusTop );
491
Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
493
Vec2<T> point = screenToLocal(p);
495
return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
496
Vec3<T>(point.x,point.y,-_nearPlane));
498
return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_nearPlane));
502
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
504
if (orthographic() || point.z == T (0))
505
return localToScreen( Vec2<T>( point.x, point.y ) );
507
return localToScreen( Vec2<T>( point.x * _nearPlane / -point.z,
508
point.y * _nearPlane / -point.z ) );
512
T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
514
int zdiff = zmax - zmin;
518
throw Iex::DivzeroExc
519
("Bad call to Frustum::ZToDepth: zmax == zmin");
522
if ( zval > zmax+1 ) zval -= zdiff;
524
T fzval = (T(zval) - T(zmin)) / T(zdiff);
525
return normalizedZToDepth(fzval);
529
T Frustum<T>::normalizedZToDepth(T zval) const
531
T Zp = zval * 2.0 - 1;
535
return -(Zp*(_farPlane-_nearPlane) + (_farPlane+_nearPlane))/2;
539
T farTimesNear = 2 * _farPlane * _nearPlane;
540
T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
542
if (abs(farMinusNear) < 1 &&
543
abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
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");
551
return farTimesNear / farMinusNear;
556
long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
558
long zdiff = zmax - zmin;
559
T farMinusNear = _farPlane-_nearPlane;
563
T farPlusNear = 2*depth + _farPlane + _nearPlane;
565
if (abs(farMinusNear) < 1 &&
566
abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
568
throw Iex::DivzeroExc
569
("Bad viewing frustum: near and far clipping planes "
570
"are too close to each other");
573
T Zp = -farPlusNear/farMinusNear;
574
return long(0.5*(Zp+1)*zdiff) + zmin;
580
T farTimesNear = 2*_farPlane*_nearPlane;
581
if (abs(depth) < 1 &&
582
abs(farTimesNear) > limits<T>::max() * abs(depth))
584
throw Iex::DivzeroExc
585
("Bad call to DepthToZ function: value of `depth' "
589
T farPlusNear = farTimesNear/depth + _farPlane + _nearPlane;
590
if (abs(farMinusNear) < 1 &&
591
abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
593
throw Iex::DivzeroExc
594
("Bad viewing frustum: near and far clipping planes "
595
"are too close to each other");
598
T Zp = farPlusNear/farMinusNear;
599
return long(0.5*(Zp+1)*zdiff) + zmin;
604
T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
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.
616
if (abs(p.z) > 1 || abs(-_nearPlane) < limits<T>::max() * abs(p.z))
618
return radius * (-_nearPlane / p.z);
622
throw Iex::DivzeroExc
623
("Bad call to Frustum::screenRadius: the magnitude of `p' "
627
return radius * (-_nearPlane / p.z);
631
T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
633
if (abs(-_nearPlane) > 1 || abs(p.z) < limits<T>::max() * abs(-_nearPlane))
635
return radius * (p.z / -_nearPlane);
639
throw Iex::DivzeroExc
640
("Bad viewing frustum: the near clipping plane is too "
646
void Frustum<T>::planes(Plane3<T> p[6])
649
// Plane order: Top, Right, Bottom, Left, Near, Far.
650
// Normals point outwards.
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);
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 );
673
p[4].set( Vec3<T>(0, 0, 1), -_nearPlane );
674
p[5].set( Vec3<T>(0, 0,-1), _farPlane );
679
void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
682
// Plane order: Top, Right, Bottom, Left, Near, Far.
683
// Normals point outwards.
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;
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;
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;
723
typedef Frustum<float> Frustumf;
724
typedef Frustum<double> Frustumd;
730
#if defined _WIN32 || defined _WIN64