mPolyhedron.impl.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _MPOLYHEDRON_IMPL_H_
  23. #define _MPOLYHEDRON_IMPL_H_
  24. #include "math/mPlaneTransformer.h"
  25. //-----------------------------------------------------------------------------
  26. template< typename Base >
  27. Point3F PolyhedronImpl< Base >::getCenterPoint() const
  28. {
  29. const U32 numPoints = this->getNumPoints();
  30. if( numPoints == 0 )
  31. return Point3F( 0.f, 0.f, 0.f );
  32. const typename Base::PointType* pointList = this->getPoints();
  33. Point3F center( pointList[ 0 ] );
  34. for( U32 i = 1; i < numPoints; ++ i )
  35. center += pointList[ i ];
  36. center /= ( F32 ) numPoints;
  37. return center;
  38. }
  39. //-----------------------------------------------------------------------------
  40. template< typename Base >
  41. void PolyhedronImpl< Base >::transform( const MatrixF& matrix, const Point3F& scale )
  42. {
  43. // Transform points.
  44. const U32 numPoints = this->getNumPoints();
  45. typename Base::PointType* points = this->getPoints();
  46. for( U32 i = 0; i < numPoints; ++ i )
  47. {
  48. matrix.mulP( points[ i ] );
  49. points[ i ].convolve( scale );
  50. }
  51. // Transform planes.
  52. const U32 numPlanes = this->getNumPlanes();
  53. typename Base::PlaneType* planes = this->getPlanes();
  54. PlaneTransformer transformer;
  55. transformer.set( matrix, scale );
  56. for( U32 i = 0; i < numPlanes; ++ i )
  57. {
  58. const typename Base::PlaneType& plane = planes[ i ];
  59. PlaneF result;
  60. transformer.transform( plane, result );
  61. planes[ i ] = result;
  62. }
  63. }
  64. //-----------------------------------------------------------------------------
  65. template< typename Base >
  66. U32 PolyhedronImpl< Base >::constructIntersection( const PlaneF& plane, Point3F* outPoints, U32 maxOutPoints ) const
  67. {
  68. // The assumption here is that the polyhedron is entirely composed
  69. // of convex polygons implicitly described by the edges, points, and planes.
  70. // So, any polygon can only have one of three relations to the given plane
  71. //
  72. // 1) None of its edges intersect with the plane, i.e. the polygon can be ignored.
  73. // 2) One of its edges lies on the plane.
  74. // 2) Two of its edges intersect with the plane.
  75. //
  76. // Conceptually, we need to find the first face with an intersecting edge, then find
  77. // another edge on the same face that is also intersecting, and then continue with the
  78. // face on the opposite side of the edge.
  79. const U32 numEdges = this->getNumEdges();
  80. const typename Base::EdgeType* edges = this->getEdges();
  81. const typename Base::PointType* points = this->getPoints();
  82. U32 numOutPoints = 0;
  83. #define ADD_POINT( p ) \
  84. if( numOutPoints >= maxOutPoints ) \
  85. return 0; \
  86. outPoints[ numOutPoints ++ ] = p;
  87. Point3F intersection;
  88. S32 firstEdge = -1;
  89. S32 firstFace = -1;
  90. U32 v1 = 0;
  91. U32 v2 = 0;
  92. PlaneF::Side v1Side = PlaneF::Front;
  93. PlaneF::Side v2Side = PlaneF::Front;
  94. // Find an edge to start with. This is the first edge
  95. // in the polyhedron that intersects the plane.
  96. for( U32 i = 0; i < numEdges; ++ i )
  97. {
  98. const typename Base::EdgeType& edge = edges[ i ];
  99. v1 = edge.vertex[ 0 ];
  100. v2 = edge.vertex[ 1 ];
  101. const Point3F& p1 = points[ v1 ];
  102. const Point3F& p2 = points[ v2 ];
  103. v1Side = plane.whichSide( p1 );
  104. v2Side = plane.whichSide( p2 );
  105. if( v1Side == PlaneF::On || v2Side == PlaneF::On ||
  106. plane.clipSegment( p1, p2, intersection ) )
  107. {
  108. firstEdge = i;
  109. firstFace = edge.face[ 0 ];
  110. break;
  111. }
  112. }
  113. if( firstEdge == -1 )
  114. return 0;
  115. // Slice around the faces of the polyhedron until
  116. // we get back to the starting face.
  117. U32 currentEdge = firstEdge;
  118. U32 currentFace = firstFace;
  119. do
  120. {
  121. // Handle the current edge.
  122. if( v1Side == PlaneF::On && v2Side == PlaneF::On )
  123. {
  124. // Both points of the edge lie on the plane. Add v2
  125. // and then look for an edge that is also connected to v1
  126. // *and* is connected to our current face. The other face
  127. // of that edge is the one we need to continue with.
  128. ADD_POINT( points[ v2 ] );
  129. for( U32 n = 0; n < numEdges; ++ n )
  130. {
  131. const typename Base::EdgeType& e = edges[ n ];
  132. // Skip current edge.
  133. if( n == currentEdge )
  134. continue;
  135. // Skip edges not belonging to current face.
  136. if( e.face[ 0 ] != currentFace && e.face[ 1 ] != currentFace )
  137. continue;
  138. // Skip edges not connected to the current point.
  139. if( e.vertex[ 0 ] != edges[ currentEdge ].vertex[ 0 ] &&
  140. e.vertex[ 1 ] != edges[ currentEdge ].vertex[ 0 ] )
  141. continue;
  142. // It's our edge. Continue on with the face that
  143. // isn't our current one.
  144. if( e.face[ 0 ] == currentFace )
  145. currentFace = e.face[ 1 ];
  146. else
  147. currentFace = e.face[ 0 ];
  148. currentEdge = n;
  149. break;
  150. }
  151. }
  152. else if( v1Side == PlaneF::On || v2Side == PlaneF::On )
  153. {
  154. // One of the points of the current edge is on the plane.
  155. // Add that point.
  156. if( v1Side == PlaneF::On )
  157. {
  158. ADD_POINT( points[ v1 ] );
  159. }
  160. else
  161. {
  162. ADD_POINT( points[ v2 ] );
  163. }
  164. // Find edge to continue with.
  165. for( U32 n = 0; n < numEdges; ++ n )
  166. {
  167. const typename Base::EdgeType& e = edges[ n ];
  168. // Skip current edge.
  169. if( n == currentEdge )
  170. continue;
  171. // Skip edges not belonging to current face.
  172. if( e.face[ 0 ] != currentFace && e.face[ 1 ] != currentFace )
  173. continue;
  174. // Skip edges connected to point that is on the plane.
  175. if( v1Side == PlaneF::On )
  176. {
  177. if( e.vertex[ 0 ] == v1 || e.vertex[ 1 ] == v1 )
  178. continue;
  179. }
  180. else
  181. {
  182. if( e.vertex[ 0 ] == v2 || e.vertex[ 1 ] == v2 )
  183. continue;
  184. }
  185. // Skip edges not intersecting the plane.
  186. U32 v1new = e.vertex[ 0 ];
  187. U32 v2new = e.vertex[ 1 ];
  188. const Point3F& p1 = points[ v1new ];
  189. const Point3F& p2 = points[ v2new ];
  190. PlaneF::Side v1SideNew = plane.whichSide( p1 );
  191. PlaneF::Side v2SideNew = plane.whichSide( p2 );
  192. if( v1SideNew != PlaneF::On && v2SideNew != PlaneF::On && !plane.clipSegment( p1, p2, intersection ) )
  193. continue;
  194. // It's our edge. Continue with the face on the
  195. // opposite side.
  196. if( e.face[ 0 ] == currentFace )
  197. currentFace = e.face[ 1 ];
  198. else
  199. currentFace = e.face[ 0 ];
  200. currentEdge = n;
  201. v1 = v1new;
  202. v2 = v2new;
  203. v1Side = v1SideNew;
  204. v2Side = v2SideNew;
  205. break;
  206. }
  207. // Already have computed all the data.
  208. continue;
  209. }
  210. // It's a clean intersecting somewhere along the edge. Add it.
  211. else
  212. {
  213. ADD_POINT( intersection );
  214. }
  215. // Find edge to continue with.
  216. for( U32 n = 0; n < numEdges; ++ n )
  217. {
  218. const typename Base::EdgeType& e = edges[ n ];
  219. // Skip current edge.
  220. if( n == currentEdge )
  221. continue;
  222. // Skip edges not belonging to current face.
  223. if( e.face[ 0 ] != currentFace && e.face[ 1 ] != currentFace )
  224. continue;
  225. // Skip edges not intersecting the plane.
  226. v1 = e.vertex[ 0 ];
  227. v2 = e.vertex[ 1 ];
  228. const Point3F& p1 = points[ v1 ];
  229. const Point3F& p2 = points[ v2 ];
  230. PlaneF::Side v1SideNew = plane.whichSide( p1 );
  231. PlaneF::Side v2SideNew = plane.whichSide( p2 );
  232. if( v1SideNew != PlaneF::On && v2SideNew != PlaneF::On && !plane.clipSegment( p1, p2, intersection ) )
  233. continue;
  234. // It's our edge. Make it the current one.
  235. if( e.face[ 0 ] == currentFace )
  236. currentFace = e.face[ 1 ];
  237. else
  238. currentFace = e.face[ 0 ];
  239. currentEdge = n;
  240. break;
  241. }
  242. }
  243. //TODO: I guess this is insufficient; edges with vertices on the plane may lead us to take different
  244. // paths depending on edge order
  245. while( currentFace != firstFace &&
  246. currentEdge != firstEdge );
  247. return numOutPoints;
  248. #undef ADD_POINT
  249. }
  250. //-----------------------------------------------------------------------------
  251. template< typename Base >
  252. template< typename IndexType >
  253. U32 PolyhedronImpl< Base >::extractFace( U32 plane, IndexType* outIndices, U32 maxOutIndices ) const
  254. {
  255. AssertFatal( plane < this->getNumPlanes(), "PolyhedronImpl::extractFace - Plane index out of range!" );
  256. // This method relies on the fact that vertices on the edges must be CW ordered
  257. // for face[0]. If that is not the case, it is still possible to infer the correct
  258. // ordering by finding one edge and a point not on the edge but still on
  259. // the polygon. By constructing a plane through that edge (simple cross product) and
  260. // then seeing which side the point is on, we know which direction is the right one
  261. // for the polygon. The implicit CW ordering spares us from having to do that, though.
  262. const U32 numEdges = this->getNumEdges();
  263. const Edge* edges = this->getEdges();
  264. // Find first edge that belongs to the plane.
  265. const Edge* firstEdge = 0;
  266. for( U32 i = 0; i < numEdges; ++ i )
  267. {
  268. const Edge& edge = edges[ i ];
  269. if( edge.face[ 0 ] == plane || edge.face[ 1 ] == plane )
  270. {
  271. firstEdge = &edge;
  272. break;
  273. }
  274. }
  275. // If we have found no edge, the polyhedron is degenerate,
  276. // so abort.
  277. if( !firstEdge )
  278. return 0;
  279. // Choose vertex that begins a CCW traversal for this plane.
  280. //
  281. // Note that we expect the planes to be facing inwards by default so we
  282. // go the opposite direction to yield a polygon facing the other way.
  283. U32 idx = 0;
  284. U32 currentVertex;
  285. const Edge* currentEdge = firstEdge;
  286. if( firstEdge->face[ 0 ] == plane )
  287. currentVertex = firstEdge->vertex[ 0 ];
  288. else
  289. currentVertex = firstEdge->vertex[ 1 ];
  290. // Now spider along the edges until we have gathered all indices
  291. // for the plane in the right order.
  292. //
  293. // For larger edge sets, it would be more efficient to first extract
  294. // all edges for the plane and then loop only over this subset to
  295. // spider along the indices. However, we tend to have small sets
  296. // so it should be sufficiently fast to just loop over the original
  297. // set.
  298. U32 indexItr = 0;
  299. do
  300. {
  301. // Add the vertex for the current edge.
  302. if( idx >= maxOutIndices )
  303. return 0;
  304. ++indexItr;
  305. if (indexItr >= 3)
  306. {
  307. outIndices[idx++] = firstEdge->vertex[0];
  308. indexItr = 0;
  309. }
  310. outIndices[idx++] = currentVertex;
  311. // Look for next edge.
  312. for( U32 i = 0; i < numEdges; ++ i )
  313. {
  314. const Edge& edge = edges[ i ];
  315. // Skip if we hit the edge that we are looking to continue from.
  316. if( &edge == currentEdge )
  317. continue;
  318. // Skip edge if it doesn't belong to the current plane.
  319. if( edge.face[ 0 ] != plane && edge.face[ 1 ] != plane )
  320. continue;
  321. // If edge connects to vertex we are looking for, make it
  322. // the current edge and push its other vertex.
  323. if( edge.vertex[ 0 ] == currentVertex )
  324. currentVertex = edge.vertex[ 1 ];
  325. else if( edge.vertex[ 1 ] == currentVertex )
  326. currentVertex = edge.vertex[ 0 ];
  327. else
  328. continue; // Skip edge.
  329. currentEdge = &edge;
  330. break;
  331. }
  332. }
  333. while( currentEdge != firstEdge );
  334. // Done.
  335. return idx;
  336. }
  337. //-----------------------------------------------------------------------------
  338. template< typename Polyhedron >
  339. void PolyhedronData::buildBoxData( Polyhedron& poly, const MatrixF& mat, const Box3F& box, bool invertNormals )
  340. {
  341. AssertFatal( poly.getNumPoints() == 8, "PolyhedronData::buildBox - Incorrect point count!" );
  342. AssertFatal( poly.getNumEdges() == 12, "PolyhedronData::buildBox - Incorrect edge count!" );
  343. AssertFatal( poly.getNumPlanes() == 6, "PolyhedronData::buildBox - Incorrect plane count!" );
  344. // Box is assumed to be axis aligned in the source space.
  345. // Transform into geometry space.
  346. Point3F xvec = mat.getRightVector() * box.len_x();
  347. Point3F yvec = mat.getForwardVector() * box.len_y();
  348. Point3F zvec = mat.getUpVector() * box.len_z();
  349. Point3F min;
  350. mat.mulP( box.minExtents, &min );
  351. // Corner points.
  352. typename Polyhedron::PointListType& pointList = poly.mPointList;
  353. pointList[ 0 ] = min; // near left bottom
  354. pointList[ 1 ] = min + yvec; // far left bottom
  355. pointList[ 2 ] = min + xvec + yvec; // far right bottom
  356. pointList[ 3 ] = min + xvec; // near right bottom
  357. pointList[ 4 ] = pointList[ 0 ] + zvec; // near left top
  358. pointList[ 5 ] = pointList[ 1 ] + zvec; // far left top
  359. pointList[ 6 ] = pointList[ 2 ] + zvec; // far right top
  360. pointList[ 7 ] = pointList[ 3 ] + zvec; // near right top
  361. // Side planes.
  362. typename Polyhedron::PlaneListType& planeList = poly.mPlaneList;
  363. const F32 pos = invertNormals ? -1.f : 1.f;
  364. const F32 neg = - pos;
  365. planeList[ 0 ].set( pointList[ 0 ], xvec * pos ); // left
  366. planeList[ 1 ].set( pointList[ 2 ], yvec * neg ); // far
  367. planeList[ 2 ].set( pointList[ 2 ], xvec * neg ); // right
  368. planeList[ 3 ].set( pointList[ 0 ], yvec * pos ); // front
  369. planeList[ 4 ].set( pointList[ 0 ], zvec * pos ); // bottom
  370. planeList[ 5 ].set( pointList[ 4 ], zvec * neg ); // top
  371. // The edges are constructed so that the vertices
  372. // are oriented clockwise for face[0].
  373. typename Polyhedron::EdgeType* edge = &poly.mEdgeList[ 0 ];
  374. for( U32 i = 0; i < 4; ++ i )
  375. {
  376. S32 n = ( i == 3 ) ? 0: i + 1;
  377. S32 p = ( i == 0 ) ? 3: i - 1;
  378. edge->vertex[ 0 ] = !invertNormals ? n : i;
  379. edge->vertex[ 1 ] = !invertNormals ? i : n;
  380. edge->face[ 0 ] = i;
  381. edge->face[ 1 ] = 4;
  382. edge ++;
  383. edge->vertex[ 0 ] = !invertNormals ? 4 + n : 4 + i;
  384. edge->vertex[ 1 ] = !invertNormals ? 4 + i : 4 + n;
  385. edge->face[ 0 ] = 5;
  386. edge->face[ 1 ] = i;
  387. edge ++;
  388. edge->vertex[ 0 ] = !invertNormals ? 4 + i : i;
  389. edge->vertex[ 1 ] = !invertNormals ? i : 4 + i;
  390. edge->face[ 0 ] = p;
  391. edge->face[ 1 ] = i;
  392. edge ++;
  393. }
  394. }
  395. #endif // _MPOLYHEDRON_IMPL_H_