mPolyhedron.impl.h 15 KB

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