Blender V2.61 - r43446

gim_tri_collision.h

Go to the documentation of this file.
00001 #ifndef GIM_TRI_COLLISION_H_INCLUDED
00002 #define GIM_TRI_COLLISION_H_INCLUDED
00003 
00007 /*
00008 -----------------------------------------------------------------------------
00009 This source file is part of GIMPACT Library.
00010 
00011 For the latest info, see http://gimpact.sourceforge.net/
00012 
00013 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
00014 email: projectileman@yahoo.com
00015 
00016  This library is free software; you can redistribute it and/or
00017  modify it under the terms of EITHER:
00018    (1) The GNU Lesser General Public License as published by the Free
00019        Software Foundation; either version 2.1 of the License, or (at
00020        your option) any later version. The text of the GNU Lesser
00021        General Public License is included with this library in the
00022        file GIMPACT-LICENSE-LGPL.TXT.
00023    (2) The BSD-style license that is included with this library in
00024        the file GIMPACT-LICENSE-BSD.TXT.
00025    (3) The zlib/libpng license that is included with this library in
00026        the file GIMPACT-LICENSE-ZLIB.TXT.
00027 
00028  This library is distributed in the hope that it will be useful,
00029  but WITHOUT ANY WARRANTY; without even the implied warranty of
00030  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
00031  GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
00032 
00033 -----------------------------------------------------------------------------
00034 */
00035 
00036 #include "gim_box_collision.h"
00037 #include "gim_clip_polygon.h"
00038 
00039 
00040 
00041 
00042 #define MAX_TRI_CLIPPING 16
00043 
00045 struct GIM_TRIANGLE_CONTACT_DATA
00046 {
00047     GREAL m_penetration_depth;
00048     GUINT m_point_count;
00049     btVector4 m_separating_normal;
00050     btVector3 m_points[MAX_TRI_CLIPPING];
00051 
00052     SIMD_FORCE_INLINE void copy_from(const GIM_TRIANGLE_CONTACT_DATA& other)
00053     {
00054         m_penetration_depth = other.m_penetration_depth;
00055         m_separating_normal = other.m_separating_normal;
00056         m_point_count = other.m_point_count;
00057         GUINT i = m_point_count;
00058         while(i--)
00059         {
00060             m_points[i] = other.m_points[i];
00061         }
00062     }
00063 
00064     GIM_TRIANGLE_CONTACT_DATA()
00065     {
00066     }
00067 
00068     GIM_TRIANGLE_CONTACT_DATA(const GIM_TRIANGLE_CONTACT_DATA& other)
00069     {
00070         copy_from(other);
00071     }
00072 
00073     
00074     
00075 
00077     template<typename DISTANCE_FUNC,typename CLASS_PLANE>
00078     SIMD_FORCE_INLINE void mergepoints_generic(const CLASS_PLANE & plane,
00079                     GREAL margin, const btVector3 * points, GUINT point_count, DISTANCE_FUNC distance_func)
00080     {   
00081         m_point_count = 0;
00082         m_penetration_depth= -1000.0f;
00083 
00084         GUINT point_indices[MAX_TRI_CLIPPING];
00085 
00086         GUINT _k;
00087 
00088         for(_k=0;_k<point_count;_k++)
00089         {
00090             GREAL _dist = -distance_func(plane,points[_k]) + margin;
00091 
00092             if(_dist>=0.0f)
00093             {
00094                 if(_dist>m_penetration_depth)
00095                 {
00096                     m_penetration_depth = _dist;
00097                     point_indices[0] = _k;
00098                     m_point_count=1;
00099                 }
00100                 else if((_dist+G_EPSILON)>=m_penetration_depth)
00101                 {
00102                     point_indices[m_point_count] = _k;
00103                     m_point_count++;
00104                 }
00105             }
00106         }
00107 
00108         for( _k=0;_k<m_point_count;_k++)
00109         {
00110             m_points[_k] = points[point_indices[_k]];
00111         }
00112     }
00113 
00115     SIMD_FORCE_INLINE void merge_points(const btVector4 & plane, GREAL margin,
00116                                          const btVector3 * points, GUINT point_count)
00117     {
00118         m_separating_normal = plane;
00119         mergepoints_generic(plane, margin, points, point_count, DISTANCE_PLANE_3D_FUNC());
00120     }
00121 };
00122 
00123 
00125 class GIM_TRIANGLE
00126 {
00127 public:
00128     btScalar m_margin;
00129     btVector3 m_vertices[3];
00130 
00131     GIM_TRIANGLE():m_margin(0.1f)
00132     {
00133     }
00134 
00135     SIMD_FORCE_INLINE GIM_AABB get_box()  const
00136     {
00137         return GIM_AABB(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
00138     }
00139 
00140     SIMD_FORCE_INLINE void get_normal(btVector3 &normal)  const
00141     {
00142         TRIANGLE_NORMAL(m_vertices[0],m_vertices[1],m_vertices[2],normal);
00143     }
00144 
00145     SIMD_FORCE_INLINE void get_plane(btVector4 &plane)  const
00146     {
00147         TRIANGLE_PLANE(m_vertices[0],m_vertices[1],m_vertices[2],plane);;
00148     }
00149 
00150     SIMD_FORCE_INLINE void apply_transform(const btTransform & trans)
00151     {
00152         m_vertices[0] = trans(m_vertices[0]);
00153         m_vertices[1] = trans(m_vertices[1]);
00154         m_vertices[2] = trans(m_vertices[2]);
00155     }
00156 
00157     SIMD_FORCE_INLINE void get_edge_plane(GUINT edge_index,const btVector3 &triangle_normal,btVector4 &plane)  const
00158     {
00159         const btVector3 & e0 = m_vertices[edge_index];
00160         const btVector3 & e1 = m_vertices[(edge_index+1)%3];
00161         EDGE_PLANE(e0,e1,triangle_normal,plane);
00162     }
00163 
00165 
00171     SIMD_FORCE_INLINE void get_triangle_transform(btTransform & triangle_transform)  const
00172     {
00173         btMatrix3x3 & matrix = triangle_transform.getBasis();
00174 
00175         btVector3 zaxis;
00176         get_normal(zaxis);
00177         MAT_SET_Z(matrix,zaxis);
00178 
00179         btVector3 xaxis = m_vertices[1] - m_vertices[0];
00180         VEC_NORMALIZE(xaxis);
00181         MAT_SET_X(matrix,xaxis);
00182 
00183         //y axis
00184         xaxis = zaxis.cross(xaxis);
00185         MAT_SET_Y(matrix,xaxis);
00186 
00187         triangle_transform.setOrigin(m_vertices[0]);
00188     }
00189 
00190 
00192 
00196     bool collide_triangle_hard_test(
00197         const GIM_TRIANGLE & other,
00198         GIM_TRIANGLE_CONTACT_DATA & contact_data) const;
00199 
00201 
00206     SIMD_FORCE_INLINE bool collide_triangle(
00207         const GIM_TRIANGLE & other,
00208         GIM_TRIANGLE_CONTACT_DATA & contact_data) const
00209     {
00210         //test box collisioin
00211         GIM_AABB boxu(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
00212         GIM_AABB boxv(other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin);
00213         if(!boxu.has_collision(boxv)) return false;
00214 
00215         //do hard test
00216         return collide_triangle_hard_test(other,contact_data);
00217     }
00218 
00247     SIMD_FORCE_INLINE bool get_uv_parameters(
00248             const btVector3 & point,
00249             const btVector3 & tri_plane,
00250             GREAL & u, GREAL & v) const
00251     {
00252         btVector3 _axe1 = m_vertices[1]-m_vertices[0];
00253         btVector3 _axe2 = m_vertices[2]-m_vertices[0];
00254         btVector3 _vecproj = point - m_vertices[0];
00255         GUINT _i1 = (tri_plane.closestAxis()+1)%3;
00256         GUINT _i2 = (_i1+1)%3;
00257         if(btFabs(_axe2[_i2])<G_EPSILON)
00258         {
00259             u = (_vecproj[_i2]*_axe2[_i1] - _vecproj[_i1]*_axe2[_i2]) /(_axe1[_i2]*_axe2[_i1]  - _axe1[_i1]*_axe2[_i2]);
00260             v = (_vecproj[_i1] - u*_axe1[_i1])/_axe2[_i1];
00261         }
00262         else
00263         {
00264             u = (_vecproj[_i1]*_axe2[_i2] - _vecproj[_i2]*_axe2[_i1]) /(_axe1[_i1]*_axe2[_i2]  - _axe1[_i2]*_axe2[_i1]);
00265             v = (_vecproj[_i2] - u*_axe1[_i2])/_axe2[_i2];
00266         }
00267 
00268         if(u<-G_EPSILON)
00269         {
00270             return false;
00271         }
00272         else if(v<-G_EPSILON)
00273         {
00274             return false;
00275         }
00276         else
00277         {
00278             btScalar sumuv;
00279             sumuv = u+v;
00280             if(sumuv<-G_EPSILON)
00281             {
00282                 return false;
00283             }
00284             else if(sumuv-1.0f>G_EPSILON)
00285             {
00286                 return false;
00287             }
00288         }
00289         return true;
00290     }
00291 
00293 
00296     SIMD_FORCE_INLINE bool is_point_inside(const btVector3 & point, const btVector3 & tri_normal) const
00297     {
00298         //Test with edge 0
00299         btVector4 edge_plane;
00300         this->get_edge_plane(0,tri_normal,edge_plane);
00301         GREAL dist = DISTANCE_PLANE_POINT(edge_plane,point);
00302         if(dist-m_margin>0.0f) return false; // outside plane
00303 
00304         this->get_edge_plane(1,tri_normal,edge_plane);
00305         dist = DISTANCE_PLANE_POINT(edge_plane,point);
00306         if(dist-m_margin>0.0f) return false; // outside plane
00307 
00308         this->get_edge_plane(2,tri_normal,edge_plane);
00309         dist = DISTANCE_PLANE_POINT(edge_plane,point);
00310         if(dist-m_margin>0.0f) return false; // outside plane
00311         return true;
00312     }
00313 
00314 
00316     SIMD_FORCE_INLINE bool ray_collision(
00317         const btVector3 & vPoint,
00318         const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
00319         GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
00320     {
00321         btVector4 faceplane;
00322         {
00323             btVector3 dif1 = m_vertices[1] - m_vertices[0];
00324             btVector3 dif2 = m_vertices[2] - m_vertices[0];
00325             VEC_CROSS(faceplane,dif1,dif2);
00326             faceplane[3] = m_vertices[0].dot(faceplane);
00327         }
00328 
00329         GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
00330         if(res == 0) return false;
00331         if(! is_point_inside(pout,faceplane)) return false;
00332 
00333         if(res==2) //invert normal
00334         {
00335             triangle_normal.setValue(-faceplane[0],-faceplane[1],-faceplane[2]);
00336         }
00337         else
00338         {
00339             triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
00340         }
00341 
00342         VEC_NORMALIZE(triangle_normal);
00343 
00344         return true;
00345     }
00346 
00347 
00349     SIMD_FORCE_INLINE bool ray_collision_front_side(
00350         const btVector3 & vPoint,
00351         const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
00352         GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
00353     {
00354         btVector4 faceplane;
00355         {
00356             btVector3 dif1 = m_vertices[1] - m_vertices[0];
00357             btVector3 dif2 = m_vertices[2] - m_vertices[0];
00358             VEC_CROSS(faceplane,dif1,dif2);
00359             faceplane[3] = m_vertices[0].dot(faceplane);
00360         }
00361 
00362         GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
00363         if(res != 1) return false;
00364 
00365         if(!is_point_inside(pout,faceplane)) return false;
00366 
00367         triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
00368 
00369         VEC_NORMALIZE(triangle_normal);
00370 
00371         return true;
00372     }
00373 
00374 };
00375 
00376 
00377 
00378 
00379 #endif // GIM_TRI_COLLISION_H_INCLUDED