- 简介
这次讲解动理学的最后一部分,动量计算后更新速度。 - 正文
下面这段代码,主要流程就是分别计算分离轴方向的动量和垂直分离轴方向的动量。
void Arbiter::ApplyImpulse()
{
Body* b1 = body1;
Body* b2 = body2;
for (int i = 0; i < numContacts; ++i)
{
Contact* c = contacts + i;
c->r1 = c->position - b1->position;
c->r2 = c->position - b2->position;
//碰撞前的相对速度
Vec2 dv = b2->velocity + Cross(b2->angularVelocity, c->r2) - b1->velocity - Cross(b1->angularVelocity, c->r1);
float vn = Dot(dv, c->normal);
//c->bias为补偿系数,得到的就是总冲量
float dPn = c->massNormal * (-vn + c->bias);
//是否累计冲量
if (World::accumulateImpulses)
{
// Clamp the accumulated impulse
float Pn0 = c->Pn;
//这里做是是冲量的累加,如果累加结果小于0了就等于0
c->Pn = Max(Pn0 + dPn, 0.0f);
//还原出累加进去的冲量大小
dPn = c->Pn - Pn0;
}
else
{
//直接获取冲量
dPn = Max(dPn, 0.0f);
}
//获得normal方向上的冲量
Vec2 Pn = dPn * c->normal;
//冲量作用在线速度和角速度上
b1->velocity -= b1->invMass * Pn;
b1->angularVelocity -= b1->invI * Cross(c->r1, Pn);
b2->velocity += b2->invMass * Pn;
b2->angularVelocity += b2->invI * Cross(c->r2, Pn);
// Relative velocity at contact
dv = b2->velocity + Cross(b2->angularVelocity, c->r2) - b1->velocity - Cross(b1->angularVelocity, c->r1);
//计算出垂直于分离轴方向的向量
Vec2 tangent = Cross(c->normal, 1.0f);
float vt = Dot(dv, tangent);
float dPt = c->massTangent * (-vt);
//摩擦力部分
if (World::accumulateImpulses)
{
// Compute friction impulse
float maxPt = friction * c->Pn;
// Clamp friction
float oldTangentImpulse = c->Pt;
c->Pt = Clamp(oldTangentImpulse + dPt, -maxPt, maxPt);
dPt = c->Pt - oldTangentImpulse;
}
else
{
float maxPt = friction * dPn;
dPt = Clamp(dPt, -maxPt, maxPt);
}
// Apply contact impulse
Vec2 Pt = dPt * tangent;
b1->velocity -= b1->invMass * Pt;
b1->angularVelocity -= b1->invI * Cross(c->r1, Pt);
b2->velocity += b2->invMass * Pt;
b2->angularVelocity += b2->invI * Cross(c->r2, Pt);
}
}
实际内容不多,就是上一篇的公式的完整实现,然后将摩擦力同时也作用上,最后将速度变化更新,这个函数需要多次迭代,我觉得就是模拟物体在碰撞过程中的形变后反弹的这个过程。