SViewFrustum.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #ifndef __S_VIEW_FRUSTUM_H_INCLUDED__
  5. #define __S_VIEW_FRUSTUM_H_INCLUDED__
  6. #include "plane3d.h"
  7. #include "vector3d.h"
  8. #include "line3d.h"
  9. #include "aabbox3d.h"
  10. #include "matrix4.h"
  11. #include "IVideoDriver.h"
  12. namespace irr
  13. {
  14. namespace scene
  15. {
  16. //! Defines the view frustum. That's the space visible by the camera.
  17. /** The view frustum is enclosed by 6 planes. These six planes share
  18. eight points. A bounding box around these eight points is also stored in
  19. this structure.
  20. */
  21. struct SViewFrustum
  22. {
  23. enum VFPLANES
  24. {
  25. //! Far plane of the frustum. That is the plane furthest away from the eye.
  26. VF_FAR_PLANE = 0,
  27. //! Near plane of the frustum. That is the plane nearest to the eye.
  28. VF_NEAR_PLANE,
  29. //! Left plane of the frustum.
  30. VF_LEFT_PLANE,
  31. //! Right plane of the frustum.
  32. VF_RIGHT_PLANE,
  33. //! Bottom plane of the frustum.
  34. VF_BOTTOM_PLANE,
  35. //! Top plane of the frustum.
  36. VF_TOP_PLANE,
  37. //! Amount of planes enclosing the view frustum. Should be 6.
  38. VF_PLANE_COUNT
  39. };
  40. //! Default Constructor
  41. SViewFrustum() : BoundingRadius(0.f), FarNearDistance(0.f) {}
  42. //! Copy Constructor
  43. SViewFrustum(const SViewFrustum& other);
  44. //! This constructor creates a view frustum based on a projection and/or view matrix.
  45. //\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).
  46. SViewFrustum(const core::matrix4& mat, bool zClipFromZero);
  47. //! This constructor creates a view frustum based on a projection and/or view matrix.
  48. //\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).
  49. inline void setFrom(const core::matrix4& mat, bool zClipFromZero);
  50. //! transforms the frustum by the matrix
  51. /** \param mat: Matrix by which the view frustum is transformed.*/
  52. void transform(const core::matrix4& mat);
  53. //! returns the point which is on the far left upper corner inside the the view frustum.
  54. core::vector3df getFarLeftUp() const;
  55. //! returns the point which is on the far left bottom corner inside the the view frustum.
  56. core::vector3df getFarLeftDown() const;
  57. //! returns the point which is on the far right top corner inside the the view frustum.
  58. core::vector3df getFarRightUp() const;
  59. //! returns the point which is on the far right bottom corner inside the the view frustum.
  60. core::vector3df getFarRightDown() const;
  61. //! returns the point which is on the near left upper corner inside the the view frustum.
  62. core::vector3df getNearLeftUp() const;
  63. //! returns the point which is on the near left bottom corner inside the the view frustum.
  64. core::vector3df getNearLeftDown() const;
  65. //! returns the point which is on the near right top corner inside the the view frustum.
  66. core::vector3df getNearRightUp() const;
  67. //! returns the point which is on the near right bottom corner inside the the view frustum.
  68. core::vector3df getNearRightDown() const;
  69. //! returns a bounding box enclosing the whole view frustum
  70. const core::aabbox3d<f32> &getBoundingBox() const;
  71. //! recalculates the bounding box and sphere based on the planes
  72. inline void recalculateBoundingBox();
  73. //! get the bounding sphere's radius (of an optimized sphere, not the AABB's)
  74. float getBoundingRadius() const;
  75. //! get the bounding sphere's radius (of an optimized sphere, not the AABB's)
  76. core::vector3df getBoundingCenter() const;
  77. //! the cam should tell the frustum the distance between far and near
  78. void setFarNearDistance(float distance);
  79. //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE
  80. core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state);
  81. //! get the given state's matrix based on frustum E_TRANSFORMATION_STATE
  82. const core::matrix4& getTransform( video::E_TRANSFORMATION_STATE state) const;
  83. //! clips a line to the view frustum.
  84. /** \return True if the line was clipped, false if not */
  85. bool clipLine(core::line3d<f32>& line) const;
  86. //! the position of the camera
  87. core::vector3df cameraPosition;
  88. //! all planes enclosing the view frustum.
  89. core::plane3d<f32> planes[VF_PLANE_COUNT];
  90. //! bounding box around the view frustum
  91. core::aabbox3d<f32> boundingBox;
  92. private:
  93. //! Hold a copy of important transform matrices
  94. enum E_TRANSFORMATION_STATE_FRUSTUM
  95. {
  96. ETS_VIEW = 0,
  97. ETS_PROJECTION = 1,
  98. ETS_COUNT_FRUSTUM
  99. };
  100. //! recalculates the bounding sphere based on the planes
  101. inline void recalculateBoundingSphere();
  102. //! Hold a copy of important transform matrices
  103. core::matrix4 Matrices[ETS_COUNT_FRUSTUM];
  104. float BoundingRadius;
  105. float FarNearDistance;
  106. core::vector3df BoundingCenter;
  107. };
  108. /*!
  109. Copy constructor ViewFrustum
  110. */
  111. inline SViewFrustum::SViewFrustum(const SViewFrustum& other)
  112. {
  113. cameraPosition=other.cameraPosition;
  114. boundingBox=other.boundingBox;
  115. u32 i;
  116. for (i=0; i<VF_PLANE_COUNT; ++i)
  117. planes[i]=other.planes[i];
  118. for (i=0; i<ETS_COUNT_FRUSTUM; ++i)
  119. Matrices[i]=other.Matrices[i];
  120. BoundingRadius = other.BoundingRadius;
  121. FarNearDistance = other.FarNearDistance;
  122. BoundingCenter = other.BoundingCenter;
  123. }
  124. inline SViewFrustum::SViewFrustum(const core::matrix4& mat, bool zClipFromZero)
  125. {
  126. setFrom(mat, zClipFromZero);
  127. }
  128. inline void SViewFrustum::transform(const core::matrix4& mat)
  129. {
  130. for (u32 i=0; i<VF_PLANE_COUNT; ++i)
  131. mat.transformPlane(planes[i]);
  132. mat.transformVect(cameraPosition);
  133. recalculateBoundingBox();
  134. }
  135. inline core::vector3df SViewFrustum::getFarLeftUp() const
  136. {
  137. core::vector3df p;
  138. planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
  139. planes[scene::SViewFrustum::VF_TOP_PLANE],
  140. planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
  141. return p;
  142. }
  143. inline core::vector3df SViewFrustum::getFarLeftDown() const
  144. {
  145. core::vector3df p;
  146. planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
  147. planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
  148. planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
  149. return p;
  150. }
  151. inline core::vector3df SViewFrustum::getFarRightUp() const
  152. {
  153. core::vector3df p;
  154. planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
  155. planes[scene::SViewFrustum::VF_TOP_PLANE],
  156. planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
  157. return p;
  158. }
  159. inline core::vector3df SViewFrustum::getFarRightDown() const
  160. {
  161. core::vector3df p;
  162. planes[scene::SViewFrustum::VF_FAR_PLANE].getIntersectionWithPlanes(
  163. planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
  164. planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
  165. return p;
  166. }
  167. inline core::vector3df SViewFrustum::getNearLeftUp() const
  168. {
  169. core::vector3df p;
  170. planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
  171. planes[scene::SViewFrustum::VF_TOP_PLANE],
  172. planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
  173. return p;
  174. }
  175. inline core::vector3df SViewFrustum::getNearLeftDown() const
  176. {
  177. core::vector3df p;
  178. planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
  179. planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
  180. planes[scene::SViewFrustum::VF_LEFT_PLANE], p);
  181. return p;
  182. }
  183. inline core::vector3df SViewFrustum::getNearRightUp() const
  184. {
  185. core::vector3df p;
  186. planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
  187. planes[scene::SViewFrustum::VF_TOP_PLANE],
  188. planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
  189. return p;
  190. }
  191. inline core::vector3df SViewFrustum::getNearRightDown() const
  192. {
  193. core::vector3df p;
  194. planes[scene::SViewFrustum::VF_NEAR_PLANE].getIntersectionWithPlanes(
  195. planes[scene::SViewFrustum::VF_BOTTOM_PLANE],
  196. planes[scene::SViewFrustum::VF_RIGHT_PLANE], p);
  197. return p;
  198. }
  199. inline const core::aabbox3d<f32> &SViewFrustum::getBoundingBox() const
  200. {
  201. return boundingBox;
  202. }
  203. inline void SViewFrustum::recalculateBoundingBox()
  204. {
  205. boundingBox.reset(getNearLeftUp());
  206. boundingBox.addInternalPoint(getNearRightUp());
  207. boundingBox.addInternalPoint(getNearLeftDown());
  208. boundingBox.addInternalPoint(getNearRightDown());
  209. boundingBox.addInternalPoint(getFarRightUp());
  210. boundingBox.addInternalPoint(getFarLeftDown());
  211. boundingBox.addInternalPoint(getFarRightDown());
  212. boundingBox.addInternalPoint(getFarLeftUp());
  213. // Also recalculate the bounding sphere when the bbox changes
  214. recalculateBoundingSphere();
  215. }
  216. inline float SViewFrustum::getBoundingRadius() const
  217. {
  218. return BoundingRadius;
  219. }
  220. inline core::vector3df SViewFrustum::getBoundingCenter() const
  221. {
  222. return BoundingCenter;
  223. }
  224. inline void SViewFrustum::setFarNearDistance(float distance)
  225. {
  226. FarNearDistance = distance;
  227. }
  228. //! This constructor creates a view frustum based on a projection
  229. //! and/or view matrix.
  230. inline void SViewFrustum::setFrom(const core::matrix4& mat, bool zClipFromZero)
  231. {
  232. // left clipping plane
  233. planes[VF_LEFT_PLANE].Normal.X = mat[3 ] + mat[0];
  234. planes[VF_LEFT_PLANE].Normal.Y = mat[7 ] + mat[4];
  235. planes[VF_LEFT_PLANE].Normal.Z = mat[11] + mat[8];
  236. planes[VF_LEFT_PLANE].D = mat[15] + mat[12];
  237. // right clipping plane
  238. planes[VF_RIGHT_PLANE].Normal.X = mat[3 ] - mat[0];
  239. planes[VF_RIGHT_PLANE].Normal.Y = mat[7 ] - mat[4];
  240. planes[VF_RIGHT_PLANE].Normal.Z = mat[11] - mat[8];
  241. planes[VF_RIGHT_PLANE].D = mat[15] - mat[12];
  242. // top clipping plane
  243. planes[VF_TOP_PLANE].Normal.X = mat[3 ] - mat[1];
  244. planes[VF_TOP_PLANE].Normal.Y = mat[7 ] - mat[5];
  245. planes[VF_TOP_PLANE].Normal.Z = mat[11] - mat[9];
  246. planes[VF_TOP_PLANE].D = mat[15] - mat[13];
  247. // bottom clipping plane
  248. planes[VF_BOTTOM_PLANE].Normal.X = mat[3 ] + mat[1];
  249. planes[VF_BOTTOM_PLANE].Normal.Y = mat[7 ] + mat[5];
  250. planes[VF_BOTTOM_PLANE].Normal.Z = mat[11] + mat[9];
  251. planes[VF_BOTTOM_PLANE].D = mat[15] + mat[13];
  252. // far clipping plane
  253. planes[VF_FAR_PLANE].Normal.X = mat[3 ] - mat[2];
  254. planes[VF_FAR_PLANE].Normal.Y = mat[7 ] - mat[6];
  255. planes[VF_FAR_PLANE].Normal.Z = mat[11] - mat[10];
  256. planes[VF_FAR_PLANE].D = mat[15] - mat[14];
  257. // near clipping plane
  258. if ( zClipFromZero )
  259. {
  260. planes[VF_NEAR_PLANE].Normal.X = mat[2];
  261. planes[VF_NEAR_PLANE].Normal.Y = mat[6];
  262. planes[VF_NEAR_PLANE].Normal.Z = mat[10];
  263. planes[VF_NEAR_PLANE].D = mat[14];
  264. }
  265. else
  266. {
  267. // near clipping plane
  268. planes[VF_NEAR_PLANE].Normal.X = mat[3 ] + mat[2];
  269. planes[VF_NEAR_PLANE].Normal.Y = mat[7 ] + mat[6];
  270. planes[VF_NEAR_PLANE].Normal.Z = mat[11] + mat[10];
  271. planes[VF_NEAR_PLANE].D = mat[15] + mat[14];
  272. }
  273. // normalize normals
  274. u32 i;
  275. for ( i=0; i != VF_PLANE_COUNT; ++i)
  276. {
  277. const f32 len = -core::reciprocal_squareroot(
  278. planes[i].Normal.getLengthSQ());
  279. planes[i].Normal *= len;
  280. planes[i].D *= len;
  281. }
  282. // make bounding box
  283. recalculateBoundingBox();
  284. }
  285. /*!
  286. View Frustum depends on Projection & View Matrix
  287. */
  288. inline core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state)
  289. {
  290. u32 index = 0;
  291. switch ( state )
  292. {
  293. case video::ETS_PROJECTION:
  294. index = SViewFrustum::ETS_PROJECTION; break;
  295. case video::ETS_VIEW:
  296. index = SViewFrustum::ETS_VIEW; break;
  297. default:
  298. break;
  299. }
  300. return Matrices [ index ];
  301. }
  302. /*!
  303. View Frustum depends on Projection & View Matrix
  304. */
  305. inline const core::matrix4& SViewFrustum::getTransform(video::E_TRANSFORMATION_STATE state) const
  306. {
  307. u32 index = 0;
  308. switch ( state )
  309. {
  310. case video::ETS_PROJECTION:
  311. index = SViewFrustum::ETS_PROJECTION; break;
  312. case video::ETS_VIEW:
  313. index = SViewFrustum::ETS_VIEW; break;
  314. default:
  315. break;
  316. }
  317. return Matrices [ index ];
  318. }
  319. //! Clips a line to the frustum
  320. inline bool SViewFrustum::clipLine(core::line3d<f32>& line) const
  321. {
  322. bool wasClipped = false;
  323. for (u32 i=0; i < VF_PLANE_COUNT; ++i)
  324. {
  325. if (planes[i].classifyPointRelation(line.start) == core::ISREL3D_FRONT)
  326. {
  327. line.start = line.start.getInterpolated(line.end,
  328. 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end));
  329. wasClipped = true;
  330. }
  331. if (planes[i].classifyPointRelation(line.end) == core::ISREL3D_FRONT)
  332. {
  333. line.end = line.start.getInterpolated(line.end,
  334. 1.f-planes[i].getKnownIntersectionWithLine(line.start, line.end));
  335. wasClipped = true;
  336. }
  337. }
  338. return wasClipped;
  339. }
  340. inline void SViewFrustum::recalculateBoundingSphere()
  341. {
  342. // Find the center
  343. const float shortlen = (getNearLeftUp() - getNearRightUp()).getLength();
  344. const float longlen = (getFarLeftUp() - getFarRightUp()).getLength();
  345. const float farlen = FarNearDistance;
  346. const float fartocenter = (farlen + (shortlen - longlen) * (shortlen + longlen)/(4*farlen)) / 2;
  347. const float neartocenter = farlen - fartocenter;
  348. BoundingCenter = cameraPosition + -planes[VF_NEAR_PLANE].Normal * neartocenter;
  349. // Find the radius
  350. core::vector3df dir[8];
  351. dir[0] = getFarLeftUp() - BoundingCenter;
  352. dir[1] = getFarRightUp() - BoundingCenter;
  353. dir[2] = getFarLeftDown() - BoundingCenter;
  354. dir[3] = getFarRightDown() - BoundingCenter;
  355. dir[4] = getNearRightDown() - BoundingCenter;
  356. dir[5] = getNearLeftDown() - BoundingCenter;
  357. dir[6] = getNearRightUp() - BoundingCenter;
  358. dir[7] = getNearLeftUp() - BoundingCenter;
  359. u32 i = 0;
  360. float diam[8] = { 0.f };
  361. for (i = 0; i < 8; ++i)
  362. diam[i] = dir[i].getLengthSQ();
  363. float longest = 0;
  364. for (i = 0; i < 8; ++i)
  365. {
  366. if (diam[i] > longest)
  367. longest = diam[i];
  368. }
  369. BoundingRadius = sqrtf(longest);
  370. }
  371. } // end namespace scene
  372. } // end namespace irr
  373. #endif