D:/Zythum/DinoKod/Common/Math3D.cpp

00001 #include "Common/Assert.h"
00002 #include "Common/Error.h"
00003 #include "Common/Console.h"
00004 #include "Common/Vector.h"
00005 #include "Common/Matrix.h"
00006 #include "Common/Point.h"
00007 #include "Common/Plane.h"
00008 
00009 #include "Common/Math3D.h"
00010 
00011 #define EPSILON 0.1f
00012 #define COLL_TEST_CULL
00013 
00014 //---------------------------------------------------------------------------------------------------------------------
00015 void GetLocalAngleFromNormal( KVector& Normal, float& AngleX, float& AngleY, float& AngleZ )
00016 {
00017         // Angle X
00018         if( ( Normal.y > -0.001f ) && ( Normal.y < 0.001f ) )
00019                 if( ( Normal.z > -0.001f ) && ( Normal.z < 0.001f ) )
00020                         AngleX = 0.0f;
00021                 else
00022                         if( Normal.z > 0.0f )
00023                                 AngleX = PI / 2.0f;
00024                         else
00025                                 AngleX = 3.0f * PI / 2.0f;
00026         else
00027                 if( Normal.y > 0.0f )
00028                         AngleX = atanf( Normal.z / Normal.y );
00029                 else
00030                         AngleX = atanf( Normal.z / Normal.y ) + PI;
00031 
00032         AngleX = fmodf( AngleX + 2.0f * PI, 2.0f * PI );
00033 
00034         // TODO : Angle Y
00035         AngleY = 0.0f;
00036 /*
00037         // Angle Z
00038         if( ( Normal.y > -0.001f ) && ( Normal.y < 0.001f ) )
00039                 if( ( Normal.x > -0.001f ) && ( Normal.x < 0.001f ) )
00040                         AngleZ = 0.0f;
00041                 else
00042                         if( Normal.x > 0.0f )
00043                                 AngleZ = PI / 2.0f;
00044                         else
00045                                 AngleZ = 3.0f * PI / 2.0f;
00046         else
00047                 if( Normal.y > 0.0f )
00048                         AngleZ = atanf( Normal.x / Normal.y );
00049                 else
00050                         AngleZ = atanf( Normal.x / Normal.y ) + PI;
00051 
00052 //      AngleZ = -AngleZ;
00053         AngleZ = fmodf( AngleZ + 2.0f * PI, 2.0f * PI );
00054 */
00055         // Angle Z
00056         if( ( Normal.x > -0.001f ) && ( Normal.x < 0.001f ) )
00057                 if( ( Normal.y > -0.001f ) && ( Normal.y < 0.001f ) )
00058                         AngleZ = 0.0f;
00059                 else
00060                         if( Normal.y > 0.0f )
00061                                 AngleZ = PI / 2.0f;
00062                         else
00063                                 AngleZ = 3.0f * PI / 2.0f;
00064         else
00065                 if( Normal.x > 0.0f )
00066                         AngleZ = atanf( Normal.y / Normal.x );
00067                 else
00068                         AngleZ = atanf( Normal.y / Normal.x ) + PI;
00069 
00070         AngleZ -= PI / 2.0f;
00071         AngleZ = fmodf( AngleZ + 2.0f * PI, 2.0f * PI );
00072 
00073         KVector NormalZ = Normal;
00074 
00075         NormalZ.x = Normal.x * cosf( -AngleZ ) + Normal.y * -sinf( -AngleZ );
00076         NormalZ.y = Normal.x * sinf( -AngleZ ) + Normal.y * cosf( -AngleZ );
00077         NormalZ.z = Normal.z;
00078 
00079         // Angle X
00080         if( ( NormalZ.y > -0.001f ) && ( NormalZ.y < 0.001f ) )
00081                 if( ( NormalZ.z > -0.001f ) && ( NormalZ.z < 0.001f ) )
00082                         AngleX = 0.0f;
00083                 else
00084                         if( NormalZ.z > 0.0f )
00085                                 AngleX = PI / 2.0f;
00086                         else
00087                                 AngleX = 3.0f * PI / 2.0f;
00088         else
00089                 if( NormalZ.y > 0.0f )
00090                         AngleX = atanf( NormalZ.z / NormalZ.y );
00091                 else
00092                         AngleX = atanf( NormalZ.z / NormalZ.y ) + PI;
00093 
00094         AngleX = fmodf( AngleX + 2.0f * PI, 2.0f * PI );
00095 }
00096 
00097 //---------------------------------------------------------------------------------------------------------------------
00098 bool IntersectTriangle( KVector& orig, KVector& dir, KVector& v0, KVector& v1, KVector& v2, float* t, float* u, float* v )
00099 {
00100     // Find vectors for two edges sharing vert0
00101     KVector edge1 = v1 - v0;
00102     KVector edge2 = v2 - v0;
00103 
00104     // Begin calculating determinant - also used to calculate U parameter
00105     KVector pvec;
00106     pvec = KVector::CrossProduct( dir, edge2 );
00107 
00108         KVector Normal = KVector::CrossProduct( edge1, edge2 );
00109         Normal.Normalize();
00110         KPlane  Plane( Normal, KVector::DotProduct( Normal, v0 ) );
00111 
00112         float   fOrig = KVector::DotProduct( Plane.m_Normal, orig ) - Plane.m_Distance;
00113         float   fDir = KVector::DotProduct( Plane.m_Normal, orig + dir ) - Plane.m_Distance;
00114 
00115 
00116 //      g_pConsole << "DISTANCE : " << fOrig << " " << fDir << KENDL;
00117 //      if( ( fabs( fOrig ) < 0.5f ) || ( fabs( fDir ) < 0.5f ) )
00118 //              goto test;
00119 //
00120 //      if( !( ( fOrig > 0.0f ) && ( fDir < 0.0f ) ) )
00121 //              return false;
00122         if( ( ( fOrig > 0.0f ) && ( fDir > 0.0f ) ) || ( ( fOrig < 0.0f ) && ( fDir < 0.0f ) ) )
00123                 return false;
00124 
00125 
00126 //test:
00127     // If determinant is near zero, ray lies in plane of triangle
00128     float det = KVector::DotProduct( edge1, pvec );
00129 
00130 #ifdef COLL_TEST_CULL
00131         
00132         if( det < EPSILON )
00133                 return false;
00134 
00135     // Calculate distance from vert0 to ray origin
00136     KVector tvec = orig - v0;
00137 
00138     // Calculate U parameter and test bounds
00139     *u = KVector::DotProduct( tvec, pvec );
00140     if( *u < 0.0f || *u > det )
00141         return false;
00142 
00143     // Prepare to test V parameter
00144     KVector qvec;
00145         qvec = KVector::CrossProduct( tvec, edge1 );
00146 
00147     // Calculate V parameter and test bounds
00148     *v = KVector::DotProduct( dir, qvec );
00149     if( *v < 0.0f || *u + *v > det )
00150         return false;
00151 
00152     // Calculate t, scale parameters, ray intersects triangle
00153     *t = KVector::DotProduct( edge2, qvec );
00154     float fInvDet = 1.0f / det;
00155     *t *= fInvDet;
00156     *u *= fInvDet;
00157     *v *= fInvDet;
00158 
00159 //      g_pConsole << *t << KENDL;
00160         
00161 //      KASSERT( *t >= 0.0f );
00162 //      if( ( *t > 0.4f ) || ( *t < 10.0f ) )
00163 //              return false;
00164 
00165 #else
00166 
00167         if ((det > -EPSILON) && (det < EPSILON))
00168                 return false; 
00169         
00170         float   inv_det = 1.0f / det;
00171         
00172         // calcule la distance entre l'origine et le premier vertex du triangle
00173         KVector tvec = orig - v0;
00174         
00175         // calcule l'élement u
00176         *u = KVector::DotProduct( tvec, pvec ) * inv_det;
00177         
00178         if ((*u < 0.0f) || (*u > 1.0f))
00179                 return false;
00180         
00181         // Prepare to test v parameter
00182         KVector qvec = KVector::CrossProduct( tvec, edge1 );
00183         
00184         // Calcule le paramètre v
00185         *v = KVector::DotProduct( dir, qvec ) * inv_det;
00186         
00187         if ((*v < 0.0f) || ((*u + *v) > 1.0f))
00188                 return false;
00189            
00190         //calcule la distance entre l'origine et le point de collision.
00191         *t = KVector::DotProduct( edge2, qvec ) * inv_det;
00192 
00193 #endif
00194  
00195         return true;
00196 }
00197 
00198 //---------------------------------------------------------------------------------------------------------------------
00199 bool IntersectTriangleCullNone( KVector& orig, KVector& dir, KVector& v0, KVector& v1, KVector& v2, float* t, float* u, float* v )
00200 {
00201     // Find vectors for two edges sharing vert0
00202     KVector edge1 = v1 - v0;
00203     KVector edge2 = v2 - v0;
00204 
00205     // Begin calculating determinant - also used to calculate U parameter
00206     KVector pvec;
00207     pvec = KVector::CrossProduct( dir, edge2 );
00208 
00209     // If determinant is near zero, ray lies in plane of triangle
00210     float det = KVector::DotProduct( edge1, pvec );
00211 
00212         if ((det > -EPSILON) && (det < EPSILON))
00213                 return false; 
00214         
00215         float   inv_det = 1.0f / det;
00216         
00217         // calcule la distance entre l'origine et le premier vertex du triangle
00218         KVector tvec = orig - v0;
00219         
00220         // calcule l'élement u
00221         *u = KVector::DotProduct( tvec, pvec ) * inv_det;
00222         
00223         if ((*u < 0.0f) || (*u > 1.0f))
00224                 return false;
00225         
00226         // Prepare to test v parameter
00227         KVector qvec = KVector::CrossProduct( tvec, edge1 );
00228         
00229         // Calcule le paramètre v
00230         *v = KVector::DotProduct( dir, qvec ) * inv_det;
00231         
00232         if ((*v < 0.0f) || ((*u + *v) > 1.0f))
00233                 return false;
00234            
00235         //calcule la distance entre l'origine et le point de collision.
00236         *t = KVector::DotProduct( edge2, qvec ) * inv_det;
00237 
00238         return true;
00239 }
00240 
00241 
00242 //---------------------------------------------------------------------------------------------------------------------
00243 bool IntersectTriangle( KVector& center, float radius, KVector& v0, KVector& v1, KVector& v2, KVector* pPoint )
00244 {
00245     // Find vectors for two edges sharing vert0
00246     KVector edge1 = v1 - v0;
00247     KVector edge2 = v2 - v0;
00248     KVector edge3 = v1 - v2;
00249 
00250         KVector Normal = KVector::CrossProduct( edge1, edge2 );
00251         Normal.Normalize();
00252         KPlane  Plane( Normal, KVector::DotProduct( Normal, v0 ) );
00253 
00254         float   fDist = (KVector::DotProduct( Plane.m_Normal, center ) - Plane.m_Distance);
00255 
00256         // La sphere est suffisament loin du plan, pas de collision
00257         if( fDist > radius )
00258                 return false;
00259 
00260         if( fDist < 0.0f )
00261                 return false;
00262 
00263         // La sphere touche le plan
00264 //      *t = -fDist;
00265 
00266         *pPoint = center + Normal * -fDist;
00267 
00268         // Edge 1
00269         KVector ve1 = KVector::CrossProduct( Normal, v1 - v0 );
00270         ve1.Normalize();
00271         KPlane  Plane1( ve1, KVector::DotProduct( ve1, v0 ) );
00272         float   d1 = KVector::DotProduct( Plane1.m_Normal, *pPoint ) - Plane1.m_Distance;
00273         if( d1 < 0.0f )
00274                 return false;
00275 
00276         // Edge 2
00277         KVector ve2 = KVector::CrossProduct( Normal, v0 - v2 );
00278         ve2.Normalize();
00279         KPlane  Plane2( ve2, KVector::DotProduct( ve2, v0 ) );
00280         float   d2 = KVector::DotProduct( Plane2.m_Normal, *pPoint ) - Plane2.m_Distance;
00281         if( d2 < 0.0f )
00282                 return false;
00283 
00284         // Edge 3
00285         KVector ve3 = KVector::CrossProduct( Normal, v2 - v1 );
00286         ve3.Normalize();
00287         KPlane  Plane3( ve3, KVector::DotProduct( ve3, v1 ) );
00288         float   d3 = KVector::DotProduct( Plane3.m_Normal, *pPoint ) - Plane3.m_Distance;
00289         if( d3 < 0.0f )
00290                 return false;
00291 
00292         return true;
00293  /*   // Begin calculating determinant - also used to calculate U parameter
00294     KVector pvec;
00295     pvec = KVector::CrossProduct( dir, edge2 );
00296 
00297     // If determinant is near zero, ray lies in plane of triangle
00298     float det = KVector::DotProduct( edge1, pvec );
00299 
00300         if ((det > -EPSILON) && (det < EPSILON))
00301                 return false; 
00302         
00303         float   inv_det = 1.0f / det;
00304         
00305         // calcule la distance entre l'origine et le premier vertex du triangle
00306         KVector tvec = orig - v0;
00307         
00308         // calcule l'élement u
00309         *u = KVector::DotProduct( tvec, pvec ) * inv_det;
00310         
00311         if ((*u < 0.0f) || (*u > 1.0f))
00312                 return false;
00313         
00314         // Prepare to test v parameter
00315         KVector qvec = KVector::CrossProduct( tvec, edge1 );
00316         
00317         // Calcule le paramètre v
00318         *v = KVector::DotProduct( dir, qvec ) * inv_det;
00319         
00320         if ((*v < 0.0f) || ((*u + *v) > 1.0f))
00321                 return false;
00322            
00323         //calcule la distance entre l'origine et le point de collision.
00324         *t = KVector::DotProduct( edge2, qvec ) * inv_det;
00325         return true;*/
00326 }
00327 
00328 //---------------------------------------------------------------------------------------------------------------------
00329 void ComputePickVector( KMatrix& MatProj, KMatrix& MatView, KPt& PickPoint, KPt& ViewportSize, KVector* PickRayOrig, KVector* PickRayDir )
00330 {
00331         // Compute the vector of the pick ray in screen space
00332         KVector v;
00333         v.x =  ( ( ( 2.0f * PickPoint.x ) / ViewportSize.x ) - 1 ) / MatProj._11;
00334         v.y = -( ( ( 2.0f * PickPoint.y ) / ViewportSize.y ) - 1 ) / MatProj._22;
00335         v.z =  1.0f;
00336 
00337         // Get the inverse view matrix
00338         KMatrix m = MatView;
00339         m.Inverse();
00340 //      m = MatrixInverse( MatView );
00341 
00342         // Transform the screen space pick ray into 3D space
00343         PickRayDir->x  = v.x * m._11 + v.y * m._21 + v.z * m._31;
00344         PickRayDir->y  = v.x * m._12 + v.y * m._22 + v.z * m._32;
00345         PickRayDir->z  = v.x * m._13 + v.y * m._23 + v.z * m._33;
00346         PickRayOrig->x = m._41;
00347         PickRayOrig->y = m._42;
00348         PickRayOrig->z = m._43;
00349 }
00350 
00351 
00352 //---------------------------------------------------------------------------------------------------------------------
00353 //---------------------------------------------------------------------------------------------------------------------
00354 //---------------------------------------------------------------------------------------------------------------------
00355 KVector ClosestPointOnLine( KVector& Point, KVector& v0, KVector& v1 )
00356 {
00357         KVector c = Point - v0;
00358         KVector V = v1 - v0; 
00359         float d = V.Magnitude();
00360 
00361         V.Normalize();
00362         float t = KVector::DotProduct( V, c );
00363 
00364         if( t < 0.0f ) return v0;
00365         if( t > d ) return v1;
00366 
00367         V *= t;
00368 
00369         return v0 + V;  
00370 }
00371 
00372 //---------------------------------------------------------------------------------------------------------------------
00373 KVector ClosestPointOnTriangle( KVector& Point, KVector& v0, KVector& v1, KVector& v2 )
00374 {
00375         KVector r01 = ClosestPointOnLine( Point, v0, v1 );
00376         KVector r12 = ClosestPointOnLine( Point, v1, v2 );
00377         KVector r20 = ClosestPointOnLine( Point, v2, v0 );
00378         KVector m01 = Point - r01;
00379         KVector m12 = Point - r12;
00380         KVector m20 = Point - r20;
00381                                                                          
00382         float d01 = m01.Magnitude();
00383         float d12 = m12.Magnitude();
00384         float d20 = m20.Magnitude();
00385 
00386         float min = d01;
00387         KVector Result = r01;
00388 
00389         if( d12 < min )
00390         {
00391                 min = d12;
00392                 Result = r12;
00393         }
00394 
00395         if( d20 < min )
00396                 Result = r20;
00397 
00398         return Result;  
00399 }
00400 
00401 //---------------------------------------------------------------------------------------------------------------------
00402 bool CheckPointInTriangle( KVector& Point, KVector& v0, KVector& v1, KVector& v2 )
00403 {
00404         float TotalAngles = 0.0f;
00405 
00406         // Calcul les 3 vecteurs
00407         KVector VecteurA = Point - v0;
00408         KVector VecteurB = Point - v1;
00409         KVector VecteurC = Point - v2;
00410 
00411         VecteurA.Normalize();
00412         VecteurB.Normalize();
00413         VecteurC.Normalize();
00414 
00415         TotalAngles += acosf( KVector::DotProduct( VecteurA, VecteurB ) );   
00416         TotalAngles += acosf( KVector::DotProduct( VecteurB, VecteurC ) );
00417         TotalAngles += acosf( KVector::DotProduct( VecteurC, VecteurA ) ); 
00418 
00419         // Teste avec une marge d'erreur
00420         if( fabsf( TotalAngles - 2.0f * PI ) <= 0.005 )
00421                 return true;
00422 
00423         return false;
00424 }
00425 
00426 //---------------------------------------------------------------------------------------------------------------------
00427 bool CheckPointInSphere( KVector Point, KVector& sO, float sR )
00428 {
00429         Point -= sO;
00430         float d = Point.Magnitude();
00431 
00432         if( d <= sR )
00433                 return true;
00434 
00435    return false;
00436 }
00437 /*
00438 //---------------------------------------------------------------------------------------------------------------------
00439 float IntersectRayPlaneDistancef( KVector& RayOrigin, KVector& RayVector, KVector& PointOrigin, KVector& PointNormal )
00440 {
00441         float d = -KVector::DotProduct( PointNormal, PointOrigin );
00442         float numer = KVector::DotProduct( PointNormal, RayOrigin ) + d;
00443         float denom = KVector::DotProduct( PointNormal, RayVector );
00444 
00445         if( denom == 0 )  // La normale est orthogonale au vector, pas d'intersection
00446                 return -1.0f;
00447         
00448         return -( numer / denom );      
00449 }
00450 */
00451 //---------------------------------------------------------------------------------------------------------------------
00452 float IntersectRayPlaneDistance( KVector& RayOrigin, KVector& RayVector, KVector& PointOrigin, KVector& PointNormal )
00453 {
00454         float d = -KVector::DotProduct( PointNormal, PointOrigin );
00455         float numer = KVector::DotProduct( PointNormal, RayOrigin ) + d;
00456         float denom = KVector::DotProduct( PointNormal, RayVector );
00457 
00458         if( denom == 0 )        // La normale est orthogonale au vector, pas d'intersection
00459                 return -1.0f;
00460 
00461         return -( numer / denom );      
00462 }
00463 
00464 //---------------------------------------------------------------------------------------------------------------------
00465 float IntersectRaySphere( KVector& RayOrigin, KVector& RayVector, KVector& SphereOrigin, float SphereRadius )
00466 {
00467         KVector Q = SphereOrigin - RayOrigin;
00468         float   c = Q.Magnitude();
00469         float   v = KVector::DotProduct( Q, RayVector );
00470         float   d = SphereRadius * SphereRadius - ( c * c - v * v );
00471 
00472         if( d < 0.0f )
00473                 return -1.0f;
00474 
00475         return v - sqrtf( d );
00476 }
00477 
00478 //---------------------------------------------------------------------------------------------------------------------
00479 float IntersectRayPlaneDistance( KVector& RayOrigin, KVector& RayVector, KVector& PlaneNormal, float PlaneDist )
00480 {
00481         float   CosAlpha;
00482         float   Delta;
00483 
00484         CosAlpha = KVector::DotProduct( RayVector, PlaneNormal );
00485 
00486         // parallel to the plane (alpha=90)
00487         if( CosAlpha == 0 )
00488                 return -1.0f;
00489 
00490         Delta = PlaneDist - KVector::DotProduct( RayOrigin, PlaneNormal );
00491 
00492         return ( Delta / CosAlpha );
00493 }
00494 
00495 //---------------------------------------------------------------------------------------------------------------------
00496 bool GetLowestRoot( float a, float b, float c, float maxR, float* root )
00497 {
00498         // Check if a solution exists
00499         float determinant = b * b - 4.0f * a * c;
00500 
00501         // If determinant is negative it means no solutions.
00502         if( determinant < 0.0f )
00503                 return false;
00504 
00505         // calculate the two roots: (if determinant == 0 then
00506         // x1==x2 but let’s disregard that slight optimization)
00507         float sqrtD = sqrtf( determinant );
00508         float r1 = (-b - sqrtD) / (2*a);
00509         float r2 = (-b + sqrtD) / (2*a);
00510 
00511         // Sort so x1 <= x2
00512         if (r1 > r2)
00513         {
00514                 float temp = r2;
00515                 r2 = r1;
00516                 r1 = temp;
00517         }
00518 
00519         // Get lowest root:
00520         if (r1 > 0 && r1 < maxR)
00521         {
00522                 *root = r1;
00523                 return true;
00524         }
00525 
00526         // It is possible that we want x2 - this can happen
00527         // if x1 < 0
00528         if (r2 > 0 && r2 < maxR)
00529         {
00530                 *root = r2;
00531                 return true;
00532         }
00533         // No (valid) solutions
00534         return false;
00535 }
00536 /*
00537 //---------------------------------------------------------------------------------------------------------------------
00538 bool CheckSphereCollision( KVector& Center, float Radius, KVector& Velocity, KVector& v0, KVector& v1, KVector& v2, KVector* pPoint, KVector* pNormal )
00539 {
00540         // Normalize la vélocité
00541         KVector NormalizedVelocity = Velocity;
00542         NormalizedVelocity.Normalize();
00543 
00544         // Calcule les vecteurs des cotés
00545     KVector Edge1 = v1 - v0;
00546     KVector Edge2 = v2 - v0;
00547 
00548         // Calcule la normale du triangle
00549         *pNormal = KVector::CrossProduct( Edge1, Edge2 );
00550         pNormal->Normalize();
00551 
00552         // Calcule le plan du triangle
00553         KPlane  Plane( *pNormal, KVector::DotProduct( v0, *pNormal ) );
00554 
00555         // Calcule le point d'intersection de la sphere
00556         KVector SpherePoint = Center - (*pNormal * Radius);
00557 
00558         // Determine la position du point d'intersection de la sphere par rapport au plan du triangle
00559         KVector PlanePoint;
00560         float   Distance;
00561         
00562         if( Plane.GetPointSide( SpherePoint ) == KPPS_FRONTSIDE )
00563         {
00564                 // Devant
00565                 // Calcule le point d'intersection du plan
00566                 Distance        = IntersectRayPlaneDistance( SpherePoint, NormalizedVelocity, v0, *pNormal );
00567                 PlanePoint  = SpherePoint + NormalizedVelocity * Distance;
00568         }
00569         else
00570         {
00571                 // Derrière
00572                 // Calcule le point d'intersection du plan
00573                 Distance        = IntersectRayPlaneDistance( SpherePoint, *pNormal, v0, *pNormal );
00574                 PlanePoint      = SpherePoint + *pNormal * Distance;
00575         }
00576 
00577         // Determine le point d'intersection de la sphere avec le triangle s'il y en a 1
00578         KVector TrianglePoint = PlanePoint;
00579 
00580         // Teste si le point d'intersection est dans le triangle
00581         if( !CheckPointInTriangle( PlanePoint, v0, v1, v2 ) ) 
00582         {
00583                 return false;
00584 
00585                 // Calcule le point le plus proche
00586                 TrianglePoint = ClosestPointOnTriangle( PlanePoint, v0, v1, v2 );
00587                 Distance = IntersectRayPlaneDistance( TrianglePoint, -NormalizedVelocity, Center, KVector( 1.0f, 1.0f, 1.0f ) );
00588 
00589                 if( Distance > 0.0f )
00590                 {
00591                         SpherePoint = TrianglePoint + (-NormalizedVelocity) * Distance;
00592                 }
00593         }
00594 
00595         if( ( Distance >= 0.0f ) && ( Distance <= Velocity.Magnitude() ) )
00596         {
00597                 *pPoint = TrianglePoint;
00598                 return true;
00599         }
00600 
00601         return false;
00602 }
00603 */
00604 
00605 //#include "Common/Console.h"
00606 //---------------------------------------------------------------------------------------------------------------------
00607 bool CheckSphereCollision( KCollisionData* pData, KVector v0, KVector v1, KVector v2, float Epsilon )
00608 {
00609         // Scale les vertex dans l'espace de l'ellipse
00610         v0 /= pData->m_Radius;
00611         v1 /= pData->m_Radius;
00612         v2 /= pData->m_Radius;
00613 
00614         // Normalize la vélocité
00615         KVector NormalizedVelocity = pData->m_Velocity;
00616         NormalizedVelocity.Normalize();
00617 
00618         // Calcule les vecteurs des cotés
00619     KVector Edge1 = v1 - v0;
00620     KVector Edge2 = v2 - v0;
00621 
00622         // Calcule la normale du triangle
00623         KVector Normal = KVector::CrossProduct( Edge1, Edge2 );
00624         Normal.Normalize();
00625 
00626         // Calcule le plan du triangle
00627         KPlane  Plane( Normal, KVector::DotProduct( v0, Normal ) );
00628 
00629         // Calcule le point d'intersection de la sphere
00630         KVector SpherePoint = pData->m_Position - Normal;
00631 
00632         // Determine la position du point d'intersection de la sphere par rapport au plan du triangle
00633         KVector PlanePoint;
00634         float   Distance;
00635         
00636         if( Plane.GetPointSide( SpherePoint, Epsilon ) == KPPS_BACKSIDE )
00637         {
00638                 // Derrière
00639                 // Calcule le point d'intersection du plan
00640                 Distance        = IntersectRayPlaneDistance( SpherePoint, Normal, v0, Normal );
00641                 PlanePoint      = SpherePoint + Normal * Distance;
00642 //              g_Console << "KPPS_BACKSIDE" << KENDL;
00643         }
00644         else
00645         {
00646                 // Devant
00647                 // Calcule le point d'intersection du plan
00648                 Distance        = IntersectRayPlaneDistance( SpherePoint, NormalizedVelocity, v0, Normal );
00649                 PlanePoint  = SpherePoint + NormalizedVelocity * Distance;
00650 //              g_Console << "KPPS_FRONTSIDE" << KENDL;
00651         }
00652 
00653         // Determine le point d'intersection de la sphere avec le triangle s'il y en a 1
00654         KVector TrianglePoint = PlanePoint;
00655 
00656         // Teste si le point d'intersection est dans le triangle
00657         if( !CheckPointInTriangle( PlanePoint, v0, v1, v2 ) ) 
00658         {
00659                 // Calcule le point le plus proche
00660                 TrianglePoint = ClosestPointOnTriangle( PlanePoint, v0, v1, v2 );
00661                 Distance = IntersectRaySphere( TrianglePoint, -NormalizedVelocity, pData->m_Position, 1.0f );
00662 
00663                 if( Distance > 0.0f )
00664                 {
00665                         SpherePoint = TrianglePoint - NormalizedVelocity * Distance;
00666                 }
00667         }
00668 
00669         // Gestion de l'erreur
00670         if( CheckPointInSphere( TrianglePoint, pData->m_Position, 1.0f ) )
00671                 pData->m_bStuck = true;
00672 
00673         // Resultat
00674         if( ( Distance > 0.0f ) && ( Distance <= pData->m_Velocity.Magnitude() ) )
00675         {
00676                 if( ( pData->m_bFoundCollision == false ) || ( Distance < pData->m_NearestDistance ) )
00677                 {
00678                         pData->m_NearestDistance                                        = Distance;
00679                         pData->m_NearestIntersectionPoint                       = SpherePoint;
00680                         pData->m_NearestPolygonIntersectionPoint        = TrianglePoint;
00681                         pData->m_bFoundCollision                                        = true;
00682                         return true;
00683                 }
00684         }
00685 
00686         return false;
00687 }
00688 
00689 //---------------------------------------------------------------------------------------------------------------------
00690 // Improved Collision detection and Response
00691 // Kasper Fauerby
00692 // kasper@peroxide.dk
00693 // http://www.peroxide.dk
00694 // 25th July 2003
00695 //---------------------------------------------------------------------------------------------------------------------
00696 void CheckSphereCollision2( KCollisionData2* pData, KVector v0, KVector v1, KVector v2 )
00697 {
00698         v0 /= pData->m_eRadius;
00699         v1 /= pData->m_eRadius;
00700         v2 /= pData->m_eRadius;
00701 
00702         // Make the plane containing this triangle.
00703         KPlane  TrianglePlane( v0, v1, v2 );
00704 
00705         // Is triangle front-facing to the velocity vector?
00706         // We only check front-facing triangles
00707         // (your choice of course)
00708         if( TrianglePlane.IsFrontFacingTo( pData->m_NormalizedVelocity ) )
00709         {
00710                 // Get interval of plane intersection:
00711                 float   t0, t1;
00712                 bool    bEmbeddedInPlane = false;
00713                 
00714                 // Calculate the signed distance from sphere
00715                 // position to triangle plane
00716                 float SignedDistToTrianglePlane = (float)TrianglePlane.SignedDistanceTo( pData->m_BasePoint );
00717 
00718                 // cache this as we’re going to use it a few times below:
00719                 float NormalDotVelocity = TrianglePlane.m_Normal.DotProductf( pData->m_Velocity );
00720                 
00721                 // if sphere is travelling parrallel to the plane:
00722                 if( NormalDotVelocity == 0.0f )
00723                 {
00724                         if( fabs( SignedDistToTrianglePlane ) >= 1.0f )
00725                         {
00726                                 // Sphere is not embedded in plane.
00727                                 // No collision possible:
00728                                 return;
00729                         }
00730                         else
00731                         {
00732                                 // sphere is embedded in plane.
00733                                 // It intersects in the whole range [0..1]
00734                                 bEmbeddedInPlane = true;
00735                                 t0 = 0.0;
00736                                 t1 = 1.0;
00737                         }
00738                 }
00739                 else
00740                 {
00741                         // N dot D is not 0. Calculate intersection interval:
00742                         t0 = ( -1.0f - SignedDistToTrianglePlane ) / NormalDotVelocity;
00743                         t1 = ( 1.0f - SignedDistToTrianglePlane ) / NormalDotVelocity;
00744                         
00745                         // Swap so t0 < t1
00746                         if( t0 > t1 )
00747                         {
00748                                 float temp = t1;
00749                                 t1 = t0;
00750                                 t0 = temp;
00751                         }
00752 
00753                         // Check that at least one result is within range:
00754                         if( t0 > 1.0f || t1 < 0.0f )
00755                         {
00756                                 // Both t values are outside values [0,1]
00757                                 // No collision possible:
00758                                 return;
00759                         }
00760 
00761                         // Clamp to [0,1]
00762                         if (t0 < 0.0) t0 = 0.0;
00763                         if (t1 < 0.0) t1 = 0.0;
00764                         if (t0 > 1.0) t0 = 1.0;
00765                         if (t1 > 1.0) t1 = 1.0;
00766                 }
00767 
00768                 // OK, at this point we have two time values t0 and t1
00769                 // between which the swept sphere intersects with the
00770                 // triangle plane. If any collision is to occur it must
00771                 // happen within this interval.
00772                 KVector CollisionPoint;
00773                 bool    bFoundCollison = false;
00774                 float   t = 1.0;
00775                 // First we check for the easy case - collision inside
00776                 // the triangle. If this happens it must be at time t0
00777                 // as this is when the sphere rests on the front side
00778                 // of the triangle plane. Note, this can only happen if
00779                 // the sphere is not embedded in the triangle plane.
00780                 if( !bEmbeddedInPlane )
00781                 {
00782                         KVector PlaneIntersectionPoint = ( pData->m_BasePoint - TrianglePlane.m_Normal ) + pData->m_Velocity * t0;
00783 
00784                         if( CheckPointInTriangle( PlaneIntersectionPoint, v0, v1, v2 ) )
00785                         {
00786                                 bFoundCollison = true;
00787                                 t = t0;
00788                                 CollisionPoint = PlaneIntersectionPoint;
00789                         }
00790                 }
00791                 // if we haven’t found a collision already we’ll have to
00792                 // sweep sphere against points and edges of the triangle.
00793                 // Note: A collision inside the triangle (the check above)
00794                 // will always happen before a vertex or edge collision!
00795                 // This is why we can skip the swept test if the above
00796                 // gives a collision!
00797                 if( bFoundCollison == false )
00798                 {
00799                         // some commonly used terms:
00800                         KVector Velocity = pData->m_Velocity;
00801                         KVector Base = pData->m_BasePoint;
00802                         float VelocitySquaredLength = Velocity.SquareMagnitude();
00803                         float a,b,c; // Params for equation
00804                         float newT;
00805                         // For each vertex or edge a quadratic equation have to
00806                         // be solved. We parameterize this equation as
00807                         // a*t^2 + b*t + c = 0 and below we calculate the
00808                         // parameters a,b and c for each test.
00809                         // Check against points:
00810                         a = VelocitySquaredLength;
00811         
00812                         // P1
00813                         b = 2.0f * Velocity.DotProductf( Base - v0 );
00814                         c = ( v0 - Base ).SquareMagnitude() - 1.0f;
00815                         if( GetLowestRoot( a, b, c, t, &newT ) )
00816                         {
00817                                 t = newT;
00818                                 bFoundCollison = true;
00819                                 CollisionPoint = v0;
00820                         }
00821 
00822                         // P2
00823                         b = 2.0f * Velocity.DotProductf( Base - v1 );
00824                         c = ( v1 - Base ).SquareMagnitude() - 1.0f;
00825                         if( GetLowestRoot( a, b, c, t, &newT ) )
00826                         {
00827                                 t = newT;
00828                                 bFoundCollison = true;
00829                                 CollisionPoint = v1;
00830                         }
00831 
00832                         // P3
00833                         b = 2.0f * Velocity.DotProductf( Base - v2 );
00834                         c = ( v2 - Base ).SquareMagnitude() - 1.0f;
00835                         if( GetLowestRoot( a, b, c, t, &newT ) )
00836                         {
00837                                 t = newT;
00838                                 bFoundCollison = true;
00839                                 CollisionPoint = v2;
00840                         }
00841 
00842                         // Check agains edges:
00843                         // p1 -> p2:
00844                         KVector Edge                            = v1 - v0;
00845                         KVector BaseToVertex            = v0 - Base;
00846                         float EdgeSquaredLength         = Edge.SquareMagnitude();
00847                         float EdgeDotVelocity           = Edge.DotProductf( Velocity );
00848                         float EdgeDotBaseToVertex       = Edge.DotProductf( BaseToVertex );
00849 
00850                         // Calculate parameters for equation
00851                         a = EdgeSquaredLength * -VelocitySquaredLength + EdgeDotVelocity * EdgeDotVelocity;
00852                         b = EdgeSquaredLength * ( 2.0f * Velocity.DotProductf( BaseToVertex ) ) - 2.0f * EdgeDotVelocity * EdgeDotBaseToVertex;
00853                         c = EdgeSquaredLength * ( 1.0f - BaseToVertex.SquareMagnitude() ) + EdgeDotBaseToVertex * EdgeDotBaseToVertex;
00854 
00855                         // Does the swept sphere collide against infinite edge?
00856                         if( GetLowestRoot( a, b, c, t, &newT ) )
00857                         {
00858                                 // Check if intersection is within line segment:
00859                                 float f = ( EdgeDotVelocity * newT - EdgeDotBaseToVertex ) / EdgeSquaredLength;
00860                                 if( f >= 0.0f && f <= 1.0f )
00861                                 {
00862                                         // intersection took place within segment.
00863                                         t = newT;
00864                                         bFoundCollison = true;
00865                                         CollisionPoint = v0 + Edge * f;
00866                                 }
00867                         }
00868 
00869                         // p2 -> p3:
00870                         Edge                            = v2 - v1;
00871                         BaseToVertex            = v1 - Base;
00872                         EdgeSquaredLength       = Edge.SquareMagnitude();
00873                         EdgeDotVelocity         = Edge.DotProductf( Velocity );
00874                         EdgeDotBaseToVertex     = Edge.DotProductf( BaseToVertex );
00875                         a = EdgeSquaredLength * -VelocitySquaredLength + EdgeDotVelocity * EdgeDotVelocity;
00876                         b = EdgeSquaredLength * ( 2.0f * Velocity.DotProductf( BaseToVertex ) ) - 2.0f * EdgeDotVelocity * EdgeDotBaseToVertex;
00877                         c = EdgeSquaredLength * ( 1.0f - BaseToVertex.SquareMagnitude() ) + EdgeDotBaseToVertex * EdgeDotBaseToVertex;
00878                         
00879                         if( GetLowestRoot( a, b, c, t, &newT ) )
00880                         {
00881                                 float f = ( EdgeDotVelocity * newT - EdgeDotBaseToVertex ) / EdgeSquaredLength;
00882                                 if( f >= 0.0f && f <= 1.0f )
00883                                 {
00884                                         t = newT;
00885                                         bFoundCollison = true;
00886                                         CollisionPoint = v1 + Edge * f;
00887                                 }
00888                         }
00889 
00890                         // v2 -> v0:
00891                         Edge                            = v0 - v2;
00892                         BaseToVertex            = v2 - Base;
00893                         EdgeSquaredLength       = Edge.SquareMagnitude();
00894                         EdgeDotVelocity         = Edge.DotProductf( Velocity );
00895                         EdgeDotBaseToVertex = Edge.DotProductf( BaseToVertex );
00896                         a = EdgeSquaredLength * -VelocitySquaredLength + EdgeDotVelocity * EdgeDotVelocity;
00897                         b = EdgeSquaredLength * ( 2.0f * Velocity.DotProductf( BaseToVertex ) ) - 2.0f * EdgeDotVelocity * EdgeDotBaseToVertex;
00898                         c = EdgeSquaredLength * ( 1.0f - BaseToVertex.SquareMagnitude() ) + EdgeDotBaseToVertex * EdgeDotBaseToVertex;
00899 
00900                         if ( GetLowestRoot( a, b, c, t, &newT ) )
00901                         {
00902                                 float f = ( EdgeDotVelocity * newT - EdgeDotBaseToVertex ) / EdgeSquaredLength;
00903                                 if( f >= 0.0f && f <= 1.0f )
00904                                 {
00905                                         t = newT;
00906                                         bFoundCollison = true;
00907                                         CollisionPoint = v2 + Edge * f;
00908                                 }
00909                         }
00910                 }
00911 
00912                 // Set result:
00913                 if( bFoundCollison == true )
00914                 {
00915                         // distance to collision: ’t’ is time of collision
00916                         float DistToCollision = t * pData->m_Velocity.Magnitude();
00917 
00918                         // Does this triangle qualify for the closest hit?
00919                         // it does if it’s the first hit or the closest
00920                         if( pData->m_bFoundCollision == false || DistToCollision < pData->m_NearestDistance )
00921                         {
00922                                 // Collision information nessesary for sliding
00923                                 pData->m_NearestDistance        = DistToCollision;
00924                                 pData->m_IntersectionPoint      = CollisionPoint;
00925                                 pData->m_CollisionNormal        = TrianglePlane.m_Normal;
00926                                 pData->m_bFoundCollision        = true;
00927                         }
00928                 }
00929         } // if not backface
00930 }
00931 
00932 /*
00933 //---------------------------------------------------------------------------------------------------------------------
00934 bool CheckSphereCollision( KCollisionData* pData, KVector v0, KVector v1, KVector v2 )
00935 {
00936         double  DistanceToTravel = pData->m_Velocity.Magnitude();
00937 
00938         // Plan du poly
00939         KVector Origin = v0;
00940         KVector Normal = KVector::CrossProduct( v1 - v0, v2 - v0 );
00941         Normal.Normalize();
00942         
00943         // Distance entre le plan et le centre de la sphere
00944         double  Distance = IntersectRayPlaneDistance( Origin, Normal, pData->m_Position, -Normal );
00945         KVector SphereIntersection;
00946         KVector PlaneIntersection;
00947 
00948         if( Distance < 0.0f )
00949         {
00950                 return false;
00951         }
00952         else if( Distance <= 1.0f )
00953         {
00954                 PlaneIntersection = pData->m_Position - Normal * Distance;
00955         }
00956         else
00957         {
00958                 SphereIntersection = pData->m_Position + Normal;
00959                 
00960                 KVector Velocity = pData->m_Velocity;
00961                 Velocity.Normalize();
00962                 double  t = IntersectRayPlaneDistance( Origin, Normal, SphereIntersection, Velocity );
00963 
00964                 if( t < 0.0f )
00965                         return false;
00966 
00967                 PlaneIntersection = SphereIntersection + Velocity * t;
00968         }
00969 
00970         KVector PolyIntersection = PlaneIntersection;
00971 
00972         // Teste si le point d'intersection est dans le triangle
00973         if( !CheckPointInTriangle( PlaneIntersection, v0, v1, v2 ) ) 
00974         { 
00975                 // Calcule le point le plus proche
00976                 PolyIntersection = ClosestPointOnTriangle( PlaneIntersection, v0, v1, v2 );
00977         }
00978 
00979         double  t = IntersectRaySphere( PolyIntersection, -pData->m_Velocity, pData->m_Position, 1.0f );
00980 
00981         if( t >= 0.0f && t <= DistanceToTravel )
00982         {
00983                 KVector Velocity = pData->m_Velocity;
00984                 Velocity.Normalize();
00985                 KVector Intersection = PolyIntersection - Velocity * t;
00986 
00987                 if( ( !pData->m_bFoundCollision ) || ( t < pData->m_NearestDistance ) )
00988                 {
00989                         pData->m_NearestDistance                                        = t;
00990                         pData->m_NearestIntersectionPoint                       = Intersection;
00991                         pData->m_NearestPolygonIntersectionPoint        = PolyIntersection;
00992                         pData->m_bFoundCollision                                        = true;
00993                         return true;
00994                 }
00995         }
00996 
00997         return false;
00998 }
00999 
01000 */
01001 
01002 //---------------------------------------------------------------------------------------------------------------------
01003 bool CheckRayEllipse( KVector& vRayOrigin, KVector& vRayDestination, KVector& vEllipseOrigin, KVector& vEllipseRadius, float* pFraction )
01004 {
01005         return CheckRaySphere( vRayOrigin / vEllipseRadius, vRayDestination / vEllipseRadius, vEllipseOrigin / vEllipseRadius, 1.0f, pFraction );
01006 }
01007 
01008 //---------------------------------------------------------------------------------------------------------------------
01009 bool CheckRaySphere( KVector& vRayOrigin, KVector& vRayDestination, KVector& vSphereCenter, float SphereRadius, float* pFraction )
01010 {
01011         KVector RayParam = vRayDestination - vRayOrigin;
01012         // a = i² + j² + k²
01013         // b = 2i(x1 - l) + 2j(y1 - m) + 2k(z1 - n)
01014         // c = l² + m² + n² + x1² + y1² + z1² + 2(-lx1 - my1 - nz1) - r²
01015         float   a = SQR( RayParam.x ) + SQR( RayParam.y ) + SQR( RayParam.z );
01016         float   b = 2.0f * RayParam.x * ( vRayOrigin.x - vSphereCenter.x ) + 2.0f * RayParam.y * ( vRayOrigin.y - vSphereCenter.y ) + 2.0f * RayParam.z * ( vRayOrigin.z - vSphereCenter.z );
01017         float   c = SQR( vSphereCenter.x ) + SQR( vSphereCenter.y ) + SQR( vSphereCenter.z )
01018                                 + SQR( vRayOrigin.x ) + SQR( vRayOrigin.y ) + SQR( vRayOrigin.z )
01019                                 + 2.0f * ( -vSphereCenter.x * vRayOrigin.x - vSphereCenter.y * vRayOrigin.y - vSphereCenter.z * vRayOrigin.z )
01020                                 - SQR( SphereRadius );
01021 
01022         // Calcul le déterminant d = b²-4ac
01023         float   d = SQR( b ) - 4.0f * a * c;
01024 
01025         // Pas de solutions
01026         if( d < 0.0f )
01027         {
01028                 *pFraction = 1.0f;
01029                 return false;
01030         }
01031 
01032         // 1 solution -b/2a
01033         if( d == 0.0f )
01034         {
01035                 *pFraction = -b / (2.0f * a);
01036                 return true;
01037         }
01038 
01039         // 2 solutions -b-Va/2a -b+Va/2a
01040         float   sqrta = sqrtf( a );
01041         float   t0 = (-b - sqrta) / (2.0f * a);
01042         float   t1 = (-b + sqrta) / (2.0f * a);
01043         *pFraction = (t0 < t1) ? t0 : t1;
01044         
01045         return true;
01046 }
01047 

Generated on Sun Mar 25 20:02:10 2007 for Zythum Project by  doxygen 1.5.1-p1