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 <cstring> // memcmp
37 : #include <vmmlib/matrix.hpp> // used inline
38 :
39 : #if defined(_MSC_VER)
40 : //can otherwise cause problems with, e.g., M_PI under Windows.
41 : #define _USE_MATH_DEFINES
42 : #include <cmath>
43 : #ifndef M_PI
44 : #include <corecrt_math_defines.h>
45 : #endif
46 : #else
47 : #ifndef M_PI
48 : #define M_PI 3.1415926535897932
49 : #endif
50 : #endif
51 :
52 : namespace vmml
53 : {
54 : /** Represents a frustum, following OpenGL conventions. */
55 : template <typename T>
56 : class Frustum
57 : {
58 : public:
59 : /** Construct a default frustum (-1, 1, -1, 1, 0.1, 100). */
60 : Frustum();
61 :
62 : /** Construct a frustum with default values */
63 : Frustum(T left, T right, T bottom, T top, T nearPlane, T farPlane);
64 :
65 : /** Construct a frustum using gluPerspective semantics */
66 : Frustum(T field_of_view_y, T aspect_ratio, T nearPlane_, T farPlane);
67 :
68 : /** Construct a frustum from a projection matrix */
69 : Frustum(const Matrix<4, 4, T>& projection);
70 :
71 : /** Destruct this frustum */
72 4 : ~Frustum() {}
73 : /** @return true if this and the other frustum are identical */
74 : bool operator==(const Frustum<T>& other) const;
75 :
76 : /** @return true if this and the other frustum are not identical */
77 : bool operator!=(const Frustum<T>& other) const;
78 :
79 : /** @return true if thw two frusta are identical withing the tolerance */
80 : bool equals(const Frustum<T>& other,
81 : T tolerance = std::numeric_limits<T>::epsilon()) const;
82 :
83 : /** @return the perspective matrix for the given frustum. */
84 : Matrix<4, 4, T> computePerspectiveMatrix() const;
85 :
86 : /** @return the orthographic matrix for the given frustum. */
87 : Matrix<4, 4, T> computeOrthoMatrix() const;
88 :
89 : /** Move the frustum near plane by the given offset "sideways" */
90 : void jitter(const vector<2, T>& jitter_);
91 :
92 : /**
93 : * Move the frustum near plane.
94 : *
95 : * Changes the position of the nearPlane, adjusting the other parameters in
96 : * a way that the shape of the perspective pyramid stays the same.
97 : */
98 : void adjustNearPlane(const T nearPlane);
99 :
100 : /** @name Access to frustum corners */
101 : //@{
102 : T& left() { return _array[0]; }
103 9 : T left() const { return _array[0]; }
104 : T& right() { return _array[1]; }
105 9 : T right() const { return _array[1]; }
106 1 : T& bottom() { return _array[2]; }
107 9 : T bottom() const { return _array[2]; }
108 1 : T& top() { return _array[3]; }
109 9 : T top() const { return _array[3]; }
110 4 : T& nearPlane() { return _array[4]; }
111 18 : T nearPlane() const { return _array[4]; }
112 : T& farPlane() { return _array[5]; }
113 12 : T farPlane() const { return _array[5]; }
114 : //@}
115 :
116 : /** @return the width of this frustum at the near plane */
117 : T getWidth() const;
118 :
119 : /** @return the height of this frustum at the near plane */
120 : T getHeight() const;
121 :
122 0 : friend std::ostream& operator<<(std::ostream& os, const Frustum& f)
123 : {
124 0 : const std::ios::fmtflags flags = os.flags();
125 0 : const int prec = os.precision();
126 :
127 0 : os.setf(std::ios::right, std::ios::adjustfield);
128 0 : os.precision(5);
129 0 : os << "[" << std::setw(10) << f.left() << " " << std::setw(10)
130 0 : << f.right() << " " << std::setw(10) << f.bottom() << " "
131 0 : << std::setw(10) << f.top() << " " << std::setw(10) << f.nearPlane()
132 0 : << " " << std::setw(10) << f.farPlane() << "]";
133 0 : os.precision(prec);
134 0 : os.setf(flags);
135 0 : return os;
136 : };
137 :
138 : private:
139 : T _array[6]; //!< left, right, bottom, top, near, far storage
140 : };
141 : } // namespace vmml
142 :
143 : // - implementation - //
144 :
145 : namespace vmml
146 : {
147 : template <typename T>
148 1 : Frustum<T>::Frustum()
149 : {
150 1 : _array[0] = -1;
151 1 : _array[1] = 1;
152 1 : _array[2] = -1;
153 1 : _array[3] = 1;
154 1 : _array[4] = 0.1f;
155 1 : _array[5] = 100;
156 1 : }
157 :
158 : template <typename T>
159 1 : Frustum<T>::Frustum(const T _left, const T _right, const T _bottom,
160 : const T _top, const T _near, const T _far)
161 : {
162 1 : _array[0] = _left;
163 1 : _array[1] = _right;
164 1 : _array[2] = _bottom;
165 1 : _array[3] = _top;
166 1 : _array[4] = _near;
167 1 : _array[5] = _far;
168 1 : }
169 :
170 : template <typename T>
171 1 : Frustum<T>::Frustum(const T fov_y, const T aspect_ratio, const T nearPlane_,
172 : const T farPlane_)
173 : {
174 1 : _array[2] = std::tan(0.5 * fov_y * M_PI / 180.0) * nearPlane_;
175 1 : _array[3] = -_array[2];
176 : // depend on _array[2,3]:
177 1 : _array[0] = bottom() * aspect_ratio;
178 1 : _array[1] = top() * aspect_ratio;
179 1 : _array[4] = nearPlane_;
180 1 : _array[5] = farPlane_;
181 1 : }
182 :
183 : template <typename T>
184 1 : Frustum<T>::Frustum(const Matrix<4, 4, T>& projection)
185 : {
186 1 : _array[4] = projection(2, 3) / (projection(2, 2) - 1.0);
187 1 : _array[5] = projection(2, 3) / (projection(2, 2) + 1.0);
188 1 : _array[2] = nearPlane() * (projection(1, 2) - 1.0) / projection(1, 1);
189 1 : _array[3] = nearPlane() * (projection(1, 2) + 1.0) / projection(1, 1);
190 1 : _array[0] = nearPlane() * (projection(0, 2) - 1.0) / projection(0, 0);
191 1 : _array[1] = nearPlane() * (projection(0, 2) + 1.0) / projection(0, 0);
192 1 : }
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 : bool Frustum<T>::operator!=(const Frustum<T>& other) const
202 : {
203 : return ::memcmp(_array, other._array, sizeof(_array)) != 0;
204 : }
205 :
206 : template <typename T>
207 1 : bool Frustum<T>::equals(const Frustum<T>& other, const T tolerance) const
208 : {
209 2 : return std::abs(_array[0] - other._array[0]) <= tolerance &&
210 2 : std::abs(_array[1] - other._array[1]) <= tolerance &&
211 2 : std::abs(_array[2] - other._array[2]) <= tolerance &&
212 2 : std::abs(_array[3] - other._array[3]) <= tolerance &&
213 3 : std::abs(_array[4] - other._array[4]) <= tolerance &&
214 2 : std::abs(_array[5] - other._array[5]) <= tolerance;
215 : }
216 :
217 : template <typename T>
218 3 : Matrix<4, 4, T> Frustum<T>::computePerspectiveMatrix() const
219 : {
220 3 : Matrix<4, 4, T> M;
221 :
222 3 : M(0, 0) = 2.0 * nearPlane() / (right() - left());
223 3 : M(0, 1) = 0.0;
224 3 : M(0, 2) = (right() + left()) / (right() - left());
225 3 : M(0, 3) = 0.0;
226 :
227 3 : M(1, 0) = 0.0;
228 3 : M(1, 1) = 2.0 * nearPlane() / (top() - bottom());
229 3 : M(1, 2) = (top() + bottom()) / (top() - bottom());
230 3 : M(1, 3) = 0.0;
231 :
232 3 : M(2, 0) = 0.0;
233 3 : M(2, 1) = 0.0;
234 : // NOTE: Some glfrustum man pages say wrongly '(far + near) / (far - near)'
235 3 : M(2, 2) = -(farPlane() + nearPlane()) / (farPlane() - nearPlane());
236 3 : M(2, 3) = -2.0 * farPlane() * nearPlane() / (farPlane() - nearPlane());
237 :
238 3 : M(3, 0) = 0.0;
239 3 : M(3, 1) = 0.0;
240 3 : M(3, 2) = -1.0;
241 3 : M(3, 3) = 0.0;
242 :
243 3 : return M;
244 : }
245 :
246 : template <typename T>
247 : Matrix<4, 4, T> Frustum<T>::computeOrthoMatrix() const
248 : {
249 : Matrix<4, 4, T> M;
250 :
251 : M(0, 0) = 2.0 / (right() - left());
252 : M(0, 1) = 0.0;
253 : M(0, 2) = 0.0;
254 : M(0, 3) = -(right() + left()) / (right() - left());
255 :
256 : M(1, 0) = 0.0;
257 : M(1, 1) = 2.0 / (top() - bottom());
258 : M(1, 2) = 0.0f;
259 : M(1, 3) = -(top() + bottom()) / (top() - bottom());
260 :
261 : M(2, 0) = 0.0;
262 : M(2, 1) = 0.0;
263 : M(2, 2) = -2.0 / (farPlane() - nearPlane());
264 : M(2, 3) = -(farPlane() + nearPlane()) / (farPlane() - nearPlane());
265 :
266 : M(3, 0) = 0.0;
267 : M(3, 1) = 0.0;
268 : M(3, 2) = 0.0;
269 : M(3, 3) = 1.0f;
270 :
271 : return M;
272 : }
273 :
274 : template <typename T>
275 : void Frustum<T>::jitter(const vector<2, T>& jitter_)
276 : {
277 : left() = left() + jitter_.x();
278 : right() = right() + jitter_.x();
279 : bottom() = bottom() + jitter_.y();
280 : top() = top() + jitter_.y();
281 : }
282 :
283 : template <typename T>
284 : void Frustum<T>::adjustNearPlane(const T new_near)
285 : {
286 : if (new_near == nearPlane())
287 : return;
288 :
289 : const T ratio = new_near / nearPlane();
290 : right() *= ratio;
291 : left() *= ratio;
292 : top() *= ratio;
293 : bottom() *= ratio;
294 : nearPlane() = new_near;
295 : }
296 :
297 : template <typename T>
298 : inline T Frustum<T>::getWidth() const
299 : {
300 : return std::abs(right() - left());
301 : }
302 :
303 : template <typename T>
304 : inline T Frustum<T>::getHeight() const
305 : {
306 : return std::abs(top() - bottom());
307 : }
308 :
309 : } // namespace vmml
310 :
311 : #endif
|