博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分离被碰撞物体, 求碰撞冲量
阅读量:6275 次
发布时间:2019-06-22

本文共 4649 字,大约阅读时间需要 15 分钟。

如果已经知道了两个相互碰撞的物体进行碰撞前的 线速度, 角速度, 质心坐标, 被碰撞点的坐标, 碰撞方向, 质量, 转动惯量, 恢复系数, 那么可以用以下公式求得两个物体对对方造成的碰撞冲量大小:

J = -vr (e + 1) / ( 1/m1 + 1/m2 + n * ((r1 × n) / I1) × r1 + n * ((r2 × n) / I2) × r2 )

其中:

m1与m2是两物体的质量

I1与I2是两物体的转动惯量

e是恢复系数

r1r2是从物体质心指向被碰撞点的向量, 也就是力臂

vr = v1' - v2'

v1' = v1 + r1×ω1, 即把角速度转成线速度也加到速度上来进行计算

n是两物体的碰撞方向向量, 有提到如何求

 

求得J之后, 将冲量分别施加在两物体上可以得到物体被碰撞后的线速度和角速度:

v1+ = v1- + (Jn) / m1

ω1+ω1- + (r1 × Jn) / I1

v2+ = v2- + (- Jn) / m2

ω2+ = ω2- + (r2 × - Jn) / I2

 

上面的公式可以在《游戏开发物理学》的103页找到, 有写如何推导. 也可以看的最后一部分.

 

applyImpulse: function (oImpulse, oPosition) {                this.velocity = this.velocity.add(oImpulse.mul(this.inverseMass));                this.angularVelocity += oPosition.sub(this.centroid).cross(oImpulse) * this.inverseInertia;            }
applyCollisionImpulse: function (bodyA, bodyB, contactPoint, normal, e) {                var cp = contactPoint,                    rA = cp.sub(bodyA.centroid),                    rB = cp.sub(bodyB.centroid),                    vA = bodyA.velocity.add(rA.scalarCross(bodyA.angularVelocity)),                    vB = bodyB.velocity.add(rB.scalarCross(bodyB.angularVelocity)),                    invIA = bodyA.inverseInertia,                    invIB = bodyB.inverseInertia,                    invMA = bodyA.inverseMass,                    invMB = bodyB.inverseMass,                    vr = vA.sub(vB),                    rsnA = rA.cross(normal),                    rsnB = rB.cross(normal),                    kn = invMA + invMB + rsnA * rsnA * invIA + rsnB * rsnB * invIB,                    jn = -(1 + e) * vr.dot(normal) / kn,                    impulse = normal.mul(jn);                    bodyA.applyImpulse(impulse, cp);                    bodyB.applyImpulse(impulse.negate(), cp);                }

2D向量与标量叉乘可以这样算:

scalarCross: function (num) {                return new Vector2D(-num * this.y, num * this.x);            }

 

如果希望添加摩擦力, 可以这样修改:

applyCollisionImpulse: function (bodyA, bodyB, cp, normal, e, friction) {                var rA = cp.sub(bodyA.centroid),                    rB = cp.sub(bodyB.centroid),                    vA = bodyA.velocity.add(rA.scalarCross(bodyA.angularVelocity)),                    vB = bodyB.velocity.add(rB.scalarCross(bodyB.angularVelocity)),                    invIA = bodyA.inverseInertia,                    invIB = bodyB.inverseInertia,                    invMA = bodyA.inverseMass,                    invMB = bodyB.inverseMass,                    vr = vA.sub(vB),                    rsnA = rA.cross(normal),                    rsnB = rB.cross(normal),                    kn = invMA + invMB + rsnA * rsnA * invIA + rsnB * rsnB * invIB,                    jn = -(1 + e) * vr.dot(normal) / kn,                    impulse = normal.mul(jn);                    bodyA.applyImpulse(impulse, cp);                    bodyB.applyImpulse(impulse.negate(), cp);                    vA = bodyA.velocity.add(rA.scalarCross(bodyA.angularVelocity));                    vB = bodyB.velocity.add(rB.scalarCross(bodyB.angularVelocity));                    vr = vA.sub(vB);                    var tangent = vr.sub(normal.mul(vr.dot(normal))).normalize(),                        rstA = rA.cross(tangent),                        rstB = rB.cross(tangent),                        kt = invMA + invMB + rstA * rstA * invIA + rstB * rstB * invIB,                        jf = Math.min(vr.dot(tangent) / kt, Math.abs(jn * friction)),                        tangentImpulse = tangent.mul(jf);                    bodyA.applyImpulse(tangentImpulse.negate(), cp);                    bodyB.applyImpulse(tangentImpulse, cp);                }

其中jf = Math.min(vr.dot(tangent) / kt, Math.abs(jn * friction))中的jn * friction就是 μ * 压力冲量, vr.dot(tangent) / kt 是使得摩擦力恰好使切线方向速度变成0的冲量大小, 因为摩擦力会在相对速度为0时变成0, 不如此计算最大摩擦冲量的话施加摩擦冲量后可能会导致切向方向物体反向加速.

 

仅靠碰撞冲量实际无法完全分离两个物体, 因为物体可以相互嵌入而不是恰好接触. 已知两物体的相互嵌入距离的话可以用下面的方法修正物体的位置:

correctPosition: function (bodyA, bodyB, penetration) {                var maxPenetration = 0.05,                    correctPercent = 0.4,                    correction,                    tA,                    tB;                if (penetration <= maxPenetration) {                    return;                }                correction = this.normal.mul((penetration - maxPenetration) / (bodyA.inverseMass + bodyB.inverseMass)                     * correctPercent);                tA = correction.negate().mul(bodyA.inverseMass);                tB = correction.mul(bodyB.inverseMass);                bodyA.translate(tA.x, tA.y);                bodyB.translate(tB.x, tB.y);                return;            }

有简单解释这个函数是如何工作的.

 

转载于:https://www.cnblogs.com/pngx/p/4260419.html

你可能感兴趣的文章
收费视频网站Netflix:用户到底想要“点”什么?
查看>>
MacOS High Sierra 12 13系统转dmg格式
查看>>
关于再次查看已做的多选题状态逻辑问题
查看>>
动态下拉菜单,非hover
查看>>
政府安全资讯精选 2017年第十六期 工信部发布关于规范互联网信息服务使用域名的通知;俄罗斯拟建立备用DNS;Google打击安卓应用在未经同意情况下收集个人信...
查看>>
简单易懂的谈谈 javascript 中的继承
查看>>
多线程基础知识
查看>>
iOS汇编基础(四)指针和macho文件
查看>>
Laravel 技巧锦集
查看>>
Android 使用 ViewPager+RecyclerView+SmartRefreshLayout 实现顶部图片下拉视差效果
查看>>
Flutter之基础Widget
查看>>
写给0-3岁产品经理的12封信(第08篇)——产品运营能力
查看>>
ArcGIS Engine 符号自动化配置工具实现
查看>>
小程序 · 跳转带参数写法,兼容url的出错
查看>>
flutter error
查看>>
Flask框架从入门到精通之模型数据库配置(十一)
查看>>
10年重新出发
查看>>
2019年-年终总结
查看>>
聊聊elasticsearch的RoutingService
查看>>
让人抓头的Java并发(一) 轻松认识多线程
查看>>