gim_tri_collision.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #ifndef GIM_TRI_COLLISION_H_INCLUDED
  2. #define GIM_TRI_COLLISION_H_INCLUDED
  3. /*! \file gim_tri_collision.h
  4. \author Francisco Leon Najera
  5. */
  6. /*
  7. -----------------------------------------------------------------------------
  8. This source file is part of GIMPACT Library.
  9. For the latest info, see http://gimpact.sourceforge.net/
  10. Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
  11. email: projectileman@yahoo.com
  12. This library is free software; you can redistribute it and/or
  13. modify it under the terms of EITHER:
  14. (1) The GNU Lesser General Public License as published by the Free
  15. Software Foundation; either version 2.1 of the License, or (at
  16. your option) any later version. The text of the GNU Lesser
  17. General Public License is included with this library in the
  18. file GIMPACT-LICENSE-LGPL.TXT.
  19. (2) The BSD-style license that is included with this library in
  20. the file GIMPACT-LICENSE-BSD.TXT.
  21. (3) The zlib/libpng license that is included with this library in
  22. the file GIMPACT-LICENSE-ZLIB.TXT.
  23. This library is distributed in the hope that it will be useful,
  24. but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
  26. GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
  27. -----------------------------------------------------------------------------
  28. */
  29. #include "gim_box_collision.h"
  30. #include "gim_clip_polygon.h"
  31. #ifndef MAX_TRI_CLIPPING
  32. #define MAX_TRI_CLIPPING 16
  33. #endif
  34. //! Structure for collision
  35. struct GIM_TRIANGLE_CONTACT_DATA
  36. {
  37. GREAL m_penetration_depth;
  38. GUINT m_point_count;
  39. btVector4 m_separating_normal;
  40. btVector3 m_points[MAX_TRI_CLIPPING];
  41. SIMD_FORCE_INLINE void copy_from(const GIM_TRIANGLE_CONTACT_DATA& other)
  42. {
  43. m_penetration_depth = other.m_penetration_depth;
  44. m_separating_normal = other.m_separating_normal;
  45. m_point_count = other.m_point_count;
  46. GUINT i = m_point_count;
  47. while(i--)
  48. {
  49. m_points[i] = other.m_points[i];
  50. }
  51. }
  52. GIM_TRIANGLE_CONTACT_DATA()
  53. {
  54. }
  55. GIM_TRIANGLE_CONTACT_DATA(const GIM_TRIANGLE_CONTACT_DATA& other)
  56. {
  57. copy_from(other);
  58. }
  59. //! classify points that are closer
  60. template<typename DISTANCE_FUNC,typename CLASS_PLANE>
  61. SIMD_FORCE_INLINE void mergepoints_generic(const CLASS_PLANE & plane,
  62. GREAL margin, const btVector3 * points, GUINT point_count, DISTANCE_FUNC distance_func)
  63. {
  64. m_point_count = 0;
  65. m_penetration_depth= -1000.0f;
  66. GUINT point_indices[MAX_TRI_CLIPPING];
  67. GUINT _k;
  68. for(_k=0;_k<point_count;_k++)
  69. {
  70. GREAL _dist = -distance_func(plane,points[_k]) + margin;
  71. if(_dist>=0.0f)
  72. {
  73. if(_dist>m_penetration_depth)
  74. {
  75. m_penetration_depth = _dist;
  76. point_indices[0] = _k;
  77. m_point_count=1;
  78. }
  79. else if((_dist+G_EPSILON)>=m_penetration_depth)
  80. {
  81. point_indices[m_point_count] = _k;
  82. m_point_count++;
  83. }
  84. }
  85. }
  86. for( _k=0;_k<m_point_count;_k++)
  87. {
  88. m_points[_k] = points[point_indices[_k]];
  89. }
  90. }
  91. //! classify points that are closer
  92. SIMD_FORCE_INLINE void merge_points(const btVector4 & plane, GREAL margin,
  93. const btVector3 * points, GUINT point_count)
  94. {
  95. m_separating_normal = plane;
  96. mergepoints_generic(plane, margin, points, point_count, DISTANCE_PLANE_3D_FUNC());
  97. }
  98. };
  99. //! Class for colliding triangles
  100. class GIM_TRIANGLE
  101. {
  102. public:
  103. btScalar m_margin;
  104. btVector3 m_vertices[3];
  105. GIM_TRIANGLE():m_margin(0.1f)
  106. {
  107. }
  108. SIMD_FORCE_INLINE GIM_AABB get_box() const
  109. {
  110. return GIM_AABB(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
  111. }
  112. SIMD_FORCE_INLINE void get_normal(btVector3 &normal) const
  113. {
  114. TRIANGLE_NORMAL(m_vertices[0],m_vertices[1],m_vertices[2],normal);
  115. }
  116. SIMD_FORCE_INLINE void get_plane(btVector4 &plane) const
  117. {
  118. TRIANGLE_PLANE(m_vertices[0],m_vertices[1],m_vertices[2],plane);;
  119. }
  120. SIMD_FORCE_INLINE void apply_transform(const btTransform & trans)
  121. {
  122. m_vertices[0] = trans(m_vertices[0]);
  123. m_vertices[1] = trans(m_vertices[1]);
  124. m_vertices[2] = trans(m_vertices[2]);
  125. }
  126. SIMD_FORCE_INLINE void get_edge_plane(GUINT edge_index,const btVector3 &triangle_normal,btVector4 &plane) const
  127. {
  128. const btVector3 & e0 = m_vertices[edge_index];
  129. const btVector3 & e1 = m_vertices[(edge_index+1)%3];
  130. EDGE_PLANE(e0,e1,triangle_normal,plane);
  131. }
  132. //! Gets the relative transformation of this triangle
  133. /*!
  134. The transformation is oriented to the triangle normal , and aligned to the 1st edge of this triangle. The position corresponds to vertice 0:
  135. - triangle normal corresponds to Z axis.
  136. - 1st normalized edge corresponds to X axis,
  137. */
  138. SIMD_FORCE_INLINE void get_triangle_transform(btTransform & triangle_transform) const
  139. {
  140. btMatrix3x3 & matrix = triangle_transform.getBasis();
  141. btVector3 zaxis;
  142. get_normal(zaxis);
  143. MAT_SET_Z(matrix,zaxis);
  144. btVector3 xaxis = m_vertices[1] - m_vertices[0];
  145. VEC_NORMALIZE(xaxis);
  146. MAT_SET_X(matrix,xaxis);
  147. //y axis
  148. xaxis = zaxis.cross(xaxis);
  149. MAT_SET_Y(matrix,xaxis);
  150. triangle_transform.setOrigin(m_vertices[0]);
  151. }
  152. //! Test triangles by finding separating axis
  153. /*!
  154. \param other Triangle for collide
  155. \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
  156. */
  157. bool collide_triangle_hard_test(
  158. const GIM_TRIANGLE & other,
  159. GIM_TRIANGLE_CONTACT_DATA & contact_data) const;
  160. //! Test boxes before doing hard test
  161. /*!
  162. \param other Triangle for collide
  163. \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
  164. \
  165. */
  166. SIMD_FORCE_INLINE bool collide_triangle(
  167. const GIM_TRIANGLE & other,
  168. GIM_TRIANGLE_CONTACT_DATA & contact_data) const
  169. {
  170. //test box collisioin
  171. GIM_AABB boxu(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
  172. GIM_AABB boxv(other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin);
  173. if(!boxu.has_collision(boxv)) return false;
  174. //do hard test
  175. return collide_triangle_hard_test(other,contact_data);
  176. }
  177. /*!
  178. Solve the System for u,v parameters:
  179. u*axe1[i1] + v*axe2[i1] = vecproj[i1]
  180. u*axe1[i2] + v*axe2[i2] = vecproj[i2]
  181. sustitute:
  182. v = (vecproj[i2] - u*axe1[i2])/axe2[i2]
  183. then the first equation in terms of 'u':
  184. --> u*axe1[i1] + ((vecproj[i2] - u*axe1[i2])/axe2[i2])*axe2[i1] = vecproj[i1]
  185. --> u*axe1[i1] + vecproj[i2]*axe2[i1]/axe2[i2] - u*axe1[i2]*axe2[i1]/axe2[i2] = vecproj[i1]
  186. --> u*(axe1[i1] - axe1[i2]*axe2[i1]/axe2[i2]) = vecproj[i1] - vecproj[i2]*axe2[i1]/axe2[i2]
  187. --> u*((axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])/axe2[i2]) = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1])/axe2[i2]
  188. --> u*(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) = vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]
  189. --> u = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]) /(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])
  190. if 0.0<= u+v <=1.0 then they are inside of triangle
  191. \return false if the point is outside of triangle.This function doesn't take the margin
  192. */
  193. SIMD_FORCE_INLINE bool get_uv_parameters(
  194. const btVector3 & point,
  195. const btVector3 & tri_plane,
  196. GREAL & u, GREAL & v) const
  197. {
  198. btVector3 _axe1 = m_vertices[1]-m_vertices[0];
  199. btVector3 _axe2 = m_vertices[2]-m_vertices[0];
  200. btVector3 _vecproj = point - m_vertices[0];
  201. GUINT _i1 = (tri_plane.closestAxis()+1)%3;
  202. GUINT _i2 = (_i1+1)%3;
  203. if(btFabs(_axe2[_i2])<G_EPSILON)
  204. {
  205. u = (_vecproj[_i2]*_axe2[_i1] - _vecproj[_i1]*_axe2[_i2]) /(_axe1[_i2]*_axe2[_i1] - _axe1[_i1]*_axe2[_i2]);
  206. v = (_vecproj[_i1] - u*_axe1[_i1])/_axe2[_i1];
  207. }
  208. else
  209. {
  210. u = (_vecproj[_i1]*_axe2[_i2] - _vecproj[_i2]*_axe2[_i1]) /(_axe1[_i1]*_axe2[_i2] - _axe1[_i2]*_axe2[_i1]);
  211. v = (_vecproj[_i2] - u*_axe1[_i2])/_axe2[_i2];
  212. }
  213. if(u<-G_EPSILON)
  214. {
  215. return false;
  216. }
  217. else if(v<-G_EPSILON)
  218. {
  219. return false;
  220. }
  221. else
  222. {
  223. btScalar sumuv;
  224. sumuv = u+v;
  225. if(sumuv<-G_EPSILON)
  226. {
  227. return false;
  228. }
  229. else if(sumuv-1.0f>G_EPSILON)
  230. {
  231. return false;
  232. }
  233. }
  234. return true;
  235. }
  236. //! is point in triangle beam?
  237. /*!
  238. Test if point is in triangle, with m_margin tolerance
  239. */
  240. SIMD_FORCE_INLINE bool is_point_inside(const btVector3 & point, const btVector3 & tri_normal) const
  241. {
  242. //Test with edge 0
  243. btVector4 edge_plane;
  244. this->get_edge_plane(0,tri_normal,edge_plane);
  245. GREAL dist = DISTANCE_PLANE_POINT(edge_plane,point);
  246. if(dist-m_margin>0.0f) return false; // outside plane
  247. this->get_edge_plane(1,tri_normal,edge_plane);
  248. dist = DISTANCE_PLANE_POINT(edge_plane,point);
  249. if(dist-m_margin>0.0f) return false; // outside plane
  250. this->get_edge_plane(2,tri_normal,edge_plane);
  251. dist = DISTANCE_PLANE_POINT(edge_plane,point);
  252. if(dist-m_margin>0.0f) return false; // outside plane
  253. return true;
  254. }
  255. //! Bidireccional ray collision
  256. SIMD_FORCE_INLINE bool ray_collision(
  257. const btVector3 & vPoint,
  258. const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
  259. GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
  260. {
  261. btVector4 faceplane;
  262. {
  263. btVector3 dif1 = m_vertices[1] - m_vertices[0];
  264. btVector3 dif2 = m_vertices[2] - m_vertices[0];
  265. VEC_CROSS(faceplane,dif1,dif2);
  266. faceplane[3] = m_vertices[0].dot(faceplane);
  267. }
  268. GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
  269. if(res == 0) return false;
  270. if(! is_point_inside(pout,faceplane)) return false;
  271. if(res==2) //invert normal
  272. {
  273. triangle_normal.setValue(-faceplane[0],-faceplane[1],-faceplane[2]);
  274. }
  275. else
  276. {
  277. triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
  278. }
  279. VEC_NORMALIZE(triangle_normal);
  280. return true;
  281. }
  282. //! one direccion ray collision
  283. SIMD_FORCE_INLINE bool ray_collision_front_side(
  284. const btVector3 & vPoint,
  285. const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
  286. GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
  287. {
  288. btVector4 faceplane;
  289. {
  290. btVector3 dif1 = m_vertices[1] - m_vertices[0];
  291. btVector3 dif2 = m_vertices[2] - m_vertices[0];
  292. VEC_CROSS(faceplane,dif1,dif2);
  293. faceplane[3] = m_vertices[0].dot(faceplane);
  294. }
  295. GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
  296. if(res != 1) return false;
  297. if(!is_point_inside(pout,faceplane)) return false;
  298. triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
  299. VEC_NORMALIZE(triangle_normal);
  300. return true;
  301. }
  302. };
  303. #endif // GIM_TRI_COLLISION_H_INCLUDED