1 #ifndef GIM_TRI_COLLISION_H_INCLUDED
2 #define GIM_TRI_COLLISION_H_INCLUDED
4 /*! \file gim_tri_collision.h
5 \author Francisco Leon Najera
8 -----------------------------------------------------------------------------
9 This source file is part of GIMPACT Library.
11 For the latest info, see http://gimpact.sourceforge.net/
13 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
14 email: projectileman@yahoo.com
16 This library is free software; you can redistribute it and/or
17 modify it under the terms of EITHER:
18 (1) The GNU Lesser General Public License as published by the Free
19 Software Foundation; either version 2.1 of the License, or (at
20 your option) any later version. The text of the GNU Lesser
21 General Public License is included with this library in the
22 file GIMPACT-LICENSE-LGPL.TXT.
23 (2) The BSD-style license that is included with this library in
24 the file GIMPACT-LICENSE-BSD.TXT.
25 (3) The zlib/libpng license that is included with this library in
26 the file GIMPACT-LICENSE-ZLIB.TXT.
28 This library is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
31 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
33 -----------------------------------------------------------------------------
36 #include "gim_box_collision.h"
37 #include "gim_clip_polygon.h"
42 #define MAX_TRI_CLIPPING 16
44 //! Structure for collision
45 struct GIM_TRIANGLE_CONTACT_DATA
47 GREAL m_penetration_depth;
49 btVector4 m_separating_normal;
50 btVector3 m_points[MAX_TRI_CLIPPING];
52 SIMD_FORCE_INLINE void copy_from(const GIM_TRIANGLE_CONTACT_DATA& other)
54 m_penetration_depth = other.m_penetration_depth;
55 m_separating_normal = other.m_separating_normal;
56 m_point_count = other.m_point_count;
57 GUINT i = m_point_count;
60 m_points[i] = other.m_points[i];
64 GIM_TRIANGLE_CONTACT_DATA()
68 GIM_TRIANGLE_CONTACT_DATA(const GIM_TRIANGLE_CONTACT_DATA& other)
76 //! classify points that are closer
77 template<typename DISTANCE_FUNC,typename CLASS_PLANE>
78 SIMD_FORCE_INLINE void mergepoints_generic(const CLASS_PLANE & plane,
79 GREAL margin, const btVector3 * points, GUINT point_count, DISTANCE_FUNC distance_func)
82 m_penetration_depth= -1000.0f;
84 GUINT point_indices[MAX_TRI_CLIPPING];
88 for(_k=0;_k<point_count;_k++)
90 GREAL _dist = -distance_func(plane,points[_k]) + margin;
94 if(_dist>m_penetration_depth)
96 m_penetration_depth = _dist;
97 point_indices[0] = _k;
100 else if((_dist+G_EPSILON)>=m_penetration_depth)
102 point_indices[m_point_count] = _k;
108 for( _k=0;_k<m_point_count;_k++)
110 m_points[_k] = points[point_indices[_k]];
114 //! classify points that are closer
115 SIMD_FORCE_INLINE void merge_points(const btVector4 & plane, GREAL margin,
116 const btVector3 * points, GUINT point_count)
118 m_separating_normal = plane;
119 mergepoints_generic(plane, margin, points, point_count, DISTANCE_PLANE_3D_FUNC());
124 //! Class for colliding triangles
129 btVector3 m_vertices[3];
131 GIM_TRIANGLE():m_margin(0.1f)
135 SIMD_FORCE_INLINE GIM_AABB get_box() const
137 return GIM_AABB(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
140 SIMD_FORCE_INLINE void get_normal(btVector3 &normal) const
142 TRIANGLE_NORMAL(m_vertices[0],m_vertices[1],m_vertices[2],normal);
145 SIMD_FORCE_INLINE void get_plane(btVector4 &plane) const
147 TRIANGLE_PLANE(m_vertices[0],m_vertices[1],m_vertices[2],plane);;
150 SIMD_FORCE_INLINE void apply_transform(const btTransform & trans)
152 m_vertices[0] = trans(m_vertices[0]);
153 m_vertices[1] = trans(m_vertices[1]);
154 m_vertices[2] = trans(m_vertices[2]);
157 SIMD_FORCE_INLINE void get_edge_plane(GUINT edge_index,const btVector3 &triangle_normal,btVector4 &plane) const
159 const btVector3 & e0 = m_vertices[edge_index];
160 const btVector3 & e1 = m_vertices[(edge_index+1)%3];
161 EDGE_PLANE(e0,e1,triangle_normal,plane);
164 //! Gets the relative transformation of this triangle
166 The transformation is oriented to the triangle normal , and aligned to the 1st edge of this triangle. The position corresponds to vertice 0:
167 - triangle normal corresponds to Z axis.
168 - 1st normalized edge corresponds to X axis,
171 SIMD_FORCE_INLINE void get_triangle_transform(btTransform & triangle_transform) const
173 btMatrix3x3 & matrix = triangle_transform.getBasis();
177 MAT_SET_Z(matrix,zaxis);
179 btVector3 xaxis = m_vertices[1] - m_vertices[0];
180 VEC_NORMALIZE(xaxis);
181 MAT_SET_X(matrix,xaxis);
184 xaxis = zaxis.cross(xaxis);
185 MAT_SET_Y(matrix,xaxis);
187 triangle_transform.setOrigin(m_vertices[0]);
191 //! Test triangles by finding separating axis
193 \param other Triangle for collide
194 \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
196 bool collide_triangle_hard_test(
197 const GIM_TRIANGLE & other,
198 GIM_TRIANGLE_CONTACT_DATA & contact_data) const;
200 //! Test boxes before doing hard test
202 \param other Triangle for collide
203 \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
206 SIMD_FORCE_INLINE bool collide_triangle(
207 const GIM_TRIANGLE & other,
208 GIM_TRIANGLE_CONTACT_DATA & contact_data) const
210 //test box collisioin
211 GIM_AABB boxu(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
212 GIM_AABB boxv(other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin);
213 if(!boxu.has_collision(boxv)) return false;
216 return collide_triangle_hard_test(other,contact_data);
221 Solve the System for u,v parameters:
223 u*axe1[i1] + v*axe2[i1] = vecproj[i1]
224 u*axe1[i2] + v*axe2[i2] = vecproj[i2]
227 v = (vecproj[i2] - u*axe1[i2])/axe2[i2]
229 then the first equation in terms of 'u':
231 --> u*axe1[i1] + ((vecproj[i2] - u*axe1[i2])/axe2[i2])*axe2[i1] = vecproj[i1]
233 --> u*axe1[i1] + vecproj[i2]*axe2[i1]/axe2[i2] - u*axe1[i2]*axe2[i1]/axe2[i2] = vecproj[i1]
235 --> u*(axe1[i1] - axe1[i2]*axe2[i1]/axe2[i2]) = vecproj[i1] - vecproj[i2]*axe2[i1]/axe2[i2]
237 --> u*((axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])/axe2[i2]) = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1])/axe2[i2]
239 --> u*(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) = vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]
241 --> u = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]) /(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])
243 if 0.0<= u+v <=1.0 then they are inside of triangle
245 \return false if the point is outside of triangle.This function doesn't take the margin
247 SIMD_FORCE_INLINE bool get_uv_parameters(
248 const btVector3 & point,
249 const btVector3 & tri_plane,
250 GREAL & u, GREAL & v) const
252 btVector3 _axe1 = m_vertices[1]-m_vertices[0];
253 btVector3 _axe2 = m_vertices[2]-m_vertices[0];
254 btVector3 _vecproj = point - m_vertices[0];
255 GUINT _i1 = (tri_plane.closestAxis()+1)%3;
256 GUINT _i2 = (_i1+1)%3;
257 if(btFabs(_axe2[_i2])<G_EPSILON)
259 u = (_vecproj[_i2]*_axe2[_i1] - _vecproj[_i1]*_axe2[_i2]) /(_axe1[_i2]*_axe2[_i1] - _axe1[_i1]*_axe2[_i2]);
260 v = (_vecproj[_i1] - u*_axe1[_i1])/_axe2[_i1];
264 u = (_vecproj[_i1]*_axe2[_i2] - _vecproj[_i2]*_axe2[_i1]) /(_axe1[_i1]*_axe2[_i2] - _axe1[_i2]*_axe2[_i1]);
265 v = (_vecproj[_i2] - u*_axe1[_i2])/_axe2[_i2];
272 else if(v<-G_EPSILON)
284 else if(sumuv-1.0f>G_EPSILON)
292 //! is point in triangle beam?
294 Test if point is in triangle, with m_margin tolerance
296 SIMD_FORCE_INLINE bool is_point_inside(const btVector3 & point, const btVector3 & tri_normal) const
299 btVector4 edge_plane;
300 this->get_edge_plane(0,tri_normal,edge_plane);
301 GREAL dist = DISTANCE_PLANE_POINT(edge_plane,point);
302 if(dist-m_margin>0.0f) return false; // outside plane
304 this->get_edge_plane(1,tri_normal,edge_plane);
305 dist = DISTANCE_PLANE_POINT(edge_plane,point);
306 if(dist-m_margin>0.0f) return false; // outside plane
308 this->get_edge_plane(2,tri_normal,edge_plane);
309 dist = DISTANCE_PLANE_POINT(edge_plane,point);
310 if(dist-m_margin>0.0f) return false; // outside plane
315 //! Bidireccional ray collision
316 SIMD_FORCE_INLINE bool ray_collision(
317 const btVector3 & vPoint,
318 const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
319 GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
323 btVector3 dif1 = m_vertices[1] - m_vertices[0];
324 btVector3 dif2 = m_vertices[2] - m_vertices[0];
325 VEC_CROSS(faceplane,dif1,dif2);
326 faceplane[3] = m_vertices[0].dot(faceplane);
329 GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
330 if(res == 0) return false;
331 if(! is_point_inside(pout,faceplane)) return false;
333 if(res==2) //invert normal
335 triangle_normal.setValue(-faceplane[0],-faceplane[1],-faceplane[2]);
339 triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
342 VEC_NORMALIZE(triangle_normal);
348 //! one direccion ray collision
349 SIMD_FORCE_INLINE bool ray_collision_front_side(
350 const btVector3 & vPoint,
351 const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
352 GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
356 btVector3 dif1 = m_vertices[1] - m_vertices[0];
357 btVector3 dif2 = m_vertices[2] - m_vertices[0];
358 VEC_CROSS(faceplane,dif1,dif2);
359 faceplane[3] = m_vertices[0].dot(faceplane);
362 GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
363 if(res != 1) return false;
365 if(!is_point_inside(pout,faceplane)) return false;
367 triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
369 VEC_NORMALIZE(triangle_normal);
379 #endif // GIM_TRI_COLLISION_H_INCLUDED