SViewFrustum.h 13 KB

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