Skip to content

Commit e4b35d3

Browse files
committed
optimised Resolver.solveVelocity
1 parent 0b07a31 commit e4b35d3

1 file changed

Lines changed: 81 additions & 56 deletions

File tree

src/collision/Resolver.js

Lines changed: 81 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,17 @@ var Bounds = require('../geometry/Bounds');
228228
*/
229229
Resolver.solveVelocity = function(pairs, timeScale) {
230230
var timeScaleSquared = timeScale * timeScale,
231-
impulse = Vector._temp[0],
232-
tempA = Vector._temp[1],
233-
tempB = Vector._temp[2],
234-
tempC = Vector._temp[3],
235-
tempD = Vector._temp[4],
236-
tempE = Vector._temp[5];
237-
238-
for (var i = 0; i < pairs.length; i++) {
231+
restingThresh = Resolver._restingThresh * timeScaleSquared,
232+
frictionNormalMultiplier = Resolver._frictionNormalMultiplier,
233+
restingThreshTangent = Resolver._restingThreshTangent * timeScaleSquared,
234+
NumberMaxValue = Number.MAX_VALUE,
235+
pairsLength = pairs.length,
236+
tangentImpulse,
237+
maxFriction,
238+
i,
239+
j;
240+
241+
for (i = 0; i < pairsLength; i++) {
239242
var pair = pairs[i];
240243

241244
if (!pair.isActive || pair.isSensor)
@@ -244,97 +247,119 @@ var Bounds = require('../geometry/Bounds');
244247
var collision = pair.collision,
245248
bodyA = collision.parentA,
246249
bodyB = collision.parentB,
247-
normal = collision.normal,
248-
tangent = collision.tangent,
250+
bodyAVelocity = bodyA.velocity,
251+
bodyBVelocity = bodyB.velocity,
252+
normalX = collision.normal.x,
253+
normalY = collision.normal.y,
254+
tangentX = collision.tangent.x,
255+
tangentY = collision.tangent.y,
249256
contacts = pair.activeContacts,
250-
contactShare = 1 / contacts.length;
257+
contactsLength = contacts.length,
258+
contactShare = 1 / contactsLength,
259+
inverseMassTotal = bodyA.inverseMass + bodyB.inverseMass,
260+
friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier * timeScaleSquared;
251261

252262
// update body velocities
253-
bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x;
254-
bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y;
255-
bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x;
256-
bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y;
263+
bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x;
264+
bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y;
265+
bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x;
266+
bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y;
257267
bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;
258268
bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;
259269

260270
// resolve each contact
261-
for (var j = 0; j < contacts.length; j++) {
271+
for (j = 0; j < contactsLength; j++) {
262272
var contact = contacts[j],
263-
contactVertex = contact.vertex,
264-
offsetA = Vector.sub(contactVertex, bodyA.position, tempA),
265-
offsetB = Vector.sub(contactVertex, bodyB.position, tempB),
266-
velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity), tempC),
267-
velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity), tempD),
268-
relativeVelocity = Vector.sub(velocityPointA, velocityPointB, tempE),
269-
normalVelocity = Vector.dot(normal, relativeVelocity);
270-
271-
var tangentVelocity = Vector.dot(tangent, relativeVelocity),
272-
tangentSpeed = Math.abs(tangentVelocity),
273-
tangentVelocityDirection = Common.sign(tangentVelocity);
273+
contactVertex = contact.vertex;
274+
275+
var offsetAX = contactVertex.x - bodyA.position.x,
276+
offsetAY = contactVertex.y - bodyA.position.y,
277+
offsetBX = contactVertex.x - bodyB.position.x,
278+
offsetBY = contactVertex.y - bodyB.position.y;
274279

275-
// raw impulses
276-
var normalImpulse = (1 + pair.restitution) * normalVelocity,
277-
normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1) * Resolver._frictionNormalMultiplier;
280+
var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity,
281+
velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity,
282+
velocityPointBX = bodyBVelocity.x - offsetBY * bodyB.angularVelocity,
283+
velocityPointBY = bodyBVelocity.y + offsetBX * bodyB.angularVelocity;
284+
285+
var relativeVelocityX = velocityPointAX - velocityPointBX,
286+
relativeVelocityY = velocityPointAY - velocityPointBY;
287+
288+
var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY,
289+
tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY;
278290

279291
// coulomb friction
280-
var tangentImpulse = tangentVelocity,
281-
maxFriction = Infinity;
282-
283-
if (tangentSpeed > pair.friction * pair.frictionStatic * normalForce * timeScaleSquared) {
284-
maxFriction = tangentSpeed;
285-
tangentImpulse = Common.clamp(
286-
pair.friction * tangentVelocityDirection * timeScaleSquared,
287-
-maxFriction, maxFriction
288-
);
292+
var normalOverlap = pair.separation + normalVelocity;
293+
var normalForce = normalOverlap > 1 ? 1 : normalOverlap;
294+
normalForce = normalOverlap < 0 ? 0 : normalForce;
295+
296+
var frictionLimit = normalForce * friction;
297+
298+
if (tangentVelocity > frictionLimit || -tangentVelocity > frictionLimit) {
299+
maxFriction = tangentVelocity > 0 ? tangentVelocity : -tangentVelocity;
300+
tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScaleSquared;
301+
302+
if (tangentImpulse < -maxFriction) {
303+
tangentImpulse = -maxFriction;
304+
} else if (tangentImpulse > maxFriction) {
305+
tangentImpulse = maxFriction;
306+
}
307+
} else {
308+
tangentImpulse = tangentVelocity;
309+
maxFriction = NumberMaxValue;
289310
}
290311

291-
// modify impulses accounting for mass, inertia and offset
292-
var oAcN = Vector.cross(offsetA, normal),
293-
oBcN = Vector.cross(offsetB, normal),
294-
share = contactShare / (bodyA.inverseMass + bodyB.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
312+
// account for mass, inertia and contact offset
313+
var oAcN = offsetAX * normalY - offsetAY * normalX,
314+
oBcN = offsetBX * normalY - offsetBY * normalX,
315+
share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
295316

296-
normalImpulse *= share;
317+
// raw impulses
318+
var normalImpulse = (1 + pair.restitution) * normalVelocity * share;
297319
tangentImpulse *= share;
298320

299321
// handle high velocity and resting collisions separately
300-
if (normalVelocity < 0 && normalVelocity * normalVelocity > Resolver._restingThresh * timeScaleSquared) {
322+
if (normalVelocity * normalVelocity > restingThresh && normalVelocity < 0) {
301323
// high normal velocity so clear cached contact normal impulse
302324
contact.normalImpulse = 0;
303325
} else {
304326
// solve resting collision constraints using Erin Catto's method (GDC08)
305327
// impulse constraint tends to 0
306328
var contactNormalImpulse = contact.normalImpulse;
307-
contact.normalImpulse = Math.min(contact.normalImpulse + normalImpulse, 0);
329+
contact.normalImpulse += normalImpulse;
330+
contact.normalImpulse = contact.normalImpulse < 0 ? contact.normalImpulse : 0;
308331
normalImpulse = contact.normalImpulse - contactNormalImpulse;
309332
}
310333

311334
// handle high velocity and resting collisions separately
312-
if (tangentVelocity * tangentVelocity > Resolver._restingThreshTangent * timeScaleSquared) {
335+
if (tangentVelocity * tangentVelocity > restingThreshTangent) {
313336
// high tangent velocity so clear cached contact tangent impulse
314337
contact.tangentImpulse = 0;
315338
} else {
316339
// solve resting collision constraints using Erin Catto's method (GDC08)
317340
// tangent impulse tends to -tangentSpeed or +tangentSpeed
318341
var contactTangentImpulse = contact.tangentImpulse;
319-
contact.tangentImpulse = Common.clamp(contact.tangentImpulse + tangentImpulse, -maxFriction, maxFriction);
342+
contact.tangentImpulse += tangentImpulse;
343+
if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction;
344+
if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction;
320345
tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
321346
}
322347

323348
// total impulse from contact
324-
impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse);
325-
impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse);
349+
var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,
350+
impulseY = normalY * normalImpulse + tangentY * tangentImpulse;
326351

327352
// apply impulse from contact
328353
if (!(bodyA.isStatic || bodyA.isSleeping)) {
329-
bodyA.positionPrev.x += impulse.x * bodyA.inverseMass;
330-
bodyA.positionPrev.y += impulse.y * bodyA.inverseMass;
331-
bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia;
354+
bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
355+
bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
356+
bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;
332357
}
333358

334359
if (!(bodyB.isStatic || bodyB.isSleeping)) {
335-
bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass;
336-
bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass;
337-
bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia;
360+
bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
361+
bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
362+
bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia;
338363
}
339364
}
340365
}

0 commit comments

Comments
 (0)