Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/bullet/BulletCollision/Gimpact/gim_tri_collision.h @ 1963

Last change on this file since 1963 was 1963, checked in by rgrieder, 16 years ago

Added Bullet physics engine.

  • Property svn:eol-style set to native
File size: 10.4 KB
Line 
1#ifndef GIM_TRI_COLLISION_H_INCLUDED
2#define GIM_TRI_COLLISION_H_INCLUDED
3
4/*! \file gim_tri_collision.h
5\author Francisco Len Nßjera
6*/
7/*
8-----------------------------------------------------------------------------
9This source file is part of GIMPACT Library.
10
11For the latest info, see http://gimpact.sourceforge.net/
12
13Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
14email: projectileman@yahoo.com
15
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.
27
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.
32
33-----------------------------------------------------------------------------
34*/
35
36#include "gim_box_collision.h"
37#include "gim_clip_polygon.h"
38
39/*! \addtogroup GEOMETRIC_OPERATIONS
40*/
41//! @{
42
43
44
45#define MAX_TRI_CLIPPING 16
46
47//! Structure for collision
48struct GIM_TRIANGLE_CONTACT_DATA
49{
50    GREAL m_penetration_depth;
51    GUINT m_point_count;
52    btVector4 m_separating_normal;
53    btVector3 m_points[MAX_TRI_CLIPPING];
54
55        SIMD_FORCE_INLINE void copy_from(const GIM_TRIANGLE_CONTACT_DATA& other)
56        {
57                m_penetration_depth = other.m_penetration_depth;
58                m_separating_normal = other.m_separating_normal;
59                m_point_count = other.m_point_count;
60                GUINT i = m_point_count;
61                while(i--)
62                {
63                        m_points[i] = other.m_points[i];
64                }
65        }
66
67        GIM_TRIANGLE_CONTACT_DATA()
68        {
69        }
70
71        GIM_TRIANGLE_CONTACT_DATA(const GIM_TRIANGLE_CONTACT_DATA& other)
72        {
73                copy_from(other);
74        }
75
76       
77       
78
79    //! classify points that are closer
80    template<typename DISTANCE_FUNC,typename CLASS_PLANE>
81    SIMD_FORCE_INLINE void mergepoints_generic(const CLASS_PLANE & plane,
82                                GREAL margin, const btVector3 * points, GUINT point_count, DISTANCE_FUNC distance_func)
83    {   
84        m_point_count = 0;
85        m_penetration_depth= -1000.0f;
86
87                GUINT point_indices[MAX_TRI_CLIPPING];
88
89                GUINT _k;
90
91                for(_k=0;_k<point_count;_k++)
92                {
93                        GREAL _dist = -distance_func(plane,points[_k]) + margin;
94
95                        if(_dist>=0.0f)
96                        {
97                                if(_dist>m_penetration_depth)
98                                {
99                                        m_penetration_depth = _dist;
100                                        point_indices[0] = _k;
101                                        m_point_count=1;
102                                }
103                                else if((_dist+G_EPSILON)>=m_penetration_depth)
104                                {
105                                        point_indices[m_point_count] = _k;
106                                        m_point_count++;
107                                }
108                        }
109                }
110
111                for( _k=0;_k<m_point_count;_k++)
112                {
113                        m_points[_k] = points[point_indices[_k]];
114                }
115        }
116
117        //! classify points that are closer
118        SIMD_FORCE_INLINE void merge_points(const btVector4 & plane, GREAL margin,
119                                                                                 const btVector3 * points, GUINT point_count)
120        {
121                m_separating_normal = plane;
122                mergepoints_generic(plane, margin, points, point_count, DISTANCE_PLANE_3D_FUNC());
123        }
124};
125
126
127//! Class for colliding triangles
128class GIM_TRIANGLE
129{
130public:
131        btScalar m_margin;
132    btVector3 m_vertices[3];
133
134    GIM_TRIANGLE():m_margin(0.1f)
135    {
136    }
137
138    SIMD_FORCE_INLINE GIM_AABB get_box()  const
139    {
140        return GIM_AABB(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
141    }
142
143    SIMD_FORCE_INLINE void get_normal(btVector3 &normal)  const
144    {
145        TRIANGLE_NORMAL(m_vertices[0],m_vertices[1],m_vertices[2],normal);
146    }
147
148    SIMD_FORCE_INLINE void get_plane(btVector4 &plane)  const
149    {
150        TRIANGLE_PLANE(m_vertices[0],m_vertices[1],m_vertices[2],plane);;
151    }
152
153    SIMD_FORCE_INLINE void apply_transform(const btTransform & trans)
154    {
155        m_vertices[0] = trans(m_vertices[0]);
156        m_vertices[1] = trans(m_vertices[1]);
157        m_vertices[2] = trans(m_vertices[2]);
158    }
159
160    SIMD_FORCE_INLINE void get_edge_plane(GUINT edge_index,const btVector3 &triangle_normal,btVector4 &plane)  const
161    {
162                const btVector3 & e0 = m_vertices[edge_index];
163                const btVector3 & e1 = m_vertices[(edge_index+1)%3];
164                EDGE_PLANE(e0,e1,triangle_normal,plane);
165    }
166
167    //! Gets the relative transformation of this triangle
168    /*!
169    The transformation is oriented to the triangle normal , and aligned to the 1st edge of this triangle. The position corresponds to vertice 0:
170    - triangle normal corresponds to Z axis.
171    - 1st normalized edge corresponds to X axis,
172
173    */
174    SIMD_FORCE_INLINE void get_triangle_transform(btTransform & triangle_transform)  const
175    {
176        btMatrix3x3 & matrix = triangle_transform.getBasis();
177
178        btVector3 zaxis;
179        get_normal(zaxis);
180        MAT_SET_Z(matrix,zaxis);
181
182        btVector3 xaxis = m_vertices[1] - m_vertices[0];
183        VEC_NORMALIZE(xaxis);
184        MAT_SET_X(matrix,xaxis);
185
186        //y axis
187        xaxis = zaxis.cross(xaxis);
188        MAT_SET_Y(matrix,xaxis);
189
190        triangle_transform.setOrigin(m_vertices[0]);
191    }
192
193
194        //! Test triangles by finding separating axis
195        /*!
196        \param other Triangle for collide
197        \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
198        */
199        bool collide_triangle_hard_test(
200                const GIM_TRIANGLE & other,
201                GIM_TRIANGLE_CONTACT_DATA & contact_data) const;
202
203        //! Test boxes before doing hard test
204        /*!
205        \param other Triangle for collide
206        \param contact_data Structure for holding contact points, normal and penetration depth; The normal is pointing toward this triangle from the other triangle
207        \
208        */
209        SIMD_FORCE_INLINE bool collide_triangle(
210                const GIM_TRIANGLE & other,
211                GIM_TRIANGLE_CONTACT_DATA & contact_data) const
212        {
213                //test box collisioin
214                GIM_AABB boxu(m_vertices[0],m_vertices[1],m_vertices[2],m_margin);
215                GIM_AABB boxv(other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin);
216                if(!boxu.has_collision(boxv)) return false;
217
218                //do hard test
219                return collide_triangle_hard_test(other,contact_data);
220        }
221
222        /*!
223
224        Solve the System for u,v parameters:
225
226        u*axe1[i1] + v*axe2[i1] = vecproj[i1]
227        u*axe1[i2] + v*axe2[i2] = vecproj[i2]
228
229        sustitute:
230        v = (vecproj[i2] - u*axe1[i2])/axe2[i2]
231
232        then the first equation in terms of 'u':
233
234        --> u*axe1[i1] + ((vecproj[i2] - u*axe1[i2])/axe2[i2])*axe2[i1] = vecproj[i1]
235
236        --> u*axe1[i1] + vecproj[i2]*axe2[i1]/axe2[i2] - u*axe1[i2]*axe2[i1]/axe2[i2] = vecproj[i1]
237
238        --> u*(axe1[i1]  - axe1[i2]*axe2[i1]/axe2[i2]) = vecproj[i1] - vecproj[i2]*axe2[i1]/axe2[i2]
239
240        --> u*((axe1[i1]*axe2[i2]  - axe1[i2]*axe2[i1])/axe2[i2]) = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1])/axe2[i2]
241
242        --> u*(axe1[i1]*axe2[i2]  - axe1[i2]*axe2[i1]) = vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]
243
244        --> u = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]) /(axe1[i1]*axe2[i2]  - axe1[i2]*axe2[i1])
245
246if 0.0<= u+v <=1.0 then they are inside of triangle
247
248        \return false if the point is outside of triangle.This function  doesn't take the margin
249        */
250        SIMD_FORCE_INLINE bool get_uv_parameters(
251                        const btVector3 & point,
252                        const btVector3 & tri_plane,
253                        GREAL & u, GREAL & v) const
254        {
255                btVector3 _axe1 = m_vertices[1]-m_vertices[0];
256                btVector3 _axe2 = m_vertices[2]-m_vertices[0];
257                btVector3 _vecproj = point - m_vertices[0];
258                GUINT _i1 = (tri_plane.closestAxis()+1)%3;
259                GUINT _i2 = (_i1+1)%3;
260                if(btFabs(_axe2[_i2])<G_EPSILON)
261                {
262                        u = (_vecproj[_i2]*_axe2[_i1] - _vecproj[_i1]*_axe2[_i2]) /(_axe1[_i2]*_axe2[_i1]  - _axe1[_i1]*_axe2[_i2]);
263                        v = (_vecproj[_i1] - u*_axe1[_i1])/_axe2[_i1];
264                }
265                else
266                {
267                        u = (_vecproj[_i1]*_axe2[_i2] - _vecproj[_i2]*_axe2[_i1]) /(_axe1[_i1]*_axe2[_i2]  - _axe1[_i2]*_axe2[_i1]);
268                        v = (_vecproj[_i2] - u*_axe1[_i2])/_axe2[_i2];
269                }
270
271                if(u<-G_EPSILON)
272                {
273                        return false;
274                }
275                else if(v<-G_EPSILON)
276                {
277                        return false;
278                }
279                else
280                {
281                        float sumuv;
282                        sumuv = u+v;
283                        if(sumuv<-G_EPSILON)
284                        {
285                                return false;
286                        }
287                        else if(sumuv-1.0f>G_EPSILON)
288                        {
289                                return false;
290                        }
291                }
292                return true;
293        }
294
295        //! is point in triangle beam?
296        /*!
297        Test if point is in triangle, with m_margin tolerance
298        */
299        SIMD_FORCE_INLINE bool is_point_inside(const btVector3 & point, const btVector3 & tri_normal) const
300        {
301                //Test with edge 0
302                btVector4 edge_plane;
303                this->get_edge_plane(0,tri_normal,edge_plane);
304                GREAL dist = DISTANCE_PLANE_POINT(edge_plane,point);
305                if(dist-m_margin>0.0f) return false; // outside plane
306
307                this->get_edge_plane(1,tri_normal,edge_plane);
308                dist = DISTANCE_PLANE_POINT(edge_plane,point);
309                if(dist-m_margin>0.0f) return false; // outside plane
310
311                this->get_edge_plane(2,tri_normal,edge_plane);
312                dist = DISTANCE_PLANE_POINT(edge_plane,point);
313                if(dist-m_margin>0.0f) return false; // outside plane
314                return true;
315        }
316
317
318        //! Bidireccional ray collision
319        SIMD_FORCE_INLINE bool ray_collision(
320                const btVector3 & vPoint,
321                const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
322                GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
323        {
324                btVector4 faceplane;
325                {
326                        btVector3 dif1 = m_vertices[1] - m_vertices[0];
327                        btVector3 dif2 = m_vertices[2] - m_vertices[0];
328                VEC_CROSS(faceplane,dif1,dif2);
329                faceplane[3] = m_vertices[0].dot(faceplane);
330                }
331
332                GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
333                if(res == 0) return false;
334                if(! is_point_inside(pout,faceplane)) return false;
335
336                if(res==2) //invert normal
337                {
338                        triangle_normal.setValue(-faceplane[0],-faceplane[1],-faceplane[2]);
339                }
340                else
341                {
342                        triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
343                }
344
345                VEC_NORMALIZE(triangle_normal);
346
347                return true;
348        }
349
350
351        //! one direccion ray collision
352        SIMD_FORCE_INLINE bool ray_collision_front_side(
353                const btVector3 & vPoint,
354                const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal,
355                GREAL & tparam, GREAL tmax = G_REAL_INFINITY)
356        {
357                btVector4 faceplane;
358                {
359                        btVector3 dif1 = m_vertices[1] - m_vertices[0];
360                        btVector3 dif2 = m_vertices[2] - m_vertices[0];
361                VEC_CROSS(faceplane,dif1,dif2);
362                faceplane[3] = m_vertices[0].dot(faceplane);
363                }
364
365                GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax);
366                if(res != 1) return false;
367
368                if(!is_point_inside(pout,faceplane)) return false;
369
370                triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]);
371
372                VEC_NORMALIZE(triangle_normal);
373
374                return true;
375        }
376
377};
378
379
380
381//! @}
382
383#endif // GIM_TRI_COLLISION_H_INCLUDED
Note: See TracBrowser for help on using the repository browser.