1 /* Copyright Jukka Jyl�nki
2
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7        http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License. */
14
15 /** @file Frustum.h
16         @author Jukka Jyl�nki
17         @brief The Frustum geometry object. */
18 #pragma once
19
20 #include "../MathGeoLibFwd.h"
21 #include "../Math/float2.h"
22 #include "../Math/float3.h"
23 #include "../Math/float3x4.h"
24 #include "../Math/float4x4.h"
25 #include "Ray.h"
26
27 #ifdef MATH_TINYXML_INTEROP
28 #include "Config/tinyxml/tinyxml.h"
29 #endif
30
31 MATH_BEGIN_NAMESPACE
32
33 /// A Frustum can be set to one of the two common different forms.
34 enum FrustumType
35 {
36         InvalidFrustum = 0,
37
38         /// Set the Frustum type to this value to define the orthographic projection formula. In orthographic projection,
39         /// 3D images are projected onto a 2D plane essentially by flattening the object along one direction (the plane normal).
40         /// The size of the projected images appear the same independent of their distance to the camera, and distant objects will 
41         /// not appear smaller. The shape of the Frustum is identical to an oriented bounding box (OBB).
42         OrthographicFrustum,
43
44         /// Set the Frustum type to this value to use the perspective projection formula. With perspective projection, the 2D
45         /// image is formed by projecting 3D points towards a single point (the eye point/tip) of the Frustum, and computing the
46         /// point of intersection of the line of the projection and the near plane of the Frustum.
47         /// This corresponds to the optics in the real-world, and objects become smaller as they move to the distance.
48         /// The shape of the Frustum is a rectangular pyramid capped from the tip.
49         PerspectiveFrustum
50 };
51
52 /// The Frustum class offers choosing between the two common conventions for the value ranges in 
53 /// post-projection space. If you are using either the OpenGL or Diret3D API, you must feed the API data that matches
54 /// the correct convention.
55 enum FrustumProjectiveSpace
56 {
57         FrustumSpaceInvalid = 0,
58
59         /// If this option is chosen, the post-projective unit cube of the Frustum
60         /// is modelled after the OpenGL API convention, meaning that in projected space,
61         /// points inside the Frustum have the X and Y range in [-1, 1], and Z ranges in [-1, 1],
62         /// where the near plane maps to Z=-1, and the far plane maps to Z=1.
63         /// @note If you are submitting projection matrices to GPU hardware using the OpenGL API, you *must*
64         ///       use this convention. (or otherwise more than half of the precision of the GL depth buffer is wasted)
65         FrustumSpaceGL,
66
67         /// If this option is chosen, the post-projective unit cube is modelled after the
68         /// Direct3D API convention, which differs from the GL convention that Z ranges in [0, 1] instead.
69         /// Near plane maps to Z=0, and far plane maps to Z=1. The X and Y range in [-1, 1] as is with GL.
70         /// @note If you are submitting projection matrices to GPU hardware using the Direct3D API, you *must*
71         ///       use this convention. (or otherwise objects will clip too near of the camera)
72         FrustumSpaceD3D
73 };
74
75 /// The handedness rule in MathGeoLib bundles together two different conventions related to the camera:
76 ///    the chirality of the world and view spaces, and the fixed local front direction of the Frustum.
77 /// @note The world and view spaces are always assumed to the same chirality, meaning that Frustum::ViewMatrix()
78 ///       (and hence Frustum::WorldMatrix()) always returns a matrix with a positive determinant, i.e. it does not mirror.
79 ///       If FrustumRightHanded is chosen, then Frustum::ProjectionMatrix() is a mirroring matrix, since the post-projective space
80 ///       is always left-handed.
81 /// @note Even though in the local space of the camera +Y is always up, in the world space one can use any 'world up' direction
82 ///       as one pleases, by orienting the camera via the Frustum::up vector.
83 enum FrustumHandedness
84 {
85         FrustumHandednessInvalid = 0,
86
87         /// If a Frustum is left-handed, then in the local space of the Frustum (the view space), the camera looks towards +Z,
88         /// while +Y goes towards up, and +X goes towards right.
89         /// @note The fixed-pipeline D3D9 API traditionally used the FrustumLeftHanded convention.
90         FrustumLeftHanded,
91
92         /// If a Frustum is right-handed, then the camera looks towards -Z, +Y is up, and +X is right.
93         /// @note The fixed-pipeline OpenGL API traditionally used the FrustumRightHanded convention.
94         FrustumRightHanded
95 };
96
97 /// Represents either an orthographic or a perspective viewing frustum.
98 class Frustum
99 {
100 private:
101         /// Specifies whether this frustum is a perspective or an orthographic frustum.
102         /** [noscript] @todo Remove the noscript attribute. */
103         FrustumType type;
104         /// Specifies whether the [-1,1] or [0,1] range is used for the post-projective depth range.
105         FrustumProjectiveSpace projectiveSpace;
106         /// Specifies the chirality of world and view spaces.
107         FrustumHandedness handedness;
108         /// The eye point of this frustum.
109         /** Specifies the position of the camera (the eye point) for this frustum in world (global) space. */
110         vec pos;
111         /// The normalized direction this frustum is watching towards. [similarOverload: pos]
112         /** This vector is specified in world (global) space. This vector is always normalized.
113                 If you assign to this member directly, be sure to only assign normalized vectors. */
114         vec front;
115         /// The normalized up direction for this frustum. [similarOverload: pos]
116         /** This vector is specified in world (global) space. This vector is always normalized.
117                 If you assign to this member directly, be sure to only assign normalized vectors.
118                 @note The vectors front and up must always be perpendicular to each other. This means that this up vector is not
119                 a static/constant up vector, e.g. (0,1,0), but changes according to when the camera pitches up and down to
120                 preserve the condition that front and up are always perpendicular.
121                 @note In the _local_ space of the Frustum, the direction +Y is _always_ the up direction and cannot be changed. This
122                 coincides to how Direct3D and OpenGL view and projection matrices are constructed. */
123         vec up;
124         /// Distance from the eye point to the front plane.
125         /** This parameter must be positive. If perspective projection is used, this parameter must be strictly positive
126                 (0 is not allowed). If orthographic projection is used, 0 is possible (but uncommon, and not recommended).
127                 When using the Frustum class to derive perspective projection matrices for a GPU, it should be noted that too
128                 small values cause poor resolution of Z values near the back plane in post-perspective space, if non-linear
129                 depth is used (which is common). The larger this value is, the more resolution there is for the Z values across the
130                 depth range. Too large values cause clipping of geometry when they come very near the camera. */
131         float nearPlaneDistance;
132         /// Distance from the eye point to the back plane of the projection matrix. [similarOverload: nearPlaneDistance]
133         /** This parameter must be strictly greater than nearPlaneDistance. The range [nearPlaneDistance, farPlaneDistance]
134                 specifies the visible range of objects inside the Frustum. When using the Frustum class for deriving perspective
135                 projection matrix for GPU rendering, it should be remembered that any geometry farther from the camera (in Z value)
136                 than this distance will be clipped from the view, and not rendered. */
137         float farPlaneDistance;
138         union
139         {
140                 /// Horizontal field-of-view, in radians. This field is only valid if type == PerspectiveFrustum.
141                 /** @see type. */
142                 float horizontalFov;
143                 /// The width of the orthographic frustum. This field is only valid if type == OrthographicFrustum.
144                 /** @see type. */
145                 float orthographicWidth;
146         };
147         union
148         {
149                 /// Vertical field-of-view, in radians. This field is only valid if type == PerspectiveFrustum.
150                 /** @see type. */
151                 float verticalFov;
152                 /// The height of the orthographic frustum. This field is only valid if type == OrthographicFrustum.
153                 /** @see type. */
154                 float orthographicHeight;
155         };
156
157         void WorldMatrixChanged();
158         void ProjectionMatrixChanged();
159
160         // Frustums are typically used in batch culling operations. Therefore the matrices associated with a Frustum are cached
161         // for immediate access.
162         float3x4 worldMatrix;
163         float4x4 projectionMatrix;
164         float4x4 viewProjMatrix;
165
166 public:
167         /// The default constructor creates an uninitialized Frustum object.
168         /** This means that the values of the members type, projectiveSpace, handedness, pos, front, up, nearPlaneDistance, farPlaneDistance, horizontalFov/orthographicWidth and
169                 verticalFov/orthographicHeight are all NaN after creating a new Frustum using this
170                 default constructor. Remember to assign to them before use.
171                 @note As an exception to other classes in MathGeoLib, this class initializes its members to NaNs, whereas the other classes leave the members uninitialized. This difference
172                         is because the Frustum class implements a caching mechanism where world, projection and viewProj matrices are recomputed on demand, which does not work nicely together
173                         if the defaults were uninitialized.
174                 [opaque-qtscript] @todo remove the opaque-qtscript attribute.
175                 @see type, pos, front, up, nearPlaneDistance, projectiveSpace, handedness, farPlaneDistance, horizontalFov, verticalFov, orthographicWidth, orthographicHeight. */
176         Frustum();
177
178         /// Sets the type of this Frustum.
179         /** @note Calling this function recomputes the cached view and projection matrices of this Frustum.
180                 @see SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), ProjectiveSpace(), Handedness(). */
181         void SetKind(FrustumProjectiveSpace projectiveSpace, FrustumHandedness handedness);
182
183         /// Sets the depth clip distances of this Frustum.
184         /** @param nearPlaneDistance The z distance from the eye point to the position of the Frustum near clip plane. Always pass a positive value here.
185                 @param farPlaneDistance The z distance from the eye point to the position of the Frustum far clip plane. Always pass a value that is larger than nearClipDistance.
186                 @note Calling this function recomputes the cached projection matrix of this Frustum.
187                 @see SetKind(), SetFrame(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), NearPlaneDistance(), FarPlaneDistance(). */
188         void SetViewPlaneDistances(float nearPlaneDistance, float farPlaneDistance);
189
190         /// Specifies the full coordinate space of this Frustum in one call.
191         /** @note Calling this function recomputes the cached world matrix of this Frustum.
192                 @note As a micro-optimization, prefer this function over the individual SetPos/SetFront/SetUp functions if you need to do a batch of two or more changes, to avoid
193                 redundant recomputation of the world matrix.
194                 @see SetKind(), SetViewPlaneDistances(), SetPos(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), Pos(), Front(), Up(). */
195         void SetFrame(const vec &pos, const vec &front, const vec &up);
196
197         /// Sets the world-space position of this Frustum.
198         /** @note Calling this function recomputes the cached world matrix of this Frustum.
199                 @see SetKind(), SetViewPlaneDistances(), SetFrame(), SetFront(), SetUp(), SetPerspective(), SetOrthographic(), Pos(). */
200         void SetPos(const vec &pos);
201
202         /// Sets the world-space direction the Frustum eye is looking towards.
203         /** @note Calling this function recomputes the cached world matrix of this Frustum.
204                 @see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetUp(), SetPerspective(), SetOrthographic(), Front(). */
205         void SetFront(const vec &front);
206
207         /// Sets the world-space camera up direction vector of this Frustum.
208         /** @note Calling this function recomputes the cached world matrix of this Frustum.
209                 @see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetPerspective(), SetOrthographic(), Up(). */
210         void SetUp(const vec &up);
211
212         /// Makes this Frustum use a perspective projection formula with the given FOV parameters.
213         /** A Frustum that uses the perspective projection is shaped like a pyramid that is cut from the top, and has a
214                 base with a rectangular area.
215                 @note Calling this function recomputes the cached projection matrix of this Frustum.
216                 @see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetOrthographic(), HorizontalFov(), VerticalFov(), SetHorizontalFovAndAspectRatio(), SetVerticalFovAndAspectRatio(). */
217         void SetPerspective(float horizontalFovfloat verticalFov);
218
219         /// Makes this Frustum use an orthographic projection formula with the given FOV parameters.
220         /** A Frustum that uses the orthographic projection is shaded like a cube (an OBB).
221                 @note Calling this function recomputes the cached projection matrix of this Frustum.
222                 @see SetKind(), SetViewPlaneDistances(), SetFrame(), SetPos(), SetFront(), SetUp(), SetOrthographic(), OrthographicWidth(), OrthographicHeight(). */
223         void SetOrthographic(float orthographicWidthfloat orthographicHeight);
224
225         /// Returns the handedness of the projection formula used by this Frustum.
226         /** @see SetKind(), FrustumHandedness. */
227         FrustumHandedness Handedness() const return handedness; }
228
229         /// Returns the type of the projection formula used by this Frustum.
230         /** @see SetPerspective(), SetOrthographic(), FrustumType. */
231         FrustumType Type() const return type; }
232
233         /// Returns the convention of the post-projective space used by this Frustum.
234         /** @see SetKind(), FrustumProjectiveSpace. */
235         FrustumProjectiveSpace ProjectiveSpace() const return projectiveSpace; }
236
237         /// Returns the world-space position of this Frustum.
238         /** @see SetPos(), Front(), Up(). */
239         const vec &Pos() const return pos; }
240
241         /// Returns the world-space camera look-at direction of this Frustum.
242         /** @see Pos(), SetFront(), Up(). */
243         const vec &Front() const return front; }
244
245         /// Returns the world-space camera up direction of this Frustum.
246         /** @see Pos(), Front(), SetUp(). */
247         const vec &Up() const return up; }
248
249         /// Returns the distance from the Frustum eye to the near clip plane.
250         /** @see SetViewPlaneDistances(), FarPlaneDistance(). */
251         float NearPlaneDistance() const return nearPlaneDistance; }
252
253         /// Returns the distance from the Frustum eye to the far clip plane.
254         /** @see SetViewPlaneDistances(), NearPlaneDistance(). */
255         float FarPlaneDistance() const return farPlaneDistance; }
256
257         /// Returns the horizontal field-of-view used by this Frustum, in radians.
258         /** @note Calling this function when the Frustum is not set to use perspective projection will return values that are meaningless.
259                 @see SetPerspective(), Type(), VerticalFov(). */
260         float HorizontalFov() const return horizontalFov; }
261
262         /// Returns the vertical field-of-view used by this Frustum, in radians.
263         /** @note Calling this function when the Frustum is not set to use perspective projection will return values that are meaningless.
264                 @see SetPerspective(), Type(), HorizontalFov(). */
265         float VerticalFov() const return verticalFov; }
266
267         /// Returns the world-space width of this Frustum.
268         /** @note Calling this function when the Frustum is not set to use orthographic projection will return values that are meaningless.
269                 @see SetOrthographic(), Type(), OrthographicHeight(). */
270         float OrthographicWidth() const return orthographicWidth; }
271
272         /// Returns the world-space height of this Frustum.
273         /** @note Calling this function when the Frustum is not set to use orthographic projection will return values that are meaningless.
274                 @see SetOrthographic(), Type(), OrthographicWidth(). */
275         float OrthographicHeight() const return orthographicHeight; }
276
277         /// Returns the number of line segment edges that this Frustum is made up of, which is always 12.
278         /** This function is used in template-based algorithms to provide an unified API for iterating over the features of a Polyhedron. */
279         int NumEdges() const return 12; }
280
281         /// Returns the aspect ratio of the view rectangle on the near plane.
282         /** The aspect ratio is the ratio of the width of the viewing rectangle to its height. This can also be computed by
283                 the expression horizontalFov / verticalFov. To produce a proper non-stretched image when rendering, this
284                 aspect ratio should match the aspect ratio of the actual render target (e.g. 4:3, 16:9 or 16:10 in full screen mode).
285                 @see horizontalFov, verticalFov. */
286         float AspectRatio() const;
287
288         /// Makes this Frustum use a perspective projection formula with the given horizontal FOV parameter and aspect ratio.
289         /** Specifies the horizontal and vertical field-of-view values for this Frustum based on the given horizontal FOV
290                 and the screen size aspect ratio.
291                 @note Calling this function recomputes the cached projection matrix of this Frustum.
292                 @see SetPerspective(), SetVerticalFovAndAspectRatio(). */
293         void SetHorizontalFovAndAspectRatio(float horizontalFovfloat aspectRatio);
294
295         /// Makes this Frustum use a perspective projection formula with the given vertical FOV parameter and aspect ratio.
296         /** Specifies the horizontal and vertical field-of-view values for this Frustum based on the given vertical FOV
297                 and the screen size aspect ratio.
298                 @note Calling this function recomputes the cached projection matrix of this Frustum.
299                 @see SetPerspective(), SetHorizontalFovAndAspectRatio(). */
300         void SetVerticalFovAndAspectRatio(float verticalFovfloat aspectRatio);
301
302         /// Computes the direction vector that points logically to the right-hand side of the Frustum.
303         /** This vector together with the member variables 'front' and 'up' form the orthonormal basis of the view frustum.
304                 @see pos, front. */
305         vec WorldRight() const;
306
307         /// Computes the plane equation of the near plane of this Frustum.
308         /** The normal vector of the returned plane points outwards from the volume inside the frustum, i.e. towards the eye point
309                 (towards -front). This means the negative half-space of the Frustum is the space inside the Frustum.
310                 @see front, FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(), GetPlane(), GetPlanes(). */
311         Plane NearPlane() const;
312
313         /// Computes the width of the near plane quad in world space units.
314         /** @see NearPlaneHeight(). */
315         float NearPlaneWidth() const;
316
317         /// Computes the height of the near plane quad in world space units.
318         /** @see NearPlaneHeight(). */
319         float NearPlaneHeight() const;
320
321         /// Computes the plane equation of the far plane of this Frustum. [similarOverload: NearPlane]
322         /** The normal vector of the returned plane points outwards from the volume inside the frustum, i.e. away from the eye point.
323                 (towards front). This means the negative half-space of the Frustum is the space inside the Frustum.
324                 @see front, FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(), GetPlane(), GetPlanes(). */
325         Plane FarPlane() const;
326
327         /// Returns the plane equation of the specified side of this Frustum.
328         /** The normal vector of the returned plane points outwards from the volume inside the frustum.
329                 This means the negative half-space of the Frustum is the space inside the Frustum.
330                 [indexTitle: Left/Right/Top/BottomPlane]
331                 @see NearPlane(), FarPlane(), GetPlane(), GetPlanes(). */
332         Plane LeftPlane() const;
333         Plane RightPlane() const///< [similarOverload: LeftPlane] [hideIndex]
334         Plane TopPlane() const///< [similarOverload: LeftPlane] [hideIndex]
335         Plane BottomPlane() const///< [similarOverload: LeftPlane] [hideIndex]
336
337         /// Returns the specified plane of this frustum.
338         /** The normal vector of the returned plane points outwards from the volume inside the frustum.
339                 @param faceIndex A number in the range [0,5], which returns the plane at the selected index from
340                         the array { near, far, left, right, top, bottom }.
341                 @see GetPlanes(), NearPlane(), FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(). */
342         Plane GetPlane(int faceIndex) const;
343
344         /// Returns all six planes of this Frustum.
345         /** The planes will be output in the order { near, far, left, right, top, bottom }.
346                 @param outArray [out] A pointer to an array of at least 6 elements. This pointer will receive the planes of this Frustum.
347                         This pointer may not be null.
348                 @see GetPlane(), NearPlane(), FarPlane(), LeftPlane(), RightPlane(), TopPlane(), BottomPlane(). */
349         void GetPlanes(Plane *outArray) const;
350
351         vec CenterPoint() const;
352
353         /// Returns an edge of this Frustum.
354         /** @param edgeIndex The index of the edge line segment to get, in the range [0, 11].
355                 @todo Draw a diagram that shows which index generates which edge.
356                 @see PointInside(), CornerPoint(), PointOnEdge(), FaceCenterPoint(), FacePoint(). */
357         LineSegment Edge(int edgeIndex) const;
358
359         /// Generates one of the eight corner points of this Frustum.
360         /** @param cornerIndex The index of the corner point to generate, in the range [0, 7].
361                  The points are returned in the order 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++.
362                  (corresponding the XYZ axis directions). */
363         vec CornerPoint(int cornerIndex) const;
364
365         /// Returns all eight corner points of this array.
366         /** @param outPointArray [out] A pointer to an array of at least 8 elements. This pointer will receive the corner vertices
367                         of this Frustum. This pointer may not be null. */
368         void GetCornerPoints(vec *outPointArray) const;
369
370         /// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
371         inline vec AnyPointFast() const return CornerPoint(0); }
372
373         /// Computes an extreme point of this Frustum in the given direction.
374         /** An extreme point is a farthest point of this Frustum in the given direction. Given a direction,
375                 this point is not necessarily unique.
376                 @param direction The direction vector of the direction to find the extreme point. This vector may
377                         be unnormalized, but may not be null.
378                 @return An extreme point of this Frustum in the given direction. The returned point is always a
379                         corner point of this Frustum.
380                 @see CornerPoint(). */
381         vec ExtremePoint(const vec &direction) const float projectionDistance; return ExtremePoint(direction, projectionDistance); }
382         vec ExtremePoint(const vec &direction, float &projectionDistance) const;
383
384         /// Projects this Frustum onto the given 1D axis direction vector.
385         /** This function collapses this Frustum onto an 1D axis for the purposes of e.g. separate axis test computations.
386                 The function returns a 1D range [outMin, outMax] denoting the interval of the projection.
387                 @param direction The 1D axis to project to. This vector may be unnormalized, in which case the output
388                         of this function gets scaled by the length of this vector.
389                 @param outMin [out] Returns the minimum extent of this object along the projection axis.
390                 @param outMax [out] Returns the maximum extent of this object along the projection axis. */
391         void ProjectToAxis(const vec &direction, float &outMin, float &outMax) const;
392
393         int UniqueFaceNormals(vec *out) const;
394         int UniqueEdgeDirections(vec *out) const;
395
396         /// Sets the pos, front and up members of this frustum from the given world transform.
397         /** This function sets the 'front' parameter of this Frustum to look towards the -Z/+Z axis of the given matrix
398                 depending on the handedness set to the Frustum,
399                 and the 'up' parameter of this Frustum to point towards the +Y axis of the given matrix.
400                 @param worldTransform An orthonormalized matrix with determinant of +1 (no mirroring). */
401         void SetWorldMatrix(const float3x4 &worldTransform);
402
403         /// Computes the matrix that transforms from the view space to the world (global) space of this Frustum.
404         /** @note The returned matrix is the inverse of the matrix returned by ViewMatrix().
405                 @return An orthonormal affine matrix that performs the view->world transformation. The returned
406                         matrix is built to use the convention Matrix * vector to map a point between these spaces.
407                         (as opposed to the convention v*M).
408                 @see ViewMatrix(), ProjectionMatrix(), ViewProjMatrix(). */
409         float3x4 WorldMatrix() const return worldMatrix;  }
410         float3x4 ComputeWorldMatrix() const;
411
412         /// Computes the matrix that transforms from the world (global) space to the view space of this Frustum.
413         /** @note The returned matrix is the inverse of the matrix returned by WorldMatrix().
414                 @return An orthonormal affine matrix that performs the world->view transformation. The returned
415                         matrix is built to use the convention Matrix * vector to map a point between these spaces.
416                         (as opposed to the convention v*M).
417                 @see WorldMatrix(), ProjectionMatrix(), ViewProjMatrix(). */
418         float3x4 ViewMatrix() const float3x4 m = worldMatrix; m.InverseOrthonormal(); return m; }
419         float3x4 ComputeViewMatrix() const;
420
421         /// Computes the matrix that projects from the view space to the projection space of this Frustum.
422         /** @return A projection matrix that performs the view->proj transformation. This matrix is neither
423                         invertible or orthonormal. The returned matrix is built to use the convention Matrix * vector
424                         to map a point between these spaces. (as opposed to the convention v*M).
425                 @see WorldMatrix(), ViewMatrix(), ViewProjMatrix(). */
426         float4x4 ProjectionMatrix() const return projectionMatrix; }
427         float4x4 ComputeProjectionMatrix() const;
428
429         /// Computes the matrix that transforms from the world (global) space to the projection space of this Frustum.
430         /** The matrix computed by this function is simply the concatenation ProjectionMatrix()*ViewMatrix(). This order
431                 of concatenation follows the M*v convention of transforming vectors (as opposed to the v*M convention). This
432                 multiplication order is used, since the matrices ProjectionMatrix() and ViewMatrix() also follow the M*v convention.
433                 @return A matrix that performs the world->view->proj transformation. This matrix is neither invertible or
434                         orthonormal. The returned matrix is built to use the convention Matrix * vector
435                         to map a point between these spaces. (as opposed to the convention v*M).
436                 @see WorldMatrix(), ViewMatrix(), ProjectionMatrix(). */
437         float4x4 ViewProjMatrix() const return viewProjMatrix; }
438         float4x4 ComputeViewProjMatrix() const;
439
440         /// Finds a ray in world space that originates at the eye point and looks in the given direction inside the frustum.
441         /** The (x,y) coordinate specifies the normalized viewport coordinate through which the ray passes.
442                 Both x and y must be in the range [-1,1].
443                 Specifying (-1, -1) returns the bottom-left corner of the near plane.
444                 The point (1, 1) corresponds to the top-right corner of the near plane. */
445         Ray UnProject(float x, float y) const;
446         Ray UnProject(const float2 &xy) const return UnProject(xy.x, xy.y); }
447
448         ///\todo Add float3 UnProject(const float3 &point) const;
449         /** Like UnProject, but if the frustum type is PerspectiveFrustum, the ray originates at the near plane,
450                 and not at the camera eye point. For orthographic frustum, LookAt and LookAtFromNearPlane are identical
451                 (always originates at near plane). */
452         Ray UnProjectFromNearPlane(float x, float y) const;
453
454         /// Returns the world-space line segment of the points that project to the given normalized viewport coordinate (x,y).
455         /** The (x,y) coordinate specifies the normalized viewport coordinate through which the line segment passes.
456                 Both x and y must be in the range [-1,1]. */
457         LineSegment UnProjectLineSegment(float x, float y) const;
458
459         /// Returns a point inside this frustum parameterized by three scalar coordinates.
460         /** @param x The horizontal normalized viewport coordinate in the range [-1, 1].
461                 @param y The vertical normalized viewport coordinate in the range [-1, 1].
462                 @param z The linear depth coordinate in the range [0, 1].
463                 @note This function is slightly different than multiplying by inv(view*proj), since depth is handled linearly.
464                 @see FastRandomPointInside(), UniformRandomPointInside(). */
465         vec PointInside(float x, float y, float z) const;
466         vec PointInside(const vec &xyz) const return PointInside(xyz.x, xyz.y, xyz.z); }
467
468         /// Projects the given point onto the near plane of this frustum.
469         /** The (x,y) component of the returned vector gives the normalized viewport coordinates of the point on the
470                 near plane. The z component gives the normalized depth of the point.
471                 If the point is inside the frustum, x and y are in the range [-1, 1] and z is in the range [0, 1]. If the point
472                 was behind the near plane, z will return a negative value. If the point lies exactly on the near plane, z==0
473                 will be returned. If the point lies exactly on the far plane, z==1 will be returned, and if a z>1 is returned,
474                 the given point was outside the far plane of this Frustum.
475                 @param point A point in world space to project onto the near plane of this frustum.
476                 @return The normalized 2D (x,y) coordinate of the given point projected onto the near plane of this Frustum.
477                         The z coordinate specifies the normalized (linear) depth of the projected point. */
478         vec Project(const vec &point) const;
479
480         /// Returns a point on the near plane.
481         /** @param x A value in the range [-1, 1].
482                 @param y A value in the range [-1, 1].
483                 Specifying (-1, -1) returns the bottom-left corner of the near plane.
484                 The point (1, 1) corresponds to the top-right corner of the near plane.
485                 @note This coordinate space is called the normalized viewport coordinate space.
486                 @see FarPlanePos(). */
487         vec NearPlanePos(float x, float y) const;
488         vec NearPlanePos(const float2 &point) const;
489
490         /// Returns a point on the far plane.
491         /** @param x A value in the range [-1, 1].
492                 @param y A value in the range [-1, 1].
493                 Specifying (-1, -1) returns the bottom-left corner of the far plane.
494                 The point (1, 1) corresponds to the top-right corner of the far plane.
495                 @note This coordinate space is called the normalized viewport coordinate space.
496                 @see NearPlanePos(). */
497         vec FarPlanePos(float x, float y) const;
498         vec FarPlanePos(const float2 &point) const;
499
500         /// Maps a point from the normalized viewport space to the screen space.
501         /** In normalized viewport space, top-left: (-1, 1), top-right: (1, 1), bottom-left: (-1, -1), bottom-right: (-1, 1).
502                 In screen space, top-left: (0, 0), top-right: (0, screenWidth-1), bottom-left: (0, screenHeight-1), bottom-right: (screenWidth-1, screenHeight-1).
503                 This mapping is affine.
504                 @see ScreenToViewportSpace(). */
505         static float2 ViewportToScreenSpace(float x, float y, int screenWidth, int screenHeight);
506         static float2 ViewportToScreenSpace(const float2 &point, int screenWidth, int screenHeight);
507
508         /// Maps a point from screen space to normalized viewport space.
509         /** This function computes the inverse function of ViewportToScreenSpace(). This mapping is affine.
510                 @see ViewportToScreenSpace(). */
511         static float2 ScreenToViewportSpace(float x, float y, int screenWidth, int screenHeight);
512         static float2 ScreenToViewportSpace(const float2 &point, int screenWidth, int screenHeight);
513
514         /// Tests if this Frustum is finite.
515         /** A Frustum is <b><i>finite</i></b> if none of its member variables contain floating-point NaNs or +/-infs
516                 in them.
517                 @return True if each member variable has a finite floating-point value.
518                 @see type, pos, front, up, nearPlaneDistance, farPlaneDistance, horizontalFov, verticalFov, orthographicWidth, orthographicHeight.
519                 @todo Implement IsDegenerate(). */
520         bool IsFinite() const;
521
522         /// Computes the volume of this Frustum.
523         float Volume() const;
524
525         /// Quickly generates a random point inside this Frustum.
526         /** If the frustum type is orthographic, then the points are uniformly distributed. If the frustum type is perspective, then not.
527                 @see class LCG, UniformRandomPointInside(), PointInside(). */
528         vec FastRandomPointInside(LCG &rng) const;
529
530         /// Generates a uniformly random point inside this Frustum.
531         /** For orthographic frustum type, this function is identical to FastRandomPointInside.
532                 @see class LCG, FastRandomPointInside(), PointInside(). */
533         vec UniformRandomPointInside(LCG &rng) const;
534
535         /// Moves this Frustum by the given offset vector.
536         /** @note This function operates in-place.
537                 @param offset The world space offset to apply to the position of this Frustum.
538                 @see Transform(). */
539         void Translate(const vec &offset);
540
541         /// Applies a transformation to this Frustum.
542         /** @param transform The transformation to apply to this Frustum. This transformation must be
543                 affine, and must contain an orthogonal set of column vectors (may not contain shear or projection).
544                 The transformation can only contain uniform scale, and may not contain mirroring.
545                 @see Translate(), Scale(), classes float3x3, float3x4, float4x4, Quat. */
546         void Transform(const float3x3 &transform);
547         void Transform(const float3x4 &transform);
548         void Transform(const float4x4 &transform);
549         void Transform(const Quat &transform);
550
551         /// Returns the tightest AABB that contains this Frustum.
552         /** This function computes the optimal minimum volume AABB that encloses this Frustum.
553                 @note Since an AABB cannot generally represent a Frustum, this conversion is not exact, but the returned AABB
554                         specifies a larger volume.                      
555                 @see MinimalEnclosingOBB(), ToPolyhedron(). */
556         AABB MinimalEnclosingAABB() const;
557
558         /// Returns the tightest OBB that encloses this Frustum.
559         /** This function computes the optimal minimum volume OBB that encloses this Frustum.
560                 @note If the type of this frustum is Perspective, this conversion is not exact, but the returned OBB specifies
561                         a larger volume. If the type of this Frustum is orthographic, this conversion is exact, since the shape of an
562                         orthographic Frustum is an OBB.
563                 @see MinimalEnclosingAABB(), ToPolyhedron(). */
564         OBB MinimalEnclosingOBB(float expandGuardband = 1e-5f) const;
565
566         /// Converts this Frustum to a Polyhedron.
567         /** This function returns a Polyhedron representation of this Frustum. This conversion is exact, meaning that the returned
568                 Polyhedron represents exactly the same set of points that this Frustum does.
569                 @see MinimalEnclosingAABB(), MinimalEnclosingOBB(). */
570         Polyhedron ToPolyhedron() const;
571
572         /// Converts this Frustum to a PBVolume.
573         /** This function returns a plane-bounded volume representation of this Frustum. The conversion is exact, meaning that the
574                 returned PBVolume<6> represents exactly the same set of points that this Frustum does.
575                 @see ToPolyhedron(). */
576         PBVolume<6> ToPBVolume() const;
577
578         /// Tests if the given object is fully contained inside this Frustum.
579         /** This function returns true if the given object lies inside this Frustum, and false otherwise.
580                 @note The comparison is performed using less-or-equal, so the faces of this Frustum count as being inside, but
581                         due to float inaccuracies, this cannot generally be relied upon.
582                 @todo Add Contains(Circle/Disc/Sphere/Capsule).
583                 @see Distance(), Intersects(), ClosestPoint(). */
584         bool Contains(const vec &point) const;
585         bool Contains(const LineSegment &lineSegment) const;
586         bool Contains(const Triangle &triangle) const;
587         bool Contains(const Polygon &polygon) const;
588         bool Contains(const AABB &aabb) const;
589         bool Contains(const OBB &obb) const;
590         bool Contains(const Frustum &frustum) const;
591         bool Contains(const Polyhedron &polyhedron) const;
592
593         /// Computes the closest point inside this Frustum to the given point.
594         /** If the target point lies inside this Frustum, then that point is returned.
595                 @see Distance(), Contains(), Intersects().
596                 @todo Add ClosestPoint(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Sphere/Capsule/Frustum/Polyhedron). */
597         vec ClosestPoint(const vec &point) const;
598
599         /// Computes the distance between this Frustum and the given object.
600         /** This function finds the nearest pair of points on this and the given object, and computes their distance.
601                 If the two objects intersect, or one object is contained inside the other, the returned distance is zero.
602                 @todo Add Frustum::Distance(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Capsule/Frustum/Polyhedron).
603                 @see Contains(), Intersects(), ClosestPoint(). */
604         float Distance(const vec &point) const;
605
606         /// Tests whether this Frustum and the given object intersect.  
607         /** Both objects are treated as "solid", meaning that if one of the objects is fully contained inside
608                 another, this function still returns true. (e.g. in case a line segment is contained inside this Frustum,
609                 or this Frustum is contained inside a Sphere, etc.)
610                 The first parameter of this function specifies the other object to test against.
611                 @see Contains(), Distance(), ClosestPoint().
612                 @todo Add Intersects(Circle/Disc). */
613         bool Intersects(const Ray &ray) const;
614         bool Intersects(const Line &line) const;
615         bool Intersects(const LineSegment &lineSegment) const;
616         bool Intersects(const AABB &aabb) const;
617         bool Intersects(const OBB &obb) const;
618         bool Intersects(const Plane &plane) const;
619         bool Intersects(const Triangle &triangle) const;
620         bool Intersects(const Polygon &polygon) const;
621         bool Intersects(const Sphere &sphere) const;
622         bool Intersects(const Capsule &capsule) const;
623         bool Intersects(const Frustum &frustum) const;
624         bool Intersects(const Polyhedron &polyhedron) const;
625
626 #if defined(MATH_TINYXML_INTEROP) && defined(MATH_CONTAINERLIB_SUPPORT)
627         void DeserializeFromXml(TiXmlElement *e);
628 #endif
629
630 #ifdef MATH_ENABLE_STL_SUPPORT
631         /// Returns a human-readable representation of this Frustum. Most useful for debugging purposes.
632         std::string ToString() const;
633          ///\todo Implement this properly.
634         std::string SerializeToString() const return ToString(); }
635 #endif
636 #ifdef MATH_QT_INTEROP
637         operator QString() const return toString(); }
638         QString toString() const return QString::fromStdString(ToString()); }
639 #endif
640 };
641
642 Frustum operator *(const float3x3 &transform, const Frustum &frustum);
643 Frustum operator *(const float3x4 &transform, const Frustum &frustum);
644 Frustum operator *(const float4x4 &transform, const Frustum &frustum);
645 Frustum operator *(const Quat &transform, const Frustum &frustum);
646
647 #ifdef MATH_QT_INTEROP
648 Q_DECLARE_METATYPE(Frustum)
649 Q_DECLARE_METATYPE(Frustum*)
650 #endif
651
652 #ifdef MATH_ENABLE_STL_SUPPORT
653 std::ostream &operator <<(std::ostream &o, const Frustum &frustum);
654 #endif
655
656 MATH_END_NAMESPACE

Go back to previous page