NEHE OPENGL第三十课碰撞检测

NeHe OpenGL第三十课:碰撞检测
碰撞检测:
这是一课激动的教程,你也许等待它多时了。你将学会碰撞剪裁,物理模拟太多的东西,慢慢期待吧。
碰撞检测和物理模拟(作者:Dimitrios Christopoulos())
碰撞检测
这是一个我遇到的最困难的题目,因为它没有一个简单的解决办法.对于每一个程序都有一种检测碰撞的方法.当然这里有一种蛮力,它适用于各种不同的应用,当它非常的费时.
我们将讲述一种算法,它非常的快,简单并易于扩展.下面我们来看看这个算法包含的内容: 1)碰撞检测
移动的球-平面
高速路收费系统
移动的球-圆柱
移动的球-移动的球
2)基于物理的建模
碰撞表示
应用重力加速度
激光点云数据处理3)特殊效果
爆炸的表示,利用互交叉的公告板形式
声音使用Windows声音库
4)关于代码
代码被分为以下5个部分
Lesson30.cpp:主程序代码l
Image.cpp,Image.h:加载图像
Tmatrix.cpp,Tmatrix.h:矩阵
Tray.cpp,Tray.h:射线
Tvector.cpp,Tvector.h:向量
1)碰撞检测
我们使用射线来完成相关的算法,它的定义为:
射线上的点=射线的原点+t*射线的方向
t用来描述它距离原点的位置,它的范围是[0,无限远).
现在我们可以使用射线来计算它和平面以及圆柱的交点了。
射线和平面的碰撞检测:
平面被描述为:
Xn dot X=d
Xn是平面的法线.
X是平面上的一个点.
d是平面到原点的距离.
现在我们得到射线和平面的两个方程:复合膜
PointOnRay=Raystart+t*Raydirection
Xn dot X=d
如果他们相交,则上诉方程组有解,如下所示:
Xn dot PointOnRay=d
(Xn dot Raystart)+t*(Xn dot Raydirection)=d
解得t:
t=(d-Xn dot Raystart)/(Xn dot Raydirection)
t代表原点到与平面相交点的参数,把t带回原方程我们会得到与平面的碰撞点.如果
Xn*Raydirection=0。则说明它与平面平行,则将不产生碰撞。如果t为负值,则说明交点在射线的相反方向,也不会产生碰撞。
//判断是否和平面相交,是则返回1,否则返回0int TestIntersionPlane(const Plane& plane,const TVector&position,const TVector&direction,double&lamda,TVector& pNormal){
double DotProduct=direction.dot(plane._Normal);
double l2;
//判断是否平行于平面
if((DotProduct<ZERO)&&(DotProduct>-ZERO))
return0;
l2=(plane._Normal.dot(plane._Position-position))/DotProduct;
柜台制作
if(l2<-ZERO)
return0;
pNormal=plane._Normal;
lamda=l2;
return1;
}
射线-圆柱的碰撞检测
计算射线和圆柱方程组得解。
int TestIntersionCylinder(const Cylinder&cylinder,const TVector&position,const TVector&direction,double&lamda,TVector&pNormal,TVector&newposition)
球-球之间的碰撞检测
球被表示为中心和它的半径,决定两个球是否相交就是求出它们之间的距离是否小于它们的直径。
在处理两个移动的球是否相交时,有一个bug就是,当它们的移动速度太快,回出现它们相交,但在相邻的两步检测不出它们是否相交的情况,如下图所示:
at89s52最小系统
有一个替代的办法就是细分相邻的时间片断,如果在这之间发生了碰撞,则确定有效。我们把这个细分时间段设置为3,代码如下:
//判断球和球是否相交,是则返回1,否则返回0int FindBallCol(TVector&point,double& TimePoint,double Time2,int&BallNr1,int&BallNr2){TVector RelativeV;TRay rays;double MyTime=0.0,Add=Time2/150.0,Timedummy=10000,
Timedummy2=-1;TVector posi;//判断球和球是否相交for(int
i=0;i<NrOfBalls-1;i++){for(int
j=i+1;j<NrOfBalls;j++){RelativeV=ArrayVel[i]-ArrayVel[j];rays=TRay(OldPos[ i],TVector::unit(RelativeV));MyTime=0.0;
if((rays.dist(OldPos[j]))>40)continue;
while(MyTime<Time2)
{
MyTime+=Add;
posi=OldPos[i]+RelativeV*MyTime;
if(posi.dist(OldPos[j])<=40){
point=posi;
if(Timedummy>(MyTime-Add))Timedummy=MyTime-Add;
BallNr1=i;
BallNr2=j;
break;
}
}
}
}
if(Timedummy!=10000){TimePoint=Timedummy;
return1;
}
return0;
}
怎样应用我们的知识
现在我们已经可以决定射线和平面/圆柱的交点了,如下图所示:
当我们到了碰撞位置后,下一步我们需要知道它是否发生在当前这一步中.如果距离碰撞点的位置小于这一步球体运动的间隔,则碰撞发生.我们使用如下的方程计算运动到碰撞时所需的时间:
Tc=Dsc*T/Dst
接着我们知道碰撞点位置,如下面公式所示:
Collision point=Start+Velocity*Tc
2)基于物理的模拟
碰撞反应
为了计算对于一个静止物体的碰撞,我们需要知道以下信息:碰撞点,碰撞法线,碰撞时间.
它是基于以下物理规律的,碰撞的入射角等于反射角.如下图所示:
R为反射方向
I为入射方向
滚珠丝杠电动推杆N为法线方向
反射方向有以下公式计算:
R=2*(-I dot N)*N+I
rt2=ArrayVel[BallNr].mag();//返回速度向量的模
ArrayVel[BallNr].unit();//归一化速度向量
//计算反射向量
ArrayVel[BallNr]=TVector::unit((normal*(2*normal.dot(-ArrayVel[BallNr])))+ ArrayVel[BallNr]);
ArrayVel[BallNr]=ArrayVel[BallNr]*rt2;
球体之间的碰撞
由于它很复杂,我们用下图来说明这个原理.
U1和U2为速度向量,我们用X_Axis表示两个球中心连线的轴,U1X和U2X为U1和U2在这个轴上的分量。U1y和U2y为垂直于X_Axis轴的分量。M1和M2为两个球体的分量。V1和V2为碰撞后的速度,V1x,V1y,V2x,V2y为他们的分量。
在我们的例子里,所有球的质量都相等,解得方程为,在垂直轴上的速度不变,在X_Axis 轴上互相交换速度。代码如下:
TVector pb1,pb2,xaxis,U1x,U1y,U2x,U2y,V1x,V1y,V2x,V2y;
double a,b;
pb1=OldPos[BallColNr1]+ArrayVel[BallColNr1]*BallTime;//球1的位置
pb2=OldPos[BallColNr2]+ArrayVel[BallColNr2]*BallTime;//球2的位置
xaxis=(pb2-pb1).unit();//X-Axis轴
a=xaxis.dot(ArrayVel[BallColNr1]);//X_Axis投影系数
U1x=xaxis*a;//计算在X_Axis轴上的速度
U1y=ArrayVel[BallColNr1]-U1x;//计算在垂直轴上的速度
xaxis=(pb1-pb2).unit();
b=xaxis.dot(ArrayVel[BallColNr2]);
U2x=xaxis*b;
U2y=ArrayVel[BallColNr2]-U2x;
V1x=(U1x+U2x-(U1x-U2x))*0.5;//计算新的速度
V2x=(U1x+U2x-(U2x-U1x))*0.5;

本文发布于:2024-09-21 01:21:36,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/4/205170.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:碰撞   平面   射线   相交
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议