#include "../Include/MathUtil.h" #include namespace CrossM{ namespace Math{ // »ï°¢ÇüÀÌ AABB ¾È¿¡ ¿ÏÀüÈ÷ Æ÷ÇԵǴÂÁö °Ë»ç bool IsTriangleInAabb(const VECTOR3& vAabbMin, const VECTOR3& vAabbMax, const VECTOR3& vTri0, const VECTOR3& vTri1, const VECTOR3& vTri2) { if (vAabbMin.x <= vTri0.x && vTri0.x <= vAabbMax.x && vAabbMin.y <= vTri0.y && vTri0.y <= vAabbMax.y && vAabbMin.z <= vTri0.z && vTri0.z <= vAabbMax.z && vAabbMin.x <= vTri1.x && vTri1.x <= vAabbMax.x && vAabbMin.y <= vTri1.y && vTri1.y <= vAabbMax.y && vAabbMin.z <= vTri1.z && vTri1.z <= vAabbMax.z && vAabbMin.x <= vTri2.x && vTri2.x <= vAabbMax.x && vAabbMin.y <= vTri2.y && vTri2.y <= vAabbMax.y && vAabbMin.z <= vTri2.z && vTri2.z <= vAabbMax.z) { return true; } return false; } // »ï°¢Çü°ú AABB °¡ ¸¸³ª´ÂÁö¸¦ °Ë»ç bool CheckAabbTriangleIntersection(const VECTOR3& vAabbMin, const VECTOR3& vAabbMax, const VECTOR3& vTri0, const VECTOR3& vTri1, const VECTOR3& vTri2) { // Separation of Axes ¿¡ µû¸¥ AABB - triangle intersection test ±¸Çö // 6 Ãà¿¡ ´ëÇØ AABB ¿Í »ï°¢ÇüÀ» projection ÇÑ µÚ, µÑÀÌ °ãÄ¡´ÂÁö ¿©ºÎ¸¦ È®ÀÎÇÑ´Ù // ¸ðµç Ãà¿¡ ´ëÇØ °ãÄ¡¸é µÑÀº ¸¸³ª´Â°ÍÀ̰í, ÇÑ Ãà¿¡ ´ëÇØ¼­¶óµµ °ãÄ¡Áö ¾Ê´Â´Ù¸é ¸¸³ªÁö ¾Ê´Â °ÍÀÌ´Ù float fBoxProjectionMin, fBoxProjectionMax; float fTriProjectionMin, fTriProjectionMax; // AABB ÀÇ ¼¼ Ãà¿¡ ´ëÇÑ projection À» °Ë»ç // X Ãà fBoxProjectionMin = vAabbMin.x; fBoxProjectionMax = vAabbMax.x; fTriProjectionMin = std::min(vTri0.x, std::min(vTri1.x, vTri2.x)); fTriProjectionMax = std::max(vTri0.x, std::max(vTri1.x, vTri2.x)); if (false == IsRangeOverlap(fTriProjectionMin, fTriProjectionMax, fBoxProjectionMin, fBoxProjectionMax)) { return false; } // Y Ãà fBoxProjectionMin = vAabbMin.y; fBoxProjectionMax = vAabbMax.y; fTriProjectionMin = std::min(vTri0.y, std::min(vTri1.y, vTri2.y)); fTriProjectionMax = std::max(vTri0.y, std::max(vTri1.y, vTri2.y)); if (false == IsRangeOverlap(fTriProjectionMin, fTriProjectionMax, fBoxProjectionMin, fBoxProjectionMax)) { return false; } // Z Ãà fBoxProjectionMin = vAabbMin.z; fBoxProjectionMax = vAabbMax.z; fTriProjectionMin = std::min(vTri0.z, std::min(vTri1.z, vTri2.z)); fTriProjectionMax = std::max(vTri0.z, std::max(vTri1.z, vTri2.z)); if (false == IsRangeOverlap(fTriProjectionMin, fTriProjectionMax, fBoxProjectionMin, fBoxProjectionMax)) { return false; } // »ï°¢ÇüÀÇ ÀÇ ¼¼ Ãà¿¡ ´ëÇÑ projection À» °Ë»ç VECTOR3 avAxis[3]; // »ï°¢ÇüÀÇ ¼¼ ¸ð¼­¸® Math::Subtract(avAxis[0], vTri1, vTri0); Math::Subtract(avAxis[1], vTri2, vTri0); Math::Subtract(avAxis[2], vTri2, vTri1); // »ï°¢Çü °¢ Á¡À» Ãà¿¡ projection ÇÑ °ª float fProjectionTri0, fProjectionTri1, fProjectionTri2; for (int i = 0; i < 3; ++i) { VECTOR3& vAxis = avAxis[i]; // AABB ÀÇ max/min Á¡ÀÇ xyz ´Â °¢°¢ÀÇ ÃÖ´ë/ÃÖ¼Ò°ªÀ̹ǷÎ, // axis ÀÇ °¢ ÄÄÆ÷³ÍÆ®¿Í ³»ÀûÇßÀ»¶§ ÃÖ´ë°ªÀ» ±¸ÇÏ·Á¸é // x,y,z °¢°¢ÀÇ °öÀÌ Å« ÂÊ ³¢¸® °ñ¶ó¼­ ´õÇÏ¸é µÈ´Ù. // (¾îÂ÷ÇÇ AABB ¿©´üÁ¡ÀÌ xyz °¢°¢ÀÇ ÃÖ´ë/ÃÖ¼Ò°£ÀÇ Á¶ÇÕÀ̹ǷÎ, // x,y,z ¸¦ °¢°¢ ÀÓÀÇ·Î ÃÖ´ë/ÃÖ¼Ò¸¦ ¼±ÅÃÇÑ´Ù ÇØµµ ¾î‰h Á¡ ¾È¿¡ ¸ðµÎ Æ÷ÇԵǴ Á¶ÇÕÀÌ´Ù.) fBoxProjectionMin = ((vAxis.x > 0) ? vAabbMin.x : vAabbMax.x) * vAxis.x + ((vAxis.y > 0) ? vAabbMin.y : vAabbMax.y) * vAxis.y + ((vAxis.z > 0) ? vAabbMin.z : vAabbMax.z) * vAxis.z; fBoxProjectionMax = ((vAxis.x > 0) ? vAabbMax.x : vAabbMin.x) * vAxis.x + ((vAxis.y > 0) ? vAabbMax.y : vAabbMin.y) * vAxis.y + ((vAxis.z > 0) ? vAabbMax.z : vAabbMin.z) * vAxis.z; fProjectionTri0 = Math::DotProduct(vTri0, vAxis); fProjectionTri1 = Math::DotProduct(vTri1, vAxis); fProjectionTri2 = Math::DotProduct(vTri2, vAxis); fTriProjectionMin = std::min(fProjectionTri0, std::min(fProjectionTri1, fProjectionTri2)); fTriProjectionMax = std::max(fProjectionTri0, std::max(fProjectionTri1, fProjectionTri2)); if (false == IsRangeOverlap(fTriProjectionMin, fTriProjectionMax, fBoxProjectionMin, fBoxProjectionMax)) { return false; } } return true; } // µÎ AABB °¡ ¸¸³ª´ÂÁö °Ë»ç bool CheckAabbAabbIntersection(const VECTOR3& vAabb1Min, const VECTOR3& vAabb1Max, const VECTOR3& vAabb2Min, const VECTOR3& vAabb2Max) { if (false ==IsRangeOverlap(vAabb1Min.x, vAabb1Max.x, vAabb2Min.x, vAabb2Max.x)) return false; if (false ==IsRangeOverlap(vAabb1Min.y, vAabb1Max.y, vAabb2Min.y, vAabb2Max.y)) return false; if (false ==IsRangeOverlap(vAabb1Min.z, vAabb1Max.z, vAabb2Min.z, vAabb2Max.z)) return false; return true; } // CheckTriangleSweepingSphereCollision ÀÇ ºÎ¼Ó ÇÔ¼ö. // ax^2 + bx + c ÀÇ ÇØ Áß min~max ¹üÀ§ ³»ÀÇ °¡Àå ÀÛÀº ÇØ¸¦ ¹ÝȯÇÑ´Ù. ¸¸Á·ÇÏ´Â ÇØ°¡ ¾øÀ¸¸é false ¹Ýȯ static bool GetLowestRootInRange(const float a, const float b, const float c, const float fMinRoot, const float fMaxRoot, float& fRoot) { // ½Ç¼öÇØ°¡ Á¸ÀçÇÏ´ÂÁö ÆÇº°½Ä °è»ê float fDeterminant = b*b - 4.0f*a*c; // ½Ç¼öÇØ°¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¸é ÇØ ¾øÀ½ if (fDeterminant < 0.0f) return false; // µÎ°³ÀÇ ÇØ¸¦ °è»êÇÑ´Ù float fSqrtD = sqrtf(fDeterminant); float r1 = (-b - fSqrtD) / (2*a); float r2 = (-b + fSqrtD) / (2*a); // r1 < r2 ÀÇ Å©±â°¡ µÇµµ·Ï Á¤·Ä if (r1 > r2) std::swap(r1, r2); // ÀÛÀºÂʺÎÅÍ ¹üÀ§ ³»ÀÎÁö ÆÇº°ÇØ, ¹üÀ§³»Àϰæ¿ì ÇØ·Î¼­ ¸®ÅÏ if (r1 > fMinRoot && r1 < fMaxRoot) { fRoot = r1; return true; } // ÀÛÀº ÇØ ÂÊÀÌ ¹üÀ§³»¿¡ µéÁö ¾ÊÀ¸¸é, Å« ÇØ ÂÊÀÌ ¹üÀ§³»ÀÎÁö °Ë»çÇÑ´Ù if (r2 > fMinRoot && r2 < fMaxRoot) { fRoot = r2; return true; } return false; } bool CheckTriangleSweepingSphereCollision(float &fOutT, VECTOR3& vOutContactPoint, bool& bOutContactInsideTriangle, const TriangSweepingSphere& triAndSphere) { // ¾à°£ÀÇ alias const Math::VECTOR3 &vBasePoint = triAndSphere.m_vSphereSweepStart; const Math::VECTOR3 &vTri0 = triAndSphere.m_vTri0; const Math::VECTOR3 &vTri1 = triAndSphere.m_vTri1; const Math::VECTOR3 &vTri2 = triAndSphere.m_vTri2; const Math::VECTOR3 &vPath = triAndSphere.m_vSphereSweepPath; // »ï°¢ÇüÀÇ ¼¼ ¸ð¼­¸® Math::VECTOR3 vTriEdge01, vTriEdge02, vTriEdge12; // »ï°¢ÇüÀ» Æ÷ÇÔÇÏ´Â Æò¸é. ÃßÈÄ plane Ŭ·¡½º µîÀ¸·Î ¸¸µé¾î¾ß ÇÒ µí Math::VECTOR3 vTriPlaneNormal; float fTriPlaneConstant; // »ï°¢ÇüÀÇ ¼¼ ¸ð¼­¸® º¤Å͸¦ ±¸Çϰí.. Math::Subtract(vTriEdge01, vTri1, vTri0); Math::Subtract(vTriEdge02, vTri2, vTri0); Math::Subtract(vTriEdge12, vTri2, vTri1); // »ï°¢ÇüÀÌ Æ÷ÇÔµÈ Æò¸éÀÇ ÆÄ¶ó¹ÌÅ͵éÀ» ±¸ÇÔ Math::CrossProduct(vTriPlaneNormal, vTriEdge01, vTriEdge02); Math::Normalize(vTriPlaneNormal, vTriPlaneNormal); fTriPlaneConstant = -Math::DotProduct(vTriPlaneNormal, vTri0); // sweeping path ¿Í Ãæµ¹Æò¸é¹ý¼± ³»Àû float fNormalDotPath = Math::DotProduct(vTriPlaneNormal, vPath); // sphere ÀÇ ÁøÇà¹æÇâÀÌ °°Àº ¹æÇâÀ̸é üũ¾ÈÇÔ if (fNormalDotPath > 0.0f) { return false; } float t0, t1; bool bEmbededInPlane = false; float fSignedDistBaseToTriPlane = Math::DotProduct(vTriPlaneNormal, vBasePoint) + fTriPlaneConstant; if (0.0f == fNormalDotPath) { // sphere °¡ »ï°¢Çü¸é°ú ÆòÇàÇÏ°Ô ÁøÇà if (fabs(fSignedDistBaseToTriPlane) >= triAndSphere.m_fSphereRadius) { return false; // »ï°¢Çü¸é¿¡¼­ ¸Ö¸® ¶³¾îÁ®¼­ ÆòÇàÀ̵¿Áß } else { bEmbededInPlane = true; t0 = 0.0f; t1 = 1.0f; } } else { t0 = (-triAndSphere.m_fSphereRadius-fSignedDistBaseToTriPlane)/fNormalDotPath; t1 = (triAndSphere.m_fSphereRadius-fSignedDistBaseToTriPlane)/fNormalDotPath; // t0 < t1 À¸·Î ¼ÒÆ® if (t0 > t1) { std::swap(t0, t1); } // t ±¸°£ÀÌ sphere À̵¿°æ·Î ¼±ºÐ ³»¿¡ ÀÖÁö ¾Ê´Ù if (t0 > 1.0f || t1 <0.0f) { return false; } // t °ªÀ» 0~1 ±¸°£³»·Î Ŭ·¥ÇÎ t0 = std::max(t0, 0.0f); t1 = std::min(t1, 1.0f); } VECTOR3 vContactPoint; bool bFoundCollision = false; float t = 1.0f; // »ï°¢Çü ³»ºÎ¿Í üũ if (!bEmbededInPlane) { vContactPoint = vBasePoint + (vPath*t0) - vTriPlaneNormal; if (IsPointInTriangle(vContactPoint, vTri0, vTri1, vTri2)) { bFoundCollision = true; t = t0; } } // ¾ÆÁ÷ Ãæµ¹Á¡À» ãÁö ¸øÇß´Ù¸é ¸ð¼­¸®¿Í ²ÀÁöÁ¡¿¡ ´ëÇØ Å×½ºÆ®¸¦ ÇØ¾ßÇÑ´Ù if (!bFoundCollision) { float fSQuaredPathLength = GetSquaredLength(vPath); float a, b, c; float newT; float fSquaredRadius = triAndSphere.m_fSphereRadius*triAndSphere.m_fSphereRadius; a = fSQuaredPathLength; // vTri0 b = 2.0f * (DotProduct(vPath, vBasePoint - vTri0)); c = (Math::GetSquaredLength(vTri0 - vBasePoint) - fSquaredRadius); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { t = newT; bFoundCollision = true; vContactPoint = vTri0; } // vTri1 if (bFoundCollision) { b = 2.0f * (DotProduct(vPath, vBasePoint - vTri1)); c = (Math::GetSquaredLength(vTri1 - vBasePoint) - fSquaredRadius); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { t = newT; bFoundCollision = true; vContactPoint = vTri1; } } // vTri2 if (bFoundCollision) { b = 2.0f * (DotProduct(vPath, vBasePoint - vTri2)); c = (Math::GetSquaredLength(vTri2 - vBasePoint) - fSquaredRadius); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { t = newT; bFoundCollision = true; vContactPoint = vTri0; } } // ¸ð¼­¸®¿¡ ´ëÇØ Å×½ºÆ® VECTOR3 vBaseToVertex; float fEdgeSquaredLength; float fEdgeDotPath; float fEdgeDotBaseToVertex; // vTri0 ~ vTri1 vBaseToVertex = vTri0 - vBasePoint; fEdgeSquaredLength = GetSquaredLength(vTriEdge01); fEdgeDotPath = DotProduct(vTriEdge01, vPath); fEdgeDotBaseToVertex = DotProduct(vTriEdge01, vBaseToVertex); a = fEdgeSquaredLength* -fSQuaredPathLength + fEdgeDotPath*fEdgeDotPath; b = fEdgeSquaredLength* (2.0f*Math::DotProduct(vPath, vBaseToVertex)) - 2.0f*fEdgeDotPath*fEdgeDotBaseToVertex; c = (fEdgeSquaredLength* (1.0f - Math::GetSquaredLength(vBaseToVertex)) + fEdgeDotBaseToVertex*fEdgeDotBaseToVertex); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { float f = (fEdgeDotPath*t - fEdgeDotBaseToVertex) / fEdgeSquaredLength; if (f >= 0.0f && f <= 1.0f) { t = newT; bFoundCollision = true; vContactPoint = vTri0 + vTriEdge01*f; } } // vTri0 ~ vTri2 vBaseToVertex = vTri0 - vBasePoint; fEdgeSquaredLength = GetSquaredLength(vTriEdge02); fEdgeDotPath = DotProduct(vTriEdge02, vPath); fEdgeDotBaseToVertex = DotProduct(vTriEdge02, vBaseToVertex); a = fEdgeSquaredLength* -fSQuaredPathLength + fEdgeDotPath*fEdgeDotPath; b = fEdgeSquaredLength* (2.0f*Math::DotProduct(vPath, vBaseToVertex)) - 2.0f*fEdgeDotPath*fEdgeDotBaseToVertex; c = (fEdgeSquaredLength* (1.0f - Math::GetSquaredLength(vBaseToVertex)) + fEdgeDotBaseToVertex*fEdgeDotBaseToVertex); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { float f = (fEdgeDotPath*t - fEdgeDotBaseToVertex) / fEdgeSquaredLength; if (f >= 0.0f && f <= 1.0f) { t = newT; bFoundCollision = true; vContactPoint = vTri0 + vTriEdge02*f; } } // vTri1 ~ vTri2 vBaseToVertex = vTri1 - vBasePoint; fEdgeSquaredLength = GetSquaredLength(vTriEdge12); fEdgeDotPath = DotProduct(vTriEdge12, vPath); fEdgeDotBaseToVertex = DotProduct(vTriEdge12, vBaseToVertex); a = fEdgeSquaredLength* -fSQuaredPathLength + fEdgeDotPath*fEdgeDotPath; b = fEdgeSquaredLength* (2.0f*Math::DotProduct(vPath, vBaseToVertex)) - 2.0f*fEdgeDotPath*fEdgeDotBaseToVertex; c = (fEdgeSquaredLength* (1.0f - Math::GetSquaredLength(vBaseToVertex)) + fEdgeDotBaseToVertex*fEdgeDotBaseToVertex); if (GetLowestRootInRange(a, b, c, 0.0f, t, newT)) { float f = (fEdgeDotPath*t - fEdgeDotBaseToVertex) / fEdgeSquaredLength; if (f >= 0.0f && f <= 1.0f) { t = newT; bFoundCollision = true; vContactPoint = vTri1 + vTriEdge12*f; } } } if (bFoundCollision) { fOutT = t; vOutContactPoint = vContactPoint; return true; } return false; } // ÁöÁ¤µÈ Á¡ÀÌ »ï°¢Çü ³»¿¡ Æ÷ÇԵǴÂÁö È®ÀÎÇÏ´Â ÄÚµå // Fauerby ÀÇ ±Û¿¡ Keidy ¶ó´Â »ç¶÷ÀÌ ±â°íÇÑ °¡Àå ºü¸¥ ·çƾÀ̶ó°í ÇÑ´Ù // ¼öÇÐÀûÀÎ Áõ¸íÀº.. ¸ð¸£°Ú´Ù-_- ÀÏ´Ü ÀÌ¿ë bool IsPointInTriangle(const VECTOR3& p, const VECTOR3& vTri0, const VECTOR3& vTri1, const VECTOR3& vTri2) { // ¿øÁ¡À» ³¤ µÎ »ï°¢Çü ¸ð¼­¸®, ¿øÁ¡À» ±âÁØÀ¸·Î ÇÑ p ÀÇ À§Ä¡º¤ÅÍ VECTOR3 vEdge1, vEdge2, pTri; Math::Subtract(vEdge1, vTri1, vTri0); Math::Subtract(vEdge2, vTri2, vTri0); Math::Subtract(pTri, p, vTri0); float a = Math::DotProduct(vEdge1, vEdge1); float b = Math::DotProduct(vEdge1, vEdge2); float c = Math::DotProduct(vEdge2, vEdge2); float d = Math::DotProduct(pTri, vEdge1); float e = Math::DotProduct(pTri, vEdge2); float x = d*c - e*b; float y = e*a - d*b; float z = x + y - (a*c - b*b); return ( ((unsigned int&)z) & ~ ( ((unsigned int&)x) | ((unsigned int&)y) ) & 0x80000000) != 0 ? true : false; } }}