b2ContactSolver.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "b2ContactSolver.h"
  19. #include "b2Contact.h"
  20. #include "../b2Body.h"
  21. #include "../b2World.h"
  22. #include "../../Common/b2StackAllocator.h"
  23. b2ContactSolver::b2ContactSolver(const b2TimeStep& step, b2Contact** contacts, int32 contactCount, b2StackAllocator* allocator)
  24. {
  25. m_step = step;
  26. m_allocator = allocator;
  27. m_constraintCount = 0;
  28. for (int32 i = 0; i < contactCount; ++i)
  29. {
  30. b2Assert(contacts[i]->IsSolid());
  31. m_constraintCount += contacts[i]->GetManifoldCount();
  32. }
  33. m_constraints = (b2ContactConstraint*)m_allocator->Allocate(m_constraintCount * sizeof(b2ContactConstraint));
  34. int32 count = 0;
  35. for (int32 i = 0; i < contactCount; ++i)
  36. {
  37. b2Contact* contact = contacts[i];
  38. b2Body* b1 = contact->m_shape1->GetBody();
  39. b2Body* b2 = contact->m_shape2->GetBody();
  40. int32 manifoldCount = contact->GetManifoldCount();
  41. b2Manifold* manifolds = contact->GetManifolds();
  42. float32 friction = contact->m_friction;
  43. float32 restitution = contact->m_restitution;
  44. b2Vec2 v1 = b1->m_linearVelocity;
  45. b2Vec2 v2 = b2->m_linearVelocity;
  46. float32 w1 = b1->m_angularVelocity;
  47. float32 w2 = b2->m_angularVelocity;
  48. for (int32 j = 0; j < manifoldCount; ++j)
  49. {
  50. b2Manifold* manifold = manifolds + j;
  51. b2Assert(manifold->pointCount > 0);
  52. const b2Vec2 normal = manifold->normal;
  53. b2Assert(count < m_constraintCount);
  54. b2ContactConstraint* c = m_constraints + count;
  55. c->body1 = b1;
  56. c->body2 = b2;
  57. c->manifold = manifold;
  58. c->normal = normal;
  59. c->pointCount = manifold->pointCount;
  60. c->friction = friction;
  61. c->restitution = restitution;
  62. for (int32 k = 0; k < c->pointCount; ++k)
  63. {
  64. b2ManifoldPoint* cp = manifold->points + k;
  65. b2ContactConstraintPoint* ccp = c->points + k;
  66. ccp->normalImpulse = cp->normalImpulse;
  67. ccp->tangentImpulse = cp->tangentImpulse;
  68. ccp->separation = cp->separation;
  69. ccp->positionImpulse = 0.0f;
  70. ccp->localAnchor1 = cp->localPoint1;
  71. ccp->localAnchor2 = cp->localPoint2;
  72. ccp->r1 = b2Mul(b1->GetXForm().R, cp->localPoint1 - b1->GetLocalCenter());
  73. ccp->r2 = b2Mul(b2->GetXForm().R, cp->localPoint2 - b2->GetLocalCenter());
  74. float32 r1Sqr = b2Dot(ccp->r1, ccp->r1);
  75. float32 r2Sqr = b2Dot(ccp->r2, ccp->r2);
  76. float32 rn1 = b2Dot(ccp->r1, normal);
  77. float32 rn2 = b2Dot(ccp->r2, normal);
  78. float32 kNormal = b1->m_invMass + b2->m_invMass;
  79. kNormal += b1->m_invI * (r1Sqr - rn1 * rn1) + b2->m_invI * (r2Sqr - rn2 * rn2);
  80. b2Assert(kNormal > B2_FLT_EPSILON);
  81. ccp->normalMass = 1.0f / kNormal;
  82. float32 kEqualized = b1->m_mass * b1->m_invMass + b2->m_mass * b2->m_invMass;
  83. kEqualized += b1->m_mass * b1->m_invI * (r1Sqr - rn1 * rn1) + b2->m_mass * b2->m_invI * (r2Sqr - rn2 * rn2);
  84. b2Assert(kEqualized > B2_FLT_EPSILON);
  85. ccp->equalizedMass = 1.0f / kEqualized;
  86. b2Vec2 tangent = b2Cross(normal, 1.0f);
  87. float32 rt1 = b2Dot(ccp->r1, tangent);
  88. float32 rt2 = b2Dot(ccp->r2, tangent);
  89. float32 kTangent = b1->m_invMass + b2->m_invMass;
  90. kTangent += b1->m_invI * (r1Sqr - rt1 * rt1) + b2->m_invI * (r2Sqr - rt2 * rt2);
  91. b2Assert(kTangent > B2_FLT_EPSILON);
  92. ccp->tangentMass = 1.0f / kTangent;
  93. // Setup a velocity bias for restitution.
  94. ccp->velocityBias = 0.0f;
  95. if (ccp->separation > 0.0f)
  96. {
  97. ccp->velocityBias = -60.0f * ccp->separation; // TODO_ERIN b2TimeStep
  98. }
  99. float32 vRel = b2Dot(c->normal, v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1));
  100. if (vRel < -b2_velocityThreshold)
  101. {
  102. ccp->velocityBias += -c->restitution * vRel;
  103. }
  104. }
  105. ++count;
  106. }
  107. }
  108. b2Assert(count == m_constraintCount);
  109. }
  110. b2ContactSolver::~b2ContactSolver()
  111. {
  112. m_allocator->Free(m_constraints);
  113. }
  114. void b2ContactSolver::InitVelocityConstraints(const b2TimeStep& step)
  115. {
  116. // Warm start.
  117. for (int32 i = 0; i < m_constraintCount; ++i)
  118. {
  119. b2ContactConstraint* c = m_constraints + i;
  120. b2Body* b1 = c->body1;
  121. b2Body* b2 = c->body2;
  122. float32 invMass1 = b1->m_invMass;
  123. float32 invI1 = b1->m_invI;
  124. float32 invMass2 = b2->m_invMass;
  125. float32 invI2 = b2->m_invI;
  126. b2Vec2 normal = c->normal;
  127. b2Vec2 tangent = b2Cross(normal, 1.0f);
  128. if (step.warmStarting)
  129. {
  130. for (int32 j = 0; j < c->pointCount; ++j)
  131. {
  132. b2ContactConstraintPoint* ccp = c->points + j;
  133. ccp->normalImpulse *= step.dtRatio;
  134. ccp->tangentImpulse *= step.dtRatio;
  135. b2Vec2 P = ccp->normalImpulse * normal + ccp->tangentImpulse * tangent;
  136. b1->m_angularVelocity -= invI1 * b2Cross(ccp->r1, P);
  137. b1->m_linearVelocity -= invMass1 * P;
  138. b2->m_angularVelocity += invI2 * b2Cross(ccp->r2, P);
  139. b2->m_linearVelocity += invMass2 * P;
  140. }
  141. }
  142. else
  143. {
  144. for (int32 j = 0; j < c->pointCount; ++j)
  145. {
  146. b2ContactConstraintPoint* ccp = c->points + j;
  147. ccp->normalImpulse = 0.0f;
  148. ccp->tangentImpulse = 0.0f;
  149. }
  150. }
  151. }
  152. }
  153. void b2ContactSolver::SolveVelocityConstraints()
  154. {
  155. for (int32 i = 0; i < m_constraintCount; ++i)
  156. {
  157. b2ContactConstraint* c = m_constraints + i;
  158. b2Body* b1 = c->body1;
  159. b2Body* b2 = c->body2;
  160. float32 w1 = b1->m_angularVelocity;
  161. float32 w2 = b2->m_angularVelocity;
  162. b2Vec2 v1 = b1->m_linearVelocity;
  163. b2Vec2 v2 = b2->m_linearVelocity;
  164. float32 invMass1 = b1->m_invMass;
  165. float32 invI1 = b1->m_invI;
  166. float32 invMass2 = b2->m_invMass;
  167. float32 invI2 = b2->m_invI;
  168. b2Vec2 normal = c->normal;
  169. b2Vec2 tangent = b2Cross(normal, 1.0f);
  170. float32 friction = c->friction;
  171. //#define DEFERRED_UPDATE
  172. #ifdef DEFERRED_UPDATE
  173. b2Vec2 b1_linearVelocity = b1->m_linearVelocity;
  174. float32 b1_angularVelocity = b1->m_angularVelocity;
  175. b2Vec2 b2_linearVelocity = b2->m_linearVelocity;
  176. float32 b2_angularVelocity = b2->m_angularVelocity;
  177. #endif
  178. // Solve normal constraints
  179. for (int32 j = 0; j < c->pointCount; ++j)
  180. {
  181. b2ContactConstraintPoint* ccp = c->points + j;
  182. // Relative velocity at contact
  183. b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1);
  184. // Compute normal impulse
  185. float32 vn = b2Dot(dv, normal);
  186. float32 lambda = -ccp->normalMass * (vn - ccp->velocityBias);
  187. // b2Clamp the accumulated impulse
  188. float32 newImpulse = b2Max(ccp->normalImpulse + lambda, 0.0f);
  189. lambda = newImpulse - ccp->normalImpulse;
  190. // Apply contact impulse
  191. b2Vec2 P = lambda * normal;
  192. #ifdef DEFERRED_UPDATE
  193. b1_linearVelocity -= invMass1 * P;
  194. b1_angularVelocity -= invI1 * b2Cross(r1, P);
  195. b2_linearVelocity += invMass2 * P;
  196. b2_angularVelocity += invI2 * b2Cross(r2, P);
  197. #else
  198. v1 -= invMass1 * P;
  199. w1 -= invI1 * b2Cross(ccp->r1, P);
  200. v2 += invMass2 * P;
  201. w2 += invI2 * b2Cross(ccp->r2, P);
  202. #endif
  203. ccp->normalImpulse = newImpulse;
  204. }
  205. #ifdef DEFERRED_UPDATE
  206. b1->m_linearVelocity = b1_linearVelocity;
  207. b1->m_angularVelocity = b1_angularVelocity;
  208. b2->m_linearVelocity = b2_linearVelocity;
  209. b2->m_angularVelocity = b2_angularVelocity;
  210. #endif
  211. // Solve tangent constraints
  212. for (int32 j = 0; j < c->pointCount; ++j)
  213. {
  214. b2ContactConstraintPoint* ccp = c->points + j;
  215. // Relative velocity at contact
  216. b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1);
  217. // Compute tangent force
  218. float32 vt = b2Dot(dv, tangent);
  219. float32 lambda = ccp->tangentMass * (-vt);
  220. // b2Clamp the accumulated force
  221. float32 maxFriction = friction * ccp->normalImpulse;
  222. float32 newImpulse = b2Clamp(ccp->tangentImpulse + lambda, -maxFriction, maxFriction);
  223. lambda = newImpulse - ccp->tangentImpulse;
  224. // Apply contact impulse
  225. b2Vec2 P = lambda * tangent;
  226. v1 -= invMass1 * P;
  227. w1 -= invI1 * b2Cross(ccp->r1, P);
  228. v2 += invMass2 * P;
  229. w2 += invI2 * b2Cross(ccp->r2, P);
  230. ccp->tangentImpulse = newImpulse;
  231. }
  232. b1->m_linearVelocity = v1;
  233. b1->m_angularVelocity = w1;
  234. b2->m_linearVelocity = v2;
  235. b2->m_angularVelocity = w2;
  236. }
  237. }
  238. void b2ContactSolver::FinalizeVelocityConstraints()
  239. {
  240. for (int32 i = 0; i < m_constraintCount; ++i)
  241. {
  242. b2ContactConstraint* c = m_constraints + i;
  243. b2Manifold* m = c->manifold;
  244. for (int32 j = 0; j < c->pointCount; ++j)
  245. {
  246. m->points[j].normalImpulse = c->points[j].normalImpulse;
  247. m->points[j].tangentImpulse = c->points[j].tangentImpulse;
  248. }
  249. }
  250. }
  251. bool b2ContactSolver::SolvePositionConstraints(float32 baumgarte)
  252. {
  253. float32 minSeparation = 0.0f;
  254. for (int32 i = 0; i < m_constraintCount; ++i)
  255. {
  256. b2ContactConstraint* c = m_constraints + i;
  257. b2Body* b1 = c->body1;
  258. b2Body* b2 = c->body2;
  259. float32 invMass1 = b1->m_mass * b1->m_invMass;
  260. float32 invI1 = b1->m_mass * b1->m_invI;
  261. float32 invMass2 = b2->m_mass * b2->m_invMass;
  262. float32 invI2 = b2->m_mass * b2->m_invI;
  263. b2Vec2 normal = c->normal;
  264. // Solver normal constraints
  265. for (int32 j = 0; j < c->pointCount; ++j)
  266. {
  267. b2ContactConstraintPoint* ccp = c->points + j;
  268. b2Vec2 r1 = b2Mul(b1->GetXForm().R, ccp->localAnchor1 - b1->GetLocalCenter());
  269. b2Vec2 r2 = b2Mul(b2->GetXForm().R, ccp->localAnchor2 - b2->GetLocalCenter());
  270. b2Vec2 p1 = b1->m_sweep.c + r1;
  271. b2Vec2 p2 = b2->m_sweep.c + r2;
  272. b2Vec2 dp = p2 - p1;
  273. // Approximate the current separation.
  274. float32 separation = b2Dot(dp, normal) + ccp->separation;
  275. // Track max constraint error.
  276. minSeparation = b2Min(minSeparation, separation);
  277. // Prevent large corrections and allow slop.
  278. float32 C = baumgarte * b2Clamp(separation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
  279. // Compute normal impulse
  280. float32 dImpulse = -ccp->equalizedMass * C;
  281. // b2Clamp the accumulated impulse
  282. float32 impulse0 = ccp->positionImpulse;
  283. ccp->positionImpulse = b2Max(impulse0 + dImpulse, 0.0f);
  284. dImpulse = ccp->positionImpulse - impulse0;
  285. b2Vec2 impulse = dImpulse * normal;
  286. b1->m_sweep.c -= invMass1 * impulse;
  287. b1->m_sweep.a -= invI1 * b2Cross(r1, impulse);
  288. b1->SynchronizeTransform();
  289. b2->m_sweep.c += invMass2 * impulse;
  290. b2->m_sweep.a += invI2 * b2Cross(r2, impulse);
  291. b2->SynchronizeTransform();
  292. }
  293. }
  294. // We can't expect minSpeparation >= -b2_linearSlop because we don't
  295. // push the separation above -b2_linearSlop.
  296. return minSeparation >= -1.5f * b2_linearSlop;
  297. }