基于2D多边形的碰撞检测和响应
http://yiyo213.iteye.com/blog/813181
- 可以精确模拟逼真的简单物理学,例如反弹,摩擦,斜面的滑行
- 碰撞检测可以更精确的用于高速精灵系统。在基于精灵的系统中,如果物体移动过快就会在跳过另一个物体。
- 基于向量数学因此可以扩展到3D,然而精灵碰撞系统被严格限制在2D的情况下。
特性
有一个刚体系统的例子,使用了Chrsi Hecker的物理教程。
限制
显然有无数的平面可以用来分割两个物体。但是已经经过证明的是:你只需要使用一部分平面来进行测试,对于BOX从上图中可以看出平面的法线为BOX B的长轴。
a) 生成需要测试的分离轴
b) 计算每一个多边形在分离轴法线上的投影
c) 检测这些投影是否相交
bool Intersect(Polygon A, Polygon B) |
void CalculateInterval(Vector Axis, Polygon P, float& min, float& max) |
for(J = A.num_vertices-1, I = 0; I < A.num_vertices; J = I, I ++) if (AxisSeparatePolygons(N, A, B)) |
二、用于碰撞响应的扩展分离坐标轴方法
bool Intersect(Polygon A, Polygon B, Vector& MTD) if (AxisSeparatePolygons(N, A, B)) if (AxisSeparatePolygons (N, A, B)) // find the MTD among all the separation vectors // makes sure the push vector is pushing A away from B return true; |
bool AxisSeparatePolygons(Vector& Axis, Polygon A, Polygon B) CalculateInterval(Axis, A, mina, maxa); if (mina > maxb || minb > maxa) // find the interval overlap // convert the separation axis into a push vector (re-normalise Axis *= depth / axis_length_squared; |
Vector FindMTD(Vector* PushVectors, int iNumVectors) |
A.Postion += MTD * 0.5f; |
显然,如果物体A是静态的,那么B将被完全的MTD推开(B.Position-=MTD)而A将不会被推开。
三、对快速移动的物体做进一步扩展
bool AxisSeparatePolygons(Vector Axis, Polygon A, Polygon B, Vector Offset, Vector Vel, float& t, float tmax); |
bool Collide( const Vector* A, int Anum, // All the separation axes xAxis[iNumAxes] = Vector(-xVel.y, xVel.x); // test separation axes of A if (!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, taxis[iNumAxes], t)) iNumAxes++; // test separation axes of B if (!IntervalIntersect( A, Anum, B, Bnum, xAxis[iNumAxes], xOffset, xVel, taxis[iNumAxes], t)) if (!FindMTD(xAxis, taxis, iNumAxes, N, t)) // make sure the polygons gets pushed away from each other. return true; |
bool AxisSeparatePolygons ( Vector N, Polygon A, Polygon B, Vector Offset, Vector Vel, float &t, float tmax) CalculateInterval(N, A, min0, max0); float h = Offset dot N; float d0 = min0 - max1; // if overlapped, do < 0 // separated, test dynamic intervals // small velocity, so only the overlap test will be relevant. float t0 =-d0 / v; // time of impact to d0 reaches 0 // intersection time too late or back in time, no collision return false; |
bool FindCollisionPlane (Vector* Axis, float* taxis, int iNumAxes, Vector& Ncoll, float& tcoll) // found a collision // nope, find overlaps taxis[i] /= n; // normalise interval overlap too // remember, those numbers are negative, so take the closest to 0 return (mini != -1); |
现在,你拥有了一个可以检测未来碰撞的的检测系统,或者当重叠的时候,返回碰撞平面和碰撞深度/时间
四、 基本弧碰撞响应
下面要作的是用给定的量将两个物体分离,并添加一点摩擦和一些静态摩擦,以便使物体静止在斜面上。
该部分使用简单的速度影响算法。同样,为了使碰撞响应更加真实,物体被赋予了质量(更好的是质量的倒数)。
质量的倒数是比较常用的,该值为零意味着该物体具有无穷大的质量,并因此不能移动。同时速度响应中使用质量的倒数具有更好的物理精确性。
现在我们知道多边形A在位置PA具有速度VA,与位置PB速度VB的多边形B发生碰撞。Ncoll和tcoll定义了碰撞平面。如果碰撞前是交叠的,首先分离两个物体,如下:
if (tcoll < 0)
{
if (A.InvMass == 0)
PB += Ncoll * tcoll;
else if (B.InvMass == 0)
PA -= Ncoll * tcoll;
else
{
PA -= Ncoll * (tcoll * 0.5f);
PB += Ncoll * (tcoll * 0.5f);
}
}
然后可以调用碰撞响应的代码,为了简化,我们可以考虑一个粒子碰到一个平面上
这里V表示粒子的进入速度,V’是粒子发生碰撞后的速度,N为平面的法向。
V’ = V – (2 * (V . N)) * N
理想状态下,碰撞前后粒子的能量是相同的。但是我们可以给粒子的碰撞加入弹性系数
V’ = V – ((1 + elasticity) * (V . N)) * N
弹性系数的范围为[0,1]如果为零意味着粒子将沿着平面滑动,如果为1,粒子将没有能量损耗的弹开。
同样我们可以加入一些摩擦。如果我们沿着碰撞的法线和碰撞平面方向分解速度,我们可以同时计算弹性系数和摩擦力。
这里,速度被沿着平面的法向和平面分解。弹性系数将影响沿着平面法向的响应(Vn),摩擦力将影响速度的切向(Vt)。
同样摩擦系数的范围为[0,1]. 0意味着没有摩擦力,1意味着粒子将突然停止。
Vn = (V . N) * N;
Vt = V – Vn;
V’ = Vt * (1 – friction) + Vn * -(elasticity);
对于静摩擦力,简单地在速度Vt小于给定的值时设置Vt为(0,0), 或者设置摩擦系数稍微比1大(1.001f)。
现在,计算两个物体间的碰撞响应。原理是相同的。然而,计算是基于物体的相对速度的,物体将象上述一样受到影响。结果将添加到每一个物体上。
现在我们需要修改一下系数,因为现在我们使用了相对的概念
Vector V = Va – Vb; // relative velocity
Vn = (V . N) * N;
Vt = V – Vn;
if (Vt.Length() < 0.01f) friction = 1.01f;
// response
V’ = Vt * -(friction) + Vn * -(1 + elasticity);
Va += V’ * 0.5f;
Vb -= V’ * 0.5f;
这里使物体A和物体B具有相同的响应结果。
为了使结果更加有趣,A和B可以有不同质量。显然较轻的物体会受到较大影响,较重的物体被碰撞影响较小。所以我们可以使用质量来确定两个物体碰撞响应效果。较大的物体具有较小的质量的倒数,如果质量为无穷大质量的倒数为零。
Va += V’ * (InvMassA) / (InvMassA + InvMassB);
Vb -= V’ * (InvMassB) / (InvMassA + InvMassB);
五、处理旋转
Pworld = Plocal * OA + PA
(Pworld – PA) = Plocal * OA
(Pworld – PA) * OAT = Plocal * OA * OAT
Plocal = (Pworld – PA) * OAT
Dworld = Dlocal * OA
Dworld * OAT = Dlocal * OA * OAT
Oworld = Olocal * OA
Oworld * OAT= Olocal * OA * OAT
PB’ = (PB – PA) * OAT
DB’ = (DB – DA) * OAT
OB’ = (OB) * OAT
这些会使你觉得迷惑,另一个解决方案基本上不会被局部坐标所迷惑,即所有的操作都在全局坐标中完成。这个方法的确定就是你不得不保持一个多边形 的副本,因为每一个多边形需要分别在世界坐标中计算一次。好处是你不需要再每次处理碰撞的时候重新计算变换。这个对2D游戏来数是非常好的,但是在3D 中,你不会想在每一帧中变换一次物体仅仅为了碰撞检测的目的,尤其是当物体存储在树中并有一个非常复杂的形状的时候。
六、计算触点
int FindSupportPoints(const Vector& N, float t,
const Vector* A, int Anum,
const Vector& PA, const Vector& VA,
const Matrix& OA, Vector* S)
{
Vector Norm = N ^ OA;
float d[32];
float dmin;
dmin = d[0] = A[0] * Norm;
for(int i = 1; i < Anum; i ++)
{
d[i] = A[i] * Norm;
if (d[i] < dmin)
{
dmin = d[i];
}
}
int Snum = 0;
const float threshold = 1.0E-3f;
for(int i = 0; i < Anum; i ++)
{
if (d[i] < dmin + threshold)
{
S[Snum++] = Transform(A[i], PA, VA, OA, t);
if (Snum == 2)
return Snum;
}
}
return Snum;
}
Vector Transform(const Vector& Vertex, const Vector& P, const Vector& V, const Matrix& xOrient, float t)
{
// convert point into world space
Vector T = P + (Vertex * xOrient);
// collision forwatd in time, need to translate to moment of collision
if(t > 0.0f)
T += V * t;
return T;
}
Vector FindClosestPoint(const Vector& V, const Vector& A, const Vector& B, float* pt)
{
Vector AV = V - A;
Vector AB = B - A;
float t = (AV * AB) / (AB * AB);
if (t < 0.0f)
t = 0.0f;
else if (t > 1.0f)
t = 1.0f;
if (pt) *pt = t;
Vector P = A + t * AB;
return P;
}
有了这些触点,你就可以编写一个基本的刚体系统,物体将比以前更真实的相互碰撞并响应碰撞。
为了不浪费时间介绍动态刚体,可以直接参参见下面的连接: http://www.d6.com/users/checker/dynamics.htm#articles 这里,展示了如何在2D游戏中实施真实的物理。 我将介绍一些我所做的扩展,首先,计算给定凸多边形的惯量是有技巧的。需要提醒你的是,惯量适用于角度变化,质量适用于线形变化。较高的惯量对应于较大的质量,在这种情况下物体将很难旋转。相反,较小的惯量使得物体的角速度更易改变。 质量和惯量是有联系的,因为它们都依赖于体积,密度和物体的平衡,下面的连接给出了一些参考 http://www.physicsforums.com/showthread.php?s=e251fddad79b926d003e2d4154799c14&t=25293&page=2&pp=15 一句话,计算惯量的公式为: 这里: M是质量,N是顶点数,Pn是多边形的一个顶点,||..||表示求模运算。在2D中表示向量的长度。 可以使用下面的公式根据组成多边形材质的密度来计算惯量 这里:P是密度,N是顶点数, Pn是多边形的顶点, ||..||表示求模,从上述方程中,你可以推理出计算质量的等式。 该系统的其它模式是处理交叠。这可以避免一个物体陷入另一个物体,因为使用推力计算在低速的时候是非常不精确的。为了解决交叠问题,即简单的方法是沿着碰撞法线根据碰撞深度将物体推开。当然只有在检测到交叠的时候才使用它。 为了使它更为精确,物体的移动应该依赖于它们质量的比率,因此较轻的物体应该移动更多,而较重的物体移动较少,当然具有无穷大质量的物体是不会移动的。 至于摩擦力,基本的是动态摩擦力,它将沿着物体速度的反向添加一个力,大小为||u*Jn||其中u是动摩擦系数Jn是压力。 静态摩擦力总是比较简单的模型。我选则的静态摩擦力的模型是将物体与一个不可见的物体在碰撞平面上发生碰撞。正碰撞的计算是非常简单的。碰撞力的方向是速度的反向,触点的速度会被抵消(基本上,恢复系数稍微比1大) 好了,剩下的部分就按照Chris Hecke的教程。物体翻转,碰撞,做一系列疯狂的事情,并且看起来非常的真实。 |
基于2D多边形的碰撞检测和响应相关推荐
- Unity通过脚本实现不规则多边形的碰撞检测
先上效果图 可能大家都已经对Polygon Collider 2D这个组件已经非常的熟悉,就是一个判断多边形碰撞的组件,我们可以通过编辑形状大小来实现对不同多边形的碰撞检测. 但是如果遇到较为复杂的多 ...
- WACV 2020 | 基于2D卷积处理成本签名的快速立体匹配
点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 本文由知乎作者青青韶华授权转载,不得擅自二次转载. 原文链接:https://zhuanlan.zhi ...
- 向量几何在游戏编程中的使用系列二之2-D物体间的碰撞响应
2019独角兽企业重金招聘Python工程师标准>>> 2-D物体间的碰撞响应 这次我要分析两个球体之间的碰撞响应,这样我们就可以结合以前的知识来编写一款最基本的2-D台球游戏了,虽 ...
- php-人员权限管理源码,基于ThinkPHP5+ACE框架开发的响应式通用后台权限管理系统PHP源码|响应式轻量级企业网站管理系统...
源码介绍 基于ThinkPHP5+ACE框架开发的响应式通用后台权限管理系统PHP源码是一款响应式轻量级企业网站管理系统,采用ThinkPHP5.0.10+国外ACE1.40的UI模板的后台内容管理框 ...
- 通过多线程为基于 .NET 的应用程序实现响应迅速的用户
通过多线程为基于 .NET 的应用程序实现响应迅速的用户 Ian Griffiths 本文假设您熟悉 .NET.C# 和 Windows 窗体 下载本文的代码: Multithreading.exe ...
- 通过多线程为基于 .NET 的应用程序实现响应迅速的用户[改进]
通过多线程为基于 .NET 的应用程序实现响应迅速的用户 Ian Griffiths [原文:http://net66.cnblogs.com/net66/admin/archive/2005/08 ...
- 通过多线程为基于 .NET 的应用程序实现响应迅速的用户(MSDN)
通过多线程为基于 .NET 的应用程序实现响应迅速的用户 发布日期: 12/28/2004 | 更新日期: 12/28/2004 Ian Griffiths 本文假设您熟悉 .NET.C# 和 Win ...
- 基于 2D 激光雷达和实时回环优化的 SLAM 算法
基于 2D 激光雷达和实时回环优化的 SLAM 算法 原文: https://www.ixueshu.com/document/771d692c7d3c0c40318947a18e7f9386.htm ...
- php写网页6,基于ThinkPHP6+AdminLTE框架开发的响应式企业网站CMS系统PHP源码,ThinkPHP6开发的后台权限管理系统...
源码介绍 基于最新ThinkPHP6+AdminLTE框架开发的响应式企业网站CMS系统PHP源码,基于最新版本的ThinkPHP 6.0.0RC3框架,后台前端框架采用AdminLTE.系统的核心理 ...
- 影像组学视频学习笔记(35)-基于2D超声影像的影像组学特征提取、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/f82d30289d68 来源:简书,已获转载授权 RadiomicsWorld.com "影像组学世界" ...
最新文章
- 将一个一维数组转化为二进制表示矩阵。例如_算法之矩阵最大区域问题
- npm安装less报错 rollbackFailedOptional: verb npm-session
- 打工人的一把辛酸泪,网站提现为啥多于800要扣20%的税?我想这些东西你需要明白
- redhat安装pure-ftpd+mysql时出现libmysqlclient错误的解决办法
- ·MySQL数据库管理(SQL操作命令,解决忘记密码,设置用户权限)
- 视觉SLAM笔记(15) 李群与李代数
- Java基础学习总结(124)——Java9逆天的十大新特性
- 电脑复制粘贴_ALTC 让电脑和手机能“跨屏”互相复制粘贴的免费工具!
- 深入继承之抽象类和接口综合分析及完整案列解说(一)
- Android Gradle配置构建
- 05.LoT.UI 前后台通用框架分解系列之——漂亮的时间选择器
- 大数据入门教程系列之Hive篇汇总
- 基于x86汇编的飞机大战
- Python编程快速上手----让繁琐的工作自动化(1. python编程基础)
- uniapp小说阅读
- 外汇天眼:Apple与MetaQuotes之争!谁是下一个Apple?谁会成下一个MT4/5?
- 51cto python数据分析系列课程 55g_热图_ Python数据分析系列视频课程--玩转数据可视化_数据可视化视频-51CTO学院...
- 黑科技!无需代码快速搭建网站的平台来了
- Hbuildx中使用uni-app 新建 微信小程序项目 以及 运行相关配置
- 离线安装.Net Framework 3.5
热门文章
- fantastic-matplotlib:案例集合:
- 6-1 定义一个矩形类(C++构造函数) (10 分)
- oracle赋权语句详解,Oracle GRANT 赋权详解
- matlab 数字和字符串转换
- smartbi连接mysql数据库_数据源连接 - Smartbi V7 帮助中心 - Smartbi 在线知识中心
- 常用系统修复软件绿色工具包
- 考研四六级英语引用名句
- win10+mosquitto服务器配置单向认证与双向认证
- C语言输入Aa1Bb2Cc3,C语言shuzu_test.doc
- 心知天气数据API 产品的高并发实践