Plane.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #include "Base.h"
  2. #include "Plane.h"
  3. #include "Frustum.h"
  4. #include "Ray.h"
  5. #include "BoundingSphere.h"
  6. #include "BoundingBox.h"
  7. namespace gameplay
  8. {
  9. Plane::Plane()
  10. : _normal(0, 1, 0), _distance(0)
  11. {
  12. }
  13. Plane::Plane(const Vector3& normal, float distance)
  14. {
  15. set(normal, distance);
  16. }
  17. Plane::Plane(float normalX, float normalY, float normalZ, float distance)
  18. {
  19. set(Vector3(normalX, normalY, normalZ), distance);
  20. }
  21. Plane::Plane(const Plane& copy)
  22. {
  23. set(copy);
  24. }
  25. Plane::~Plane()
  26. {
  27. }
  28. const Vector3& Plane::getNormal() const
  29. {
  30. return _normal;
  31. }
  32. void Plane::setNormal(const Vector3& normal)
  33. {
  34. _normal = normal;
  35. normalize();
  36. }
  37. void Plane::setNormal(float x, float y, float z)
  38. {
  39. _normal.set(x, y, z);
  40. normalize();
  41. }
  42. float Plane::getDistance() const
  43. {
  44. return _distance;
  45. }
  46. void Plane::setDistance(float distance)
  47. {
  48. _distance = distance;
  49. }
  50. float Plane::distance(const Vector3& point) const
  51. {
  52. return _normal.x * point.x + _normal.y * point.y + _normal.z * point.z + _distance;
  53. }
  54. void Plane::intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3* point)
  55. {
  56. GP_ASSERT(point);
  57. // The planes' normals must be all normalized (which we guarantee in the Plane class).
  58. // Calculate the determinant of the matrix (i.e | n1 n2 n3 |).
  59. float det = p1._normal.x * (p2._normal.y * p3._normal.z -
  60. p2._normal.z * p3._normal.y) - p2._normal.x *(p1._normal.y * p3._normal.z -
  61. p1._normal.z * p3._normal.y) + p3._normal.x * (p1._normal.y * p2._normal.z - p1._normal.z * p2._normal.y);
  62. // If the determinant is zero, then the planes do not all intersect.
  63. if (fabs(det) <= MATH_EPSILON)
  64. return;
  65. // Create 3 points, one on each plane.
  66. // (We just pick the point on the plane directly along its normal from the origin).
  67. float p1x = -p1._normal.x * p1._distance;
  68. float p1y = -p1._normal.y * p1._distance;
  69. float p1z = -p1._normal.z * p1._distance;
  70. float p2x = -p2._normal.x * p2._distance;
  71. float p2y = -p2._normal.y * p2._distance;
  72. float p2z = -p2._normal.z * p2._distance;
  73. float p3x = -p3._normal.x * p3._distance;
  74. float p3y = -p3._normal.y * p3._distance;
  75. float p3z = -p3._normal.z * p3._distance;
  76. // Calculate the cross products of the normals.
  77. float c1x = (p2._normal.y * p3._normal.z) - (p2._normal.z * p3._normal.y);
  78. float c1y = (p2._normal.z * p3._normal.x) - (p2._normal.x * p3._normal.z);
  79. float c1z = (p2._normal.x * p3._normal.y) - (p2._normal.y * p3._normal.x);
  80. float c2x = (p3._normal.y * p1._normal.z) - (p3._normal.z * p1._normal.y);
  81. float c2y = (p3._normal.z * p1._normal.x) - (p3._normal.x * p1._normal.z);
  82. float c2z = (p3._normal.x * p1._normal.y) - (p3._normal.y * p1._normal.x);
  83. float c3x = (p1._normal.y * p2._normal.z) - (p1._normal.z * p2._normal.y);
  84. float c3y = (p1._normal.z * p2._normal.x) - (p1._normal.x * p2._normal.z);
  85. float c3z = (p1._normal.x * p2._normal.y) - (p1._normal.y * p2._normal.x);
  86. // Calculate the point of intersection using the formula:
  87. // x = (| n1 n2 n3 |)^-1 * [(x1 * n1)(n2 x n3) + (x2 * n2)(n3 x n1) + (x3 * n3)(n1 x n2)]
  88. float s1 = p1x * p1._normal.x + p1y * p1._normal.y + p1z * p1._normal.z;
  89. float s2 = p2x * p2._normal.x + p2y * p2._normal.y + p2z * p2._normal.z;
  90. float s3 = p3x * p3._normal.x + p3y * p3._normal.y + p3z * p3._normal.z;
  91. float detI = 1.0f / det;
  92. point->x = (s1 * c1x + s2 * c2x + s3 * c3x) * detI;
  93. point->y = (s1 * c1y + s2 * c2y + s3 * c3y) * detI;
  94. point->z = (s1 * c1z + s2 * c2z + s3 * c3z) * detI;
  95. }
  96. float Plane::intersects(const BoundingSphere& sphere) const
  97. {
  98. return sphere.intersects(*this);
  99. }
  100. float Plane::intersects(const BoundingBox& box) const
  101. {
  102. return box.intersects(*this);
  103. }
  104. float Plane::intersects(const Frustum& frustum) const
  105. {
  106. // Get the corners of the frustum.
  107. Vector3 corners[8];
  108. frustum.getCorners(corners);
  109. // Calculate the distances from all of the corners to the plane.
  110. // If all of the distances are positive, then the frustum is in the
  111. // positive half-space of this plane; if all the distances are negative,
  112. // then the frustum is in the negative half-space of this plane; if some of
  113. // the distances are positive and some are negative, the frustum intersects.
  114. float d = distance(corners[0]);
  115. if (d > 0.0f)
  116. {
  117. if (distance(corners[1]) <= 0.0f ||
  118. distance(corners[2]) <= 0.0f ||
  119. distance(corners[3]) <= 0.0f ||
  120. distance(corners[4]) <= 0.0f ||
  121. distance(corners[5]) <= 0.0f ||
  122. distance(corners[6]) <= 0.0f ||
  123. distance(corners[7]) <= 0.0f)
  124. {
  125. return Plane::INTERSECTS_INTERSECTING;
  126. }
  127. return Plane::INTERSECTS_FRONT;
  128. }
  129. else if (d < 0.0f)
  130. {
  131. if (distance(corners[1]) >= 0.0f ||
  132. distance(corners[2]) >= 0.0f ||
  133. distance(corners[3]) >= 0.0f ||
  134. distance(corners[4]) >= 0.0f ||
  135. distance(corners[5]) >= 0.0f ||
  136. distance(corners[6]) >= 0.0f ||
  137. distance(corners[7]) >= 0.0f)
  138. {
  139. return Plane::INTERSECTS_INTERSECTING;
  140. }
  141. return Plane::INTERSECTS_BACK;
  142. }
  143. else
  144. {
  145. return Plane::INTERSECTS_INTERSECTING;
  146. }
  147. }
  148. float Plane::intersects(const Plane& plane) const
  149. {
  150. // Check if the planes intersect.
  151. if ((_normal.x == plane._normal.x && _normal.y == plane._normal.y && _normal.z == plane._normal.z) || !isParallel(plane))
  152. {
  153. return Plane::INTERSECTS_INTERSECTING;
  154. }
  155. // Calculate the point where the given plane's normal vector intersects the given plane.
  156. Vector3 point(plane._normal.x * -plane._distance, plane._normal.y * -plane._distance, plane._normal.z * -plane._distance);
  157. // Calculate whether the given plane is in the positive or negative half-space of this plane
  158. // (corresponds directly to the sign of the distance from the point calculated above to this plane).
  159. if (distance(point) > 0.0f)
  160. {
  161. return Plane::INTERSECTS_FRONT;
  162. }
  163. else
  164. {
  165. return Plane::INTERSECTS_BACK;
  166. }
  167. }
  168. float Plane::intersects(const Ray& ray) const
  169. {
  170. // Calculate the distance from the ray's origin to the plane.
  171. float d = distance(ray.getOrigin());
  172. // If the origin of the ray lies in the plane, then it intersects.
  173. if (d == 0.0f)
  174. {
  175. return Plane::INTERSECTS_INTERSECTING;
  176. }
  177. else
  178. {
  179. Vector3 rayDirection = ray.getDirection();
  180. // If the dot product of this plane's normal and the ray's direction is positive, and
  181. // if the distance from this plane to the ray's origin is negative -> intersection, OR
  182. // if the dot product of this plane's normal and the ray's direction is negative, and
  183. // if the distance from this plane to the ray's origin is positive -> intersection.
  184. if (_normal.x * rayDirection.x + _normal.y * rayDirection.y + _normal.z * rayDirection.z > 0.0f)
  185. {
  186. if (d < 0.0f)
  187. {
  188. return Plane::INTERSECTS_INTERSECTING;
  189. }
  190. else
  191. {
  192. return Plane::INTERSECTS_FRONT;
  193. }
  194. }
  195. else
  196. {
  197. if (d > 0.0f)
  198. {
  199. return Plane::INTERSECTS_INTERSECTING;
  200. }
  201. else
  202. {
  203. return Plane::INTERSECTS_BACK;
  204. }
  205. }
  206. }
  207. }
  208. bool Plane::isParallel(const Plane& plane) const
  209. {
  210. return (_normal.y * plane._normal.z) - (_normal.z * plane._normal.y) == 0.0f &&
  211. (_normal.z * plane._normal.x) - (_normal.x * plane._normal.z) == 0.0f &&
  212. (_normal.x * plane._normal.y) - (_normal.y * plane._normal.x) == 0.0f;
  213. }
  214. void Plane::set(const Vector3& normal, float distance)
  215. {
  216. _normal = normal;
  217. _distance = distance;
  218. normalize();
  219. }
  220. void Plane::set(const Plane& plane)
  221. {
  222. _normal = plane._normal;
  223. _distance = plane._distance;
  224. }
  225. void Plane::transform(const Matrix& matrix)
  226. {
  227. Matrix inverted;
  228. if (matrix.invert(&inverted))
  229. {
  230. // Treat the plane as a four-tuple and multiply by the inverse transpose of the matrix to get the transformed plane.
  231. // Then we normalize the plane by dividing both the normal and the distance by the length of the normal.
  232. float nx = _normal.x * inverted.m[0] + _normal.y * inverted.m[1] + _normal.z * inverted.m[2] + _distance * inverted.m[3];
  233. float ny = _normal.x * inverted.m[4] + _normal.y * inverted.m[5] + _normal.z * inverted.m[6] + _distance * inverted.m[7];
  234. float nz = _normal.x * inverted.m[8] + _normal.y * inverted.m[9] + _normal.z * inverted.m[10] + _distance * inverted.m[11];
  235. float d = _normal.x * inverted.m[12]+ _normal.y * inverted.m[13] + _normal.z * inverted.m[14] + _distance * inverted.m[15];
  236. float divisor = sqrt(nx * nx + ny * ny + nz * nz);
  237. GP_ASSERT(divisor);
  238. float factor = 1.0f / divisor;
  239. _normal.x = nx * factor;
  240. _normal.y = ny * factor;
  241. _normal.z = nz * factor;
  242. _distance = d * factor;
  243. }
  244. }
  245. void Plane::normalize()
  246. {
  247. if (_normal.isZero())
  248. return;
  249. // Normalize the plane's normal.
  250. float normalizeFactor = 1.0f / sqrt(_normal.x * _normal.x + _normal.y * _normal.y + _normal.z * _normal.z);
  251. if (normalizeFactor != 1.0f)
  252. {
  253. _normal.x *= normalizeFactor;
  254. _normal.y *= normalizeFactor;
  255. _normal.z *= normalizeFactor;
  256. _distance *= normalizeFactor;
  257. }
  258. }
  259. }