#include "stdafx.h" #include "EternityEngine.h" #include "intersectUtil.h" const float EPSILON = 0.000001f; CIntersectUtil::CIntersectUtil(void) { } CIntersectUtil::~CIntersectUtil(void) { } // :*: ±³Â÷ ÆÇÁ¤ÀÇ ¿ø¸® ¹× ¼ø¼­ :*: // 1. ¿ì¼±, ±¤¼±ÀÇ ½ÃÀÛ Á¡ µÚÂÊ¿¡ ÀÖ´ÂÁö ÆÇÁ¤Çؼ­ µÚÂÊ¿¡ ÀÖÀ¸¸é 100% Ãæµ¹ ½ÇÆÐÀ̹ǷΠ±×´ë·Î ¸®ÅÏÇÑ´Ù. // ±¤¼±ÀÇ ¹æÇâ º¤ÅÍ¿Í ±¤¼±ÀÇ ½ÃÀÛÁ¡¿¡¼­ ±¸ÀÇ Áß½ÉÀ¸·Î ÇâÇÑ º¤ÅÍÀÇ ³»ÀûÀÌ À½¼ö, Áï, µÎ Á÷¼±ÀÌ ÀÌ·ç´Â // °¢ÀÌ µÐ°¢ÀÏ ¶§À̰í, ±¤¼±ÀÇ ½ÃÀÛÁ¡ÀÌ ±¸ÀÇ ¿ÜºÎÀÏ °æ¿ì°¡ µÇ°Ú´Ù. // // 2. ±× ´ÙÀ½¿¡, ±¤¼± ½ÃÀÛÁ¡¿¡¼­ ±¸ÀÇ Á߽ɱîÁöÀÇ °Å¸®¿Í ±¤¼±°ú ±¸ÀÇ Á߽ɱîÁö ±×Àº ¼±ºÐ°ú ÇÇŸ°í¶ó½ºÀÇ ¹ýÄ¢À» »ç¿ëÇÏ¿© // µÎ Á÷¼±ÀÇ °Å¸®¸¦ ±¸ÇÑ´Ù. ±× °Å¸®°¡ ¹ÝÁö¸§ º¸´Ù Å©¸é Ãæµ¹½ÇÆÐ. bool CIntersectUtil::RaySphereIntersect( const IN EtVector3& vRayStartPos, const IN EtVector3& vRayDir /* ¹Ýµå½Ã Á¤±ÔÈ­ µÈ º¤ÅÍ */, const IN float fRadius, const IN EtVector3& vSpherePos, OUT EtVector3* pvNearIntersectPos, OUT EtVector3* pvFarIntersectPos ) { EtVector3 vRayStartToCenter; float fDotResult = 0.0f; float fLengthSqA = 0.0f; // ±¤¼± ½ÃÀÛÁ¡¿¡¼­ ±¸ÀÇ Á߽ɱîÁöÀÇ °Å¸® Á¦°ö float fLengthSqB = 0.0f; // ±¸ÀÇ Á߽ɿ¡¼­ ±¸ÀÇ Á¢Á¡±îÁöÀÇ °Å¸® Á¦°ö float fLengthSqC = 0.0f; // ±¤¼± ½ÃÀÛÁ¡¿¡¼­ ±¸¿ÍÀÇ Á¢Á¡±îÁöÀÇ °Å¸® Á¦°ö float fRadiusSq = fRadius * fRadius; vRayStartToCenter = vSpherePos - vRayStartPos; fDotResult = EtVec3Dot( &vRayDir, &vRayStartToCenter ); fLengthSqA = EtVec3LengthSq( &vRayStartToCenter ); if( fDotResult < 0.0f && fLengthSqA > fRadiusSq ) return false; fLengthSqC = fDotResult * fDotResult; fLengthSqB = fLengthSqA - fLengthSqC; if( fRadiusSq < fLengthSqB ) return false; if( NULL != pvNearIntersectPos || NULL != pvFarIntersectPos ) { fLengthSqC = fRadiusSq - fLengthSqB; if( pvNearIntersectPos ) *pvNearIntersectPos = vRayStartPos + (fDotResult - sqrt(fLengthSqC)) * vRayDir; if( pvFarIntersectPos ) *pvFarIntersectPos = vRayStartPos + (fDotResult + sqrt(fLengthSqC)) * vRayDir; } return true; } // Á÷¼±°ú Æò¸éÀÇ ±³Â÷ ÆÇÁ¤ //int RayTriIntersect(CVector orig, CVector dir,CVector vert0, CVector vert1, CVector vert2, // Scalar *t, Scalar *u, Scalar *v) //{ // CVector edge1, edge2, tvec, pvec, qvec; // Scalar det,inv_det; // // /* find vectors for two edges sharing vert0 */ // SUB(edge1, vert1, vert0); // SUB(edge2, vert2, vert0); // // /* begin calculating determinant - also used to calculate U parameter */ // CROSS(pvec, dir, edge2); // // /* if determinant is near zero, ray lies in plane of triangle */ // det = DOT(edge1, pvec); // //#ifdef TEST_CULL /* define TEST_CULL if culling is desired */ // if (det < EPSILON) // return 0; // // /* calculate distance from vert0 to ray origin */ // SUB(tvec, orig, vert0); // // /* calculate U parameter and test bounds */ // *u = DOT(tvec, pvec); // if (*u < 0.0 || *u > det) // return 0; // // /* prepare to test V parameter */ // CROSS(qvec, tvec, edge1); // // /* calculate V parameter and test bounds */ // *v = DOT(dir, qvec); // if (*v < 0.0 || *u + *v > det) // return 0; // // /* calculate t, scale parameters, ray intersects triangle */ // *t = DOT(edge2, qvec); // inv_det = 1.0 / det; // *t *= inv_det; // *u *= inv_det; // *v *= inv_det; //#else /* the non-culling branch */ // if (det > -EPSILON && det < EPSILON) // return 0; // inv_det = 1.0 / det; // // /* calculate distance from vert0 to ray origin */ // SUB(tvec, orig, vert0); // // /* calculate U parameter and test bounds */ // *u = DOT(tvec, pvec) * inv_det; // if (*u < 0.0 || *u > 1.0) // return 0; // // /* prepare to test V parameter */ // CROSS(qvec, tvec, edge1); // // /* calculate V parameter and test bounds */ // *v = DOT(dir, qvec) * inv_det; // if (*v < 0.0 || *u + *v > 1.0) // return 0; // // /* calculate t, ray intersects triangle */ // *t = DOT(edge2, qvec) * inv_det; //#endif // return 1; // Á÷¼±°ú Æú¸®°ïÀÇ ±³Â÷ÆÇÁ¤ bool CIntersectUtil::RayTriIntersect( const IN EtVector3& vRayStart, const IN EtVector3& vRayDir, /* Á¤±ÔÈ­µÈ º¤ÅÍ */ const IN EtVector3 vVert0, const IN EtVector3 vVert1, const IN EtVector3 vVert2, float *t, float *u, float *v ) { EtVector3 vEdge[ 2 ]; EtVector3 vTvec, vPvec, vQvec; float fDet = 0.0f; float fInv_det = 0.0f; // vVert0 À» °øÀ¯ÇÏ´Â µÎ °³ÀÇ º¯À» ±¸ÇÑ´Ù. vEdge[ 0 ] = vVert1 - vVert0; vEdge[ 1 ] = vVert2 - vVert0; // Çà·Ä½ÄÀ» °è»êÇϱ⠽ÃÀÛÇÑ´Ù. ÀÌ °ªÀº U °ªÀ» °è»êÇÒ ¶§µµ ¾²ÀδÙ. EtVec3Cross( &vPvec, &vRayDir, &vEdge[ 1 ] ); // Çà·Ä½ÄÀÌ Á¦·Î¿¡ °¡±î¿öÁö¸é Ray°¡ Æò¸é°ú ÆòÇàÇÏ´Ù´Â »ç½Ç~!! ±×·³ Àý´ë·Î Ãæµ¹ÀÌ ÀϾ ¼ö°¡ ¾øÁö. fDet = EtVec3Dot( &vEdge[ 0 ], &vPvec ); #ifdef TEST_CULL // Èĸé ÄøµµÈ °Í ±îÁö ÀüºÎ °è»ê? if( det < EPSILON ) return false; // vVert0 ºÎÅÍ Á÷¼±ÀÇ ¿øÁ¡±îÁöÀÇ °Å¸® vTvec = vRayStart - vVert0; // U °ªÀ» °è»êÇÏ°í ¹üÀ§¾È¿¡ ÀÖ´ÂÁö üũÇÑ´Ù. *u = EtVec3Dot( &vTvec, &vPvec ); if( *u < 0.0f || *u > fDet ) return false; // V °ª Å×½ºÆ®¸¦ À§ÇÑ Áغñ EtVec3Cross( &vQvec, &vTvec, &vEdge[ 0 ] ); // V °ªÀÌ ¹üÀ§¾È¿¡ ÀÖ´ÂÁö üũÇÑ´Ù. *v = EtVec3Dot( &vRayDir, &vQvec ); if( *v < 0.0f || *u + *v > det ) return false; // T °ªÀ» °è»êÇϰí È®´ë ÆÄ¶ó¸ÞÅ͸¦ ¸¸µé¾î¼­ Àû¿ëÇØÁØ´Ù. *t = EtVec3Dot( &vRayDir, &vQvec ); fInv_det = 1.0f / fDet; *t *= fInv_det; *u *= fInv_det; *v *= fInv_det; #else // ÄøµÀ» ¾È ¾µ°æ¿ì. if( fDet > -EPSILON && fDet < EPSILON ) return false; fInv_det = 1.0f / fDet; // vVert0 ºÎÅÍ RayStart ±îÁöÀÇ °Å¸® vTvec = vRayStart - vVert0; // U °ª °è»ê *u = EtVec3Dot( &vTvec, &vPvec ) * fInv_det; if( *u < 0.0f || *u > 1.0f ) return false; // V °ª °è»ê EtVec3Cross( &vQvec, &vTvec, &vEdge[ 0 ] ); *v = EtVec3Dot( &vRayDir, &vQvec ) * fInv_det; if( *v < 0.0f || *u + *v > 1.0f ) return 0; *t = EtVec3Dot( &vEdge[ 1 ], &vQvec ) * fInv_det; #endif return true; }