Guest User

Untitled

a guest
Feb 10th, 2015
557
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.15 KB | None | 0 0
  1. void ContactManager3D::Merge(ContactManifold3D &src, ContactManifold3D &dest, float persistentThresholdSQ)
  2. {
  3.   GV_ASSERT(src.SameColliders(dest));
  4.  
  5.   auto &colliderA = *dest.colliderA;
  6.   auto &colliderB = *dest.colliderB;
  7.   auto &bodyA = colliderA.Parent();
  8.   auto &bodyB = colliderB.Parent();
  9.  
  10.   // list of valid contacts
  11.   Contact3D *validContacts[ContactManifold3D::k_maxContacts * 2] = { 0 };
  12.   uint8 numValidContacts = 0;
  13.  
  14.   // check persistent contacts
  15.   {
  16.     for (uint8 i = 0; i < dest.numContacts; ++i)
  17.     {
  18.       Contact3D &contact = *dest.contacts[i];
  19.       const Vec3 localToGlobalA = bodyA.LocalToGlobal(contact.localPositionA);
  20.       const Vec3 localToGlobalB = bodyB.LocalToGlobal(contact.localPositionB);
  21.       const Vec3 rA = contact.globalPositionA - localToGlobalA;
  22.       const Vec3 rB = contact.globalPositionB - localToGlobalB;
  23.       if (!src.invalidateExistingContacts
  24.           && contact.normal.Dot(localToGlobalB - localToGlobalA) <= 0.0f
  25.           && rA.LengthSQ() < persistentThresholdSQ
  26.           && rB.LengthSQ() < persistentThresholdSQ)
  27.       {
  28.         // contact persistent, keep
  29.         contact.persistent = true;
  30.         validContacts[numValidContacts++] = &contact;
  31.       }
  32.       else
  33.       {
  34.         // dispatch end contact event
  35.         if (m_listener)
  36.           m_listener->EndContact(colliderA, colliderB, contact);
  37.  
  38.         // contact not persistent, destroy
  39.         contact.~Contact3D();
  40.         m_contactAllocator.Free(&contact);
  41.       }
  42.     }
  43.   } // end of check persistent contacts
  44.  
  45.   // process new contacts
  46.   for (uint8 i = 0; i < src.numContacts; ++i)
  47.   {
  48.     auto newContact = src.contacts[i];
  49.  
  50.     // discard new contact if it's too close to cached contacts
  51.     bool discard = false;
  52.     for (uint8 j = 0; j < numValidContacts; ++j)
  53.     {
  54.       if ((newContact->globalPositionA - validContacts[j]->globalPositionA).LengthSQ() < persistentThresholdSQ)
  55.       {
  56.         discard = true;
  57.         break;
  58.       }
  59.     }
  60.  
  61.     if (discard)
  62.     {
  63.       // contact too close to cached contacts, destroy
  64.       newContact->~Contact3D();
  65.       m_contactAllocator.Free(newContact);
  66.     }
  67.     else
  68.     {
  69.       // add new contact to valid list
  70.       validContacts[numValidContacts++] = newContact;
  71.     }
  72.   }
  73.  
  74.   // repopulate new manifold
  75.   if (numValidContacts <= ContactManifold3D::k_maxContacts)
  76.   {
  77.     // enough contact slots, merge all
  78.     for (uint8 i = 0; i < numValidContacts; ++i)
  79.       dest.contacts[i] = validContacts[i];
  80.     for (uint8 i = numValidContacts; i < dest.numContacts; ++i)
  81.       dest.contacts[i] = nullptr;
  82.     dest.numContacts = numValidContacts;
  83.   }
  84.   else // not enough contact slots, pick ones furthest apart
  85.   {
  86.     dest.numContacts = 0;
  87.  
  88.     // 1) find deepest contact first
  89.     Contact3D *deepest = validContacts[0];
  90.     uint8 deepestIndex = 0;
  91.     for (uint8 i = 1; i < numValidContacts; ++i)
  92.     {
  93.       if (validContacts[i]->depth > deepest->depth)
  94.       {
  95.         deepest = validContacts[i];
  96.         deepestIndex = i;
  97.       }
  98.     }
  99.     // move deepest contact to end of valid list
  100.     std::swap(validContacts[deepestIndex], validContacts[--numValidContacts]);
  101.     // add deepest contact
  102.     dest.contacts[dest.numContacts++] = deepest;
  103.  
  104.     // 2) find furthest contact to form 1D simplex (a line)
  105.     if (dest.numContacts < ContactManifold3D::k_maxContacts)
  106.     {
  107.       float distSQ = std::numeric_limits<float>::lowest();
  108.       Contact3D *furthest = nullptr;
  109.       uint8 furthestIndex = 0;
  110.       for (uint8 i = 0; i < numValidContacts; ++i)
  111.       {
  112.         const float currDistSQ = (validContacts[i]->globalPositionA - deepest->globalPositionA).LengthSQ();
  113.         if (currDistSQ > distSQ)
  114.         {
  115.           furthest = validContacts[i];
  116.           distSQ = currDistSQ;
  117.           furthestIndex = i;
  118.         }
  119.       }
  120.       // move furthest contact to end of valid list
  121.       std::swap(validContacts[furthestIndex], validContacts[--numValidContacts]);
  122.       // add furthest contact
  123.       dest.contacts[dest.numContacts++] = furthest;
  124.     }
  125.  
  126.     // 3) expand line to a triangle
  127.     if (   dest.numContacts == 2
  128.         && dest.numContacts < ContactManifold3D::k_maxContacts
  129.         && dest.numContacts < ContactManifold3D::k_maxContacts)
  130.     {
  131.       const Vec3 &linePos = dest.contacts[0]->globalPositionA;
  132.       const Vec3  lineDir = (dest.contacts[1]->globalPositionA - dest.contacts[0]->globalPositionA).Normalized();
  133.       Contact3D *furthest = nullptr;
  134.       uint8 furthestIndex = 0;
  135.       float distSQ = std::numeric_limits<float>::lowest();
  136.       for (uint8 i = 0; i < numValidContacts; ++i)
  137.       {
  138.         // calculate distance from 1D simplex
  139.         const Vec3 posDiff = validContacts[i]->globalPositionA - linePos;
  140.         const float currDistSQ = (posDiff - posDiff.ProjectedUnit(lineDir)).LengthSQ();
  141.         if (currDistSQ > distSQ)
  142.         {
  143.           furthest = validContacts[i];
  144.           distSQ = currDistSQ;
  145.           furthestIndex = i;
  146.         }
  147.       }
  148.       // move furthest contact to end of valid list
  149.       std::swap(validContacts[furthestIndex], validContacts[--numValidContacts]);
  150.       // add furthest contact
  151.       dest.contacts[dest.numContacts++] = furthest;
  152.     }
  153.  
  154.     // 4) blow up manifold using furthest contact from 2D simplex (triangle)
  155.     if (   dest.numContacts == 3
  156.         && dest.numContacts < ContactManifold3D::k_maxContacts
  157.         && dest.numContacts < ContactManifold3D::k_maxContacts)
  158.     {
  159.       const Vec3 &a = dest.contacts[0]->globalPositionA;
  160.       const Vec3 &b = dest.contacts[1]->globalPositionA;
  161.       const Vec3 &c = dest.contacts[2]->globalPositionA;
  162.       Contact3D *furthest = nullptr;
  163.       uint8 furthestIndex = 0;
  164.       float distSQ = std::numeric_limits<float>::lowest();
  165.       for (uint8 i = 0; i < numValidContacts; ++i)
  166.       {
  167.         // calculate distance from 1D simplex
  168.         const Vec3 &p =  validContacts[i]->globalPositionA;
  169.         const float currDistSQ = (ClosestPointTriangle(p, a, b, c) - p).LengthSQ();
  170.         if (currDistSQ > distSQ)
  171.         {
  172.           furthest = validContacts[i];
  173.           distSQ = currDistSQ;
  174.           furthestIndex = i;
  175.         }
  176.       }
  177.       // move furthest contact to end of valid list
  178.       std::swap(validContacts[furthestIndex], validContacts[--numValidContacts]);
  179.       // add furthest contact
  180.       dest.contacts[dest.numContacts++] = furthest;
  181.     }
  182.  
  183.     // 5) dispose all remaining valid contacts
  184.     for (uint8 i = 0; i < numValidContacts; ++i)
  185.     {
  186.       // dispatch end contact event for persistent contacts
  187.       if (m_listener && validContacts[i]->persistent)
  188.         m_listener->EndContact(colliderA, colliderB, *validContacts[i]);
  189.  
  190.       validContacts[i]->~Contact3D();
  191.       m_contactAllocator.Free(validContacts[i]);
  192.     }
  193.   }
  194.  
  195.   // dispatch begin begin contact event for new contacts
  196.   if (m_listener)
  197.     for (uint8 i = 0; i < dest.numContacts; ++i)
  198.       if (!dest.contacts[i]->persistent)
  199.         m_listener->BeginContact(colliderA, colliderB, *dest.contacts[i]);
  200.  
  201.   // clean up source manifold
  202.   for (uint8 i = 0; i < ContactManifold3D::k_maxContacts; ++i)
  203.     src.contacts[i] = nullptr;
  204.   src.numContacts = 0;
  205. }
Advertisement
Add Comment
Please, Sign In to add comment