1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #ifndef __S_VIEW_FRUSTUM_H_INCLUDED__
\r
6 #define __S_VIEW_FRUSTUM_H_INCLUDED__
\r
9 #include "vector3d.h"
\r
11 #include "aabbox3d.h"
\r
12 #include "matrix4.h"
\r
13 #include "IVideoDriver.h"
\r
20 //! Defines the view frustum. That's the space visible by the camera.
\r
21 /** The view frustum is enclosed by 6 planes. These six planes share
\r
22 eight points. A bounding box around these eight points is also stored in
\r
29 //! Far plane of the frustum. That is the plane furthest away from the eye.
\r
31 //! Near plane of the frustum. That is the plane nearest to the eye.
\r
33 //! Left plane of the frustum.
\r
35 //! Right plane of the frustum.
\r
37 //! Bottom plane of the frustum.
\r
39 //! Top plane of the frustum.
\r
42 //! Amount of planes enclosing the view frustum. Should be 6.
\r
47 //! Default Constructor
\r
48 SViewFrustum() : BoundingRadius(0.f), FarNearDistance(0.f) {}
\r
50 //! Copy Constructor
\r
51 SViewFrustum(const SViewFrustum& other);
\r
53 //! This constructor creates a view frustum based on a projection and/or view matrix.
\r
54 //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style).
\r
55 SViewFrustum(const core::matrix4& mat, bool zClipFromZero);
\r
57 //! This constructor creates a view frustum based on a projection and/or view matrix.
\r
58 //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style).
\r
59 inline void setFrom(const core::matrix4& mat, bool zClipFromZero);
\r
61 //! transforms the frustum by the matrix
\r
62 /** \param mat: Matrix by which the view frustum is transformed.*/
\r
63 void transform(const core::matrix4& mat);
\r
65 //! returns the point which is on the far left upper corner inside the the view frustum.
\r
66 core::vector3df getFarLeftUp() const;
\r
68 //! returns the point which is on the far left bottom corner inside the the view frustum.
\r
69 core::vector3df getFarLeftDown() const;
\r
71 //! returns the point which is on the far right top corner inside the the view frustum.
\r
72 core::vector3df getFarRightUp() const;
\r
74 //! returns the point which is on the far right bottom corner inside the the view frustum.
\r
75 core::vector3df getFarRightDown() const;
\r
77 //! returns the point which is on the near left upper corner inside the the view frustum.
\r
78 core::vector3df getNearLeftUp() const;
\r
80 //! returns the point which is on the near left bottom corner inside the the view frustum.
\r
81 core::vector3df getNearLeftDown() const;
\r
83 //! returns the point which is on the near right top corner inside the the view frustum.
\r
84 core::vector3df getNearRightUp() const;
\r
86 //! returns the point which is on the near right bottom corner inside the the view frustum.
\r
87 core::vector3df getNearRightDown() const;
\r
89 //! returns a bounding box enclosing the whole view frustum
\r
90 const core::aabbox3d<f32> &getBoundingBox() const;
\r
92 //! recalculates the bounding box and sphere based on the planes
\r
93 inline void recalculateBoundingBox();
\r
95 //! get the bounding sphere's radius (of an optimized sphere, not the AABB's)
\r
96 float getBoundingRadius() const;
\r
98 //! get the bounding sphere's radius (of an optimized sphere, not the AABB's)
\r
99 core::vector3df getBoundingCenter() const;
\r
101 //! the cam should tell the frustum the distance between far and near
\r
102 void setFarNearDistance(float distance);
\r
104 //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE
\r
105 core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state);
\r
107 //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE
\r
108 const core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state) const;
\r
110 //! clips a line to the view frustum.
\r
111 /** \return True if the line was clipped, false if not */
\r
112 bool clipLine(core::line3d<f32>& line) const;
\r
114 //! the position of the camera
\r
115 core::vector3df cameraPosition;
\r
117 //! all planes enclosing the view frustum.
\r
118 core::plane3d<f32> planes[VF_PLANE_COUNT];
\r
120 //! bounding box around the view frustum
\r
121 core::aabbox3d<f32> boundingBox;
\r
124 //! Hold a copy of important transform matrices
\r
125 enum E_TRANSFORMATION_STATE_FRUSTUM
\r
128 ETS_PROJECTION = 1,
\r
132 //! recalculates the bounding sphere based on the planes
\r
133 inline void recalculateBoundingSphere();
\r
135 //! Hold a copy of important transform matrices
\r
136 core::matrix4 Matrices[ETS_COUNT_FRUSTUM];
\r
138 float BoundingRadius;
\r
139 float FarNearDistance;
\r
140 core::vector3df BoundingCenter;
\r
145 Copy constructor ViewFrustum
\r
147 inline SViewFrustum::SViewFrustum(const SViewFrustum& other)
\r
149 cameraPosition=other.cameraPosition;
\r
150 boundingBox=other.boundingBox;
\r
153 for (i=0; i<VF_PLANE_COUNT; ++i)
\r
154 planes[i]=other.planes[i];
\r
156 for (i=0; i<ETS_COUNT_FRUSTUM; ++i)
\r
157 Matrices[i]=other.Matrices[i];
\r
159 BoundingRadius = other.BoundingRadius;
\r
160 FarNearDistance = other.FarNearDistance;
\r
161 BoundingCenter = other.BoundingCenter;
\r
164 inline SViewFrustum::SViewFrustum(const core::matrix4& mat, bool zClipFromZero)
\r
166 setFrom(mat, zClipFromZero);
\r
170 inline void SViewFrustum::transform(const core::matrix4& mat)
\r
172 for (u32 i=0; i<VF_PLANE_COUNT; ++i)
\r
173 mat.transformPlane(planes[i]);
\r
175 mat.transformVect(cameraPosition);
\r
176 recalculateBoundingBox();
\r
180 inline core::vector3df SViewFrustum::getFarLeftUp() const
\r
183 planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
\r
184 planes[scene::SViewFrustum::VF_TOP_PLANE],
\r
185 planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
\r
190 inline core::vector3df SViewFrustum::getFarLeftDown() const
\r
193 planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
\r
194 planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
\r
195 planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
\r
200 inline core::vector3df SViewFrustum::getFarRightUp() const
\r
203 planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
\r
204 planes[scene::SViewFrustum::VF_TOP_PLANE],
\r
205 planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
\r
210 inline core::vector3df SViewFrustum::getFarRightDown() const
\r
213 planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
\r
214 planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
\r
215 planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
\r
220 inline core::vector3df SViewFrustum::getNearLeftUp() const
\r
223 planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
\r
224 planes[scene::SViewFrustum::VF_TOP_PLANE],
\r
225 planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
\r
230 inline core::vector3df SViewFrustum::getNearLeftDown() const
\r
233 planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
\r
234 planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
\r
235 planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
\r
240 inline core::vector3df SViewFrustum::getNearRightUp() const
\r
243 planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
\r
244 planes[scene::SViewFrustum::VF_TOP_PLANE],
\r
245 planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
\r
250 inline core::vector3df SViewFrustum::getNearRightDown() const
\r
253 planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
\r
254 planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
\r
255 planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
\r
260 inline const core::aabbox3d<f32> &SViewFrustum::getBoundingBox() const
\r
262 return boundingBox;
\r
265 inline void SViewFrustum::recalculateBoundingBox()
\r
267 boundingBox.reset(getNearLeftUp());
\r
268 boundingBox.addInternalPoint(getNearRightUp());
\r
269 boundingBox.addInternalPoint(getNearLeftDown());
\r
270 boundingBox.addInternalPoint(getNearRightDown());
\r
271 boundingBox.addInternalPoint(getFarRightUp());
\r
272 boundingBox.addInternalPoint(getFarLeftDown());
\r
273 boundingBox.addInternalPoint(getFarRightDown());
\r
274 boundingBox.addInternalPoint(getFarLeftUp());
\r
276 // Also recalculate the bounding sphere when the bbox changes
\r
277 recalculateBoundingSphere();
\r
280 inline float SViewFrustum::getBoundingRadius() const
\r
282 return BoundingRadius;
\r
285 inline core::vector3df SViewFrustum::getBoundingCenter() const
\r
287 return BoundingCenter;
\r
290 inline void SViewFrustum::setFarNearDistance(float distance)
\r
292 FarNearDistance = distance;
\r
295 //! This constructor creates a view frustum based on a projection
\r
296 //! and/or view matrix.
\r
297 inline void SViewFrustum::setFrom(const core::matrix4& mat, bool zClipFromZero)
\r
299 // left clipping plane
\r
300 planes[VF_LEFT_PLANE].Normal.X = mat[3 ] + mat[0];
\r
301 planes[VF_LEFT_PLANE].Normal.Y = mat[7 ] + mat[4];
\r
302 planes[VF_LEFT_PLANE].Normal.Z = mat[11] + mat[8];
\r
303 planes[VF_LEFT_PLANE].D = mat[15] + mat[12];
\r
305 // right clipping plane
\r
306 planes[VF_RIGHT_PLANE].Normal.X = mat[3 ] - mat[0];
\r
307 planes[VF_RIGHT_PLANE].Normal.Y = mat[7 ] - mat[4];
\r
308 planes[VF_RIGHT_PLANE].Normal.Z = mat[11] - mat[8];
\r
309 planes[VF_RIGHT_PLANE].D = mat[15] - mat[12];
\r
311 // top clipping plane
\r
312 planes[VF_TOP_PLANE].Normal.X = mat[3 ] - mat[1];
\r
313 planes[VF_TOP_PLANE].Normal.Y = mat[7 ] - mat[5];
\r
314 planes[VF_TOP_PLANE].Normal.Z = mat[11] - mat[9];
\r
315 planes[VF_TOP_PLANE].D = mat[15] - mat[13];
\r
317 // bottom clipping plane
\r
318 planes[VF_BOTTOM_PLANE].Normal.X = mat[3 ] + mat[1];
\r
319 planes[VF_BOTTOM_PLANE].Normal.Y = mat[7 ] + mat[5];
\r
320 planes[VF_BOTTOM_PLANE].Normal.Z = mat[11] + mat[9];
\r
321 planes[VF_BOTTOM_PLANE].D = mat[15] + mat[13];
\r
323 // far clipping plane
\r
324 planes[VF_FAR_PLANE].Normal.X = mat[3 ] - mat[2];
\r
325 planes[VF_FAR_PLANE].Normal.Y = mat[7 ] - mat[6];
\r
326 planes[VF_FAR_PLANE].Normal.Z = mat[11] - mat[10];
\r
327 planes[VF_FAR_PLANE].D = mat[15] - mat[14];
\r
329 // near clipping plane
\r
330 if ( zClipFromZero )
\r
332 planes[VF_NEAR_PLANE].Normal.X = mat[2];
\r
333 planes[VF_NEAR_PLANE].Normal.Y = mat[6];
\r
334 planes[VF_NEAR_PLANE].Normal.Z = mat[10];
\r
335 planes[VF_NEAR_PLANE].D = mat[14];
\r
339 // near clipping plane
\r
340 planes[VF_NEAR_PLANE].Normal.X = mat[3 ] + mat[2];
\r
341 planes[VF_NEAR_PLANE].Normal.Y = mat[7 ] + mat[6];
\r
342 planes[VF_NEAR_PLANE].Normal.Z = mat[11] + mat[10];
\r
343 planes[VF_NEAR_PLANE].D = mat[15] + mat[14];
\r
346 // normalize normals
\r
348 for ( i=0; i != VF_PLANE_COUNT; ++i)
\r
350 const f32 len = -core::reciprocal_squareroot(
\r
351 planes[i].Normal.getLengthSQ());
\r
352 planes[i].Normal *= len;
\r
353 planes[i].D *= len;
\r
356 // make bounding box
\r
357 recalculateBoundingBox();
\r
361 View Frustum depends on Projection & View Matrix
\r
363 inline core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state)
\r
368 case video::ETS_PROJECTION:
\r
369 index = SViewFrustum::ETS_PROJECTION; break;
\r
370 case video::ETS_VIEW:
\r
371 index = SViewFrustum::ETS_VIEW; break;
\r
375 return Matrices [ index ];
\r
379 View Frustum depends on Projection & View Matrix
\r
381 inline const core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state) const
\r
386 case video::ETS_PROJECTION:
\r
387 index = SViewFrustum::ETS_PROJECTION; break;
\r
388 case video::ETS_VIEW:
\r
389 index = SViewFrustum::ETS_VIEW; break;
\r
393 return Matrices [ index ];
\r
396 //! Clips a line to the frustum
\r
397 inline bool SViewFrustum::clipLine(core::line3d<f32>& line) const
\r
399 bool wasClipped = false;
\r
400 for (u32 i=0; i < VF_PLANE_COUNT; ++i)
\r
402 if (planes[i].classifyPointRelation(line.start) == core::ISREL3D_FRONT)
\r
404 line.start = line.start.getInterpolated(line.end,
\r
405 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end));
\r
408 if (planes[i].classifyPointRelation(line.end) == core::ISREL3D_FRONT)
\r
410 line.end = line.start.getInterpolated(line.end,
\r
411 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end));
\r
418 inline void SViewFrustum::recalculateBoundingSphere()
\r
421 const float shortlen = (getNearLeftUp() - getNearRightUp()).getLength();
\r
422 const float longlen = (getFarLeftUp() - getFarRightUp()).getLength();
\r
424 const float farlen = FarNearDistance;
\r
425 const float fartocenter = (farlen + (shortlen - longlen) * (shortlen + longlen)/(4*farlen)) / 2;
\r
426 const float neartocenter = farlen - fartocenter;
\r
428 BoundingCenter = cameraPosition + -planes[VF_NEAR_PLANE].Normal * neartocenter;
\r
431 core::vector3df dir[8];
\r
432 dir[0] = getFarLeftUp() - BoundingCenter;
\r
433 dir[1] = getFarRightUp() - BoundingCenter;
\r
434 dir[2] = getFarLeftDown() - BoundingCenter;
\r
435 dir[3] = getFarRightDown() - BoundingCenter;
\r
436 dir[4] = getNearRightDown() - BoundingCenter;
\r
437 dir[5] = getNearLeftDown() - BoundingCenter;
\r
438 dir[6] = getNearRightUp() - BoundingCenter;
\r
439 dir[7] = getNearLeftUp() - BoundingCenter;
\r
442 float diam[8] = { 0.f };
\r
444 for (i = 0; i < 8; ++i)
\r
445 diam[i] = dir[i].getLengthSQ();
\r
449 for (i = 0; i < 8; ++i)
\r
451 if (diam[i] > longest)
\r
455 BoundingRadius = sqrtf(longest);
\r
458 } // end namespace scene
\r
459 } // end namespace irr
\r