Line data Source code
1 : /*
2 : * Copyright (c) 2006-2016, Visualization and Multimedia Lab,
3 : * University of Zurich <http://vmml.ifi.uzh.ch>,
4 : * Eyescale Software GmbH,
5 : * Blue Brain Project, EPFL
6 : *
7 : * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions are met:
11 : *
12 : * Redistributions of source code must retain the above copyright notice, this
13 : * list of conditions and the following disclaimer. Redistributions in binary
14 : * form must reproduce the above copyright notice, this list of conditions and
15 : * the following disclaimer in the documentation and/or other materials provided
16 : * with the distribution. Neither the name of the Visualization and Multimedia
17 : * Lab, University of Zurich nor the names of its contributors may be used to
18 : * endorse or promote products derived from this software without specific prior
19 : * written permission.
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : #ifndef __VMML__FRUSTUM__HPP__
34 : #define __VMML__FRUSTUM__HPP__
35 :
36 : #include <vmmlib/matrix.hpp> // used inline
37 : #include <cstring> // memcmp
38 :
39 : namespace vmml
40 : {
41 : /** Represents a frustum, following OpenGL conventions. */
42 : template< typename T > class Frustum
43 : {
44 : public:
45 : /** Construct a default frustum (-1, 1, -1, 1, 0.1, 100). */
46 : Frustum();
47 :
48 : /** Construct a frustum with default values */
49 : Frustum( T left, T right, T bottom, T top, T nearPlane, T farPlane );
50 :
51 : /** Construct a frustum using gluPerspective semantics */
52 : Frustum( T field_of_view_y, T aspect_ratio, T nearPlane_, T farPlane );
53 :
54 : /** Construct a frustum from a projection matrix */
55 : Frustum( const Matrix< 4, 4, T >& projection );
56 :
57 : /** Destruct this frustum */
58 4 : ~Frustum() {}
59 :
60 : /** @return true if this and the other frustum are identical */
61 : bool operator==( const Frustum< T >& other ) const;
62 :
63 : /** @return true if this and the other frustum are not identical */
64 : bool operator!=( const Frustum< T >& other ) const;
65 :
66 : /** @return true if thw two frusta are identical withing the tolerance */
67 : bool equals( const Frustum< T >& other,
68 : T tolerance = std::numeric_limits< T >::epsilon( )) const;
69 :
70 : /** @return the perspective matrix for the given frustum. */
71 : Matrix< 4, 4, T > computePerspectiveMatrix() const;
72 :
73 : /** @return the orthographic matrix for the given frustum. */
74 : Matrix< 4, 4, T > computeOrthoMatrix() const;
75 :
76 : /** Move the frustum near plane by the given offset "sideways" */
77 : void jitter( const vector< 2, T >& jitter_ );
78 :
79 : /**
80 : * Move the frustum near plane.
81 : *
82 : * Changes the position of the nearPlane, adjusting the other parameters in
83 : * a way that the shape of the perspective pyramid stays the same.
84 : */
85 : void adjustNearPlane( const T nearPlane );
86 :
87 : /** @name Access to frustum corners */
88 : //@{
89 : T& left() { return _array[0]; }
90 9 : T left() const { return _array[0]; }
91 :
92 : T& right() { return _array[1]; }
93 9 : T right() const { return _array[1]; }
94 :
95 1 : T& bottom() { return _array[2]; }
96 9 : T bottom() const { return _array[2]; }
97 :
98 1 : T& top() { return _array[3]; }
99 9 : T top() const { return _array[3]; }
100 :
101 4 : T& nearPlane() { return _array[4]; }
102 18 : T nearPlane() const { return _array[4]; }
103 :
104 : T& farPlane() { return _array[5]; }
105 12 : T farPlane() const { return _array[5]; }
106 : //@}
107 :
108 : /** @return the width of this frustum at the near plane */
109 : T getWidth() const;
110 :
111 : /** @return the height of this frustum at the near plane */
112 : T getHeight() const;
113 :
114 0 : friend std::ostream& operator << ( std::ostream& os, const Frustum& f )
115 : {
116 0 : const std::ios::fmtflags flags = os.flags();
117 0 : const int prec = os.precision();
118 :
119 0 : os.setf( std::ios::right, std::ios::adjustfield );
120 0 : os.precision( 5 );
121 0 : os << "[" << std::setw(10) << f.left() << " "
122 0 : << std::setw(10) << f.right() << " "
123 0 : << std::setw(10) << f.bottom() << " "
124 0 : << std::setw(10) << f.top() << " "
125 0 : << std::setw(10) << f.nearPlane() << " "
126 0 : << std::setw(10) << f.farPlane() << "]";
127 0 : os.precision( prec );
128 0 : os.setf( flags );
129 0 : return os;
130 : };
131 :
132 : private:
133 : T _array[6]; //!< left, right, bottom, top, near, far storage
134 : };
135 : } // namespace vmml
136 :
137 : // - implementation - //
138 :
139 : namespace vmml
140 : {
141 :
142 1 : template< typename T > Frustum< T >::Frustum()
143 : {
144 1 : _array[0] = -1;
145 1 : _array[1] = 1;
146 1 : _array[2] = -1;
147 1 : _array[3] = 1;
148 1 : _array[4] = 0.1f;
149 1 : _array[5] = 100;
150 1 : }
151 :
152 : template < typename T >
153 1 : Frustum<T>::Frustum( const T _left, const T _right, const T _bottom,
154 : const T _top, const T _near, const T _far )
155 : {
156 1 : _array[0] = _left;
157 1 : _array[1] = _right;
158 1 : _array[2] = _bottom;
159 1 : _array[3] = _top;
160 1 : _array[4] = _near;
161 1 : _array[5] = _far;
162 1 : }
163 :
164 : template < typename T >
165 1 : Frustum<T>::Frustum( const T fov_y, const T aspect_ratio, const T nearPlane_,
166 : const T farPlane_ )
167 : {
168 1 : _array[2] = std::tan( 0.5 * fov_y * M_PI / 180.0 ) * nearPlane_;
169 1 : _array[3] = -_array[2];
170 : // depend on _array[2,3]:
171 1 : _array[0] = bottom() * aspect_ratio;
172 1 : _array[1] = top() * aspect_ratio;
173 1 : _array[4] = nearPlane_;
174 1 : _array[5] = farPlane_;
175 1 : }
176 :
177 : template < typename T >
178 1 : Frustum<T>::Frustum( const Matrix< 4, 4, T >& projection )
179 : {
180 1 : _array[4] = projection( 2, 3 ) / (projection( 2, 2 ) - 1.0);
181 1 : _array[5] = projection( 2, 3 ) / (projection( 2, 2 ) + 1.0);
182 1 : _array[2] = nearPlane() * ( projection( 1, 2 ) - 1.0 ) / projection( 1, 1 );
183 1 : _array[3] = nearPlane() * ( projection( 1, 2 ) + 1.0 ) / projection( 1, 1 );
184 1 : _array[0] = nearPlane() * ( projection( 0, 2 ) - 1.0 ) / projection( 0, 0 );
185 1 : _array[1] = nearPlane() * ( projection( 0, 2 ) + 1.0 ) / projection( 0, 0 );
186 1 : }
187 :
188 : template < typename T >
189 : bool Frustum<T>::operator==( const Frustum< T >& other ) const
190 : {
191 : return ::memcmp( _array, other._array, sizeof( _array )) == 0;
192 : }
193 :
194 : template < typename T >
195 : bool Frustum<T>::operator!=( const Frustum< T >& other ) const
196 : {
197 : return ::memcmp( _array, other._array, sizeof( _array )) != 0;
198 : }
199 :
200 : template < typename T >
201 1 : bool Frustum<T>::equals( const Frustum< T >& other, const T tolerance ) const
202 : {
203 2 : return std::abs( _array[0] - other._array[0] ) <= tolerance &&
204 2 : std::abs( _array[1] - other._array[1] ) <= tolerance &&
205 2 : std::abs( _array[2] - other._array[2] ) <= tolerance &&
206 2 : std::abs( _array[3] - other._array[3] ) <= tolerance &&
207 3 : std::abs( _array[4] - other._array[4] ) <= tolerance &&
208 2 : std::abs( _array[5] - other._array[5] ) <= tolerance;
209 : }
210 :
211 : template < typename T >
212 3 : Matrix< 4, 4, T > Frustum<T>::computePerspectiveMatrix() const
213 : {
214 3 : Matrix< 4, 4, T > M;
215 :
216 3 : M( 0,0 ) = 2.0 * nearPlane() / ( right() - left() );
217 3 : M( 0,1 ) = 0.0;
218 3 : M( 0,2 ) = ( right() + left() ) / ( right() - left() );
219 3 : M( 0,3 ) = 0.0;
220 :
221 3 : M( 1,0 ) = 0.0;
222 3 : M( 1,1 ) = 2.0 * nearPlane() / ( top() - bottom() );
223 3 : M( 1,2 ) = ( top() + bottom() ) / ( top() - bottom() );
224 3 : M( 1,3 ) = 0.0;
225 :
226 3 : M( 2,0 ) = 0.0;
227 3 : M( 2,1 ) = 0.0;
228 : // NOTE: Some glfrustum man pages say wrongly '(far + near) / (far - near)'
229 3 : M( 2,2 ) = -( farPlane() + nearPlane() ) / ( farPlane() - nearPlane( ));
230 3 : M( 2,3 ) = -2.0 * farPlane() * nearPlane() / (farPlane() - nearPlane());
231 :
232 3 : M( 3,0 ) = 0.0;
233 3 : M( 3,1 ) = 0.0;
234 3 : M( 3,2 ) = -1.0;
235 3 : M( 3,3 ) = 0.0;
236 :
237 3 : return M;
238 : }
239 :
240 : template < typename T >
241 : Matrix< 4, 4, T > Frustum< T >::computeOrthoMatrix() const
242 : {
243 : Matrix< 4, 4, T > M;
244 :
245 : M( 0,0 ) = 2.0 / ( right() - left() );
246 : M( 0,1 ) = 0.0;
247 : M( 0,2 ) = 0.0;
248 : M( 0,3 ) = -( right() + left() ) / ( right() - left() );
249 :
250 : M( 1,0 ) = 0.0;
251 : M( 1,1 ) = 2.0 / ( top() - bottom() );
252 : M( 1,2 ) = 0.0f;
253 : M( 1,3 ) = -( top() + bottom() ) / ( top() - bottom() );
254 :
255 : M( 2,0 ) = 0.0;
256 : M( 2,1 ) = 0.0;
257 : M( 2,2 ) = -2.0 / ( farPlane() - nearPlane() );
258 : M( 2,3 ) = -( farPlane() + nearPlane() ) / ( farPlane() - nearPlane() );
259 :
260 : M( 3,0 ) = 0.0;
261 : M( 3,1 ) = 0.0;
262 : M( 3,2 ) = 0.0;
263 : M( 3,3 ) = 1.0f;
264 :
265 : return M;
266 : }
267 :
268 : template < typename T >
269 : void Frustum< T >::jitter( const vector< 2, T >& jitter_ )
270 : {
271 : left() = left() + jitter_.x();
272 : right() = right() + jitter_.x();
273 : bottom() = bottom() + jitter_.y();
274 : top() = top() + jitter_.y();
275 : }
276 :
277 : template < typename T > void Frustum<T>::adjustNearPlane( const T new_near )
278 : {
279 : if( new_near == nearPlane() )
280 : return;
281 :
282 : const T ratio = new_near / nearPlane();
283 : right() *= ratio;
284 : left() *= ratio;
285 : top() *= ratio;
286 : bottom() *= ratio;
287 : nearPlane() = new_near;
288 : }
289 :
290 : template< typename T > inline T Frustum< T >::getWidth() const
291 : {
292 : return std::abs( right() - left( ));
293 : }
294 :
295 : template< typename T > inline T Frustum< T >::getHeight() const
296 : {
297 : return std::abs( top() - bottom( ));
298 : }
299 :
300 :
301 : } //namespace vmml
302 :
303 : #endif
|