📄 tutorial_30.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><!-- 这篇文章由Dancingwind翻译,作者的联系方式zhouwei02@mails.tsinghua.edu.cn --><title>NeHe OpenGL教程第三十课,DancingWind翻译</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
A:link {COLOR: #ccaaff; TEXT-DECORATION: none}
A:visited {COLOR: #ccaaff; TEXT-DECORATION: none}
A:active {COLOR: #ccaaff; TEXT-DECORATION: none}
A:hover {COLOR: #ffccaa; TEXT-DECORATION: none}
</style></head><body bgcolor="#000000" text="#ffffff"><br><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td height="130" width="326"><img src="Tutorial_30_files/logo.png" height="130" width="326"></td>
<td align="center" valign="middle" width="75%"><font color="#ffccaa" size="+3"><b><i>第30课</i></b></font></td>
</tr></tbody></table>
<!-- 上边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_30_files/tl.jpg" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_30_files/tc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_30_files/tr.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<!-- 中部-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<!-- 中部左边框-->
<td background="Tutorial_30_files/l.gif"><img src="Tutorial_30_files/l.gif" height="28" width="28"></td>
<!-- 中部文字部分-->
<td valign="top" width="100%">
<table border="0" width="100%">
<tbody><tr>
<td width="28%"><img src="Tutorial_30_files/lesson30.jpg" height="180" width="240"></td>
<td width="72%"><p><font class="head">碰撞检测:</font></p>
<p><font size="3">这是一课激动的教程,你也许等待它多时了。你将学会碰撞剪裁,物理模拟太多的东西,慢慢期待吧。</font></p></td>
</tr>
</tbody></table>
</td>
<!-- 中部右边框-->
<td background="Tutorial_30_files/r.gif"><img src="Tutorial_30_files/r.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<!-- 下边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_30_files/bl.gif" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_30_files/bc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_30_files/br.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_30_files/l.png"><img src="Tutorial_30_files/l.png"></td>
<td valign="top" width="100%">碰撞检测和物理模拟(作者:Dimitrios Christopoulos (christop@fhw.gr))<br>
<br> <b><u>碰撞检测</u></b> <br> <br>
这是一个我遇到的最困难的题目,因为它没有一个简单的解决办法.对于每一个程序都有一种检测碰撞的方法.当然这里有一种蛮力,它适用于各种不同的应用,当它非常的费时.<br>
我们将讲述一种算法,它非常的快,简单并易于扩展.下面我们来看看这个算法包含的内容:<br> <br>
1) 碰撞检测
<ul>
<li>移动的球-平面</li>
<li>移动的球-圆柱</li>
<li>移动的球-移动的球</li>
</ul>
2) 基于物理的建模
<ul>
<li>碰撞表示</li>
<li>应用重力加速度</li>
</ul>
3) 特殊效果
<ul>
<li>爆炸的表示,利用互交叉的公告板形式</li>
<li>声音使用Windows声音库</li>
</ul>
4) 关于代码
<ul>
<li>代码被分为以下5个部分</li>
</ul>
<table border="0">
<tbody><tr>
<td>Lesson30.cpp</td>
<td> </td>
<td>: 主程序代码l</td>
</tr>
<tr>
<td>Image.cpp,</td>
<td>Image.h</td>
<td>: 加载图像</td>
</tr>
<tr>
<td>Tmatrix.cpp,</td>
<td>Tmatrix.h</td>
<td>: 矩阵</td>
</tr>
<tr>
<td>Tray.cpp,</td>
<td>Tray.h</td>
<td>: 射线</td>
</tr>
<tr>
<td>Tvector.cpp,</td>
<td>Tvector.h</td>
<td>: 向量</td>
</tr>
</tbody></table>
<p><br>
<br>
1) 碰撞检测 <br>
<br>
我们使用射线来完成相关的算法,它的定义为: <br>
<br>
<i>射线上的点 = 射线的原点+ t * 射线的方向</i> <br>
<br>
t 用来描述它距离原点的位置,它的范围是[0, 无限远). <br>
<br>
现在我们可以使用射线来计算它和平面以及圆柱的交点了。<br>
<br>
射线和平面的碰撞检测: <br>
<br>
平面被描述为:<br>
<br>
<i>Xn dot X = d</i> <br>
<br>
Xn 是平面的法线.<br>
X 是平面上的一个点.<br>
d 是平面到原点的距离. <br>
<br>
现在我们得到射线和平面的两个方程: <br>
<br>
<i>PointOnRay = Raystart + t * Raydirection<br>
Xn dot X = d</i> <br>
<br>
如果他们相交,则上诉方程组有解,如下所示:<br>
<br>
<i>Xn dot PointOnRay = d</i> </p>
<p><i>(Xn dot Raystart) + t * (Xn dot Raydirection) = d</i> <br>
<br>
解得 t: <br>
<br>
<i>t = (d - Xn dot Raystart) / (Xn dot Raydirection)</i> <br>
<br>
t代表原点到与平面相交点的参数,把t带回原方程我们会得到与平面的碰撞点.如果Xn*Raydirection=0。则说明它与平面平行,则将不产生碰撞。如果t为负值,则说明交点在射线的相反方向,也不会产生碰撞<font face="Tahoma,Verdana,sans-serif" size="-1">。</font></p></td>
<td background="Tutorial_30_files/r.png"><img src="Tutorial_30_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre><font color="#ffffaa" size="3">//判断是否和平面相交,是则返回1,否则返回0</font><br>int TestIntersionPlane(const Plane& plane,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal)<br>{</pre>
<p> double DotProduct=direction.dot(plane._Normal);<br>
double l2;</p>
<p> <font color="#ffffaa" size="3">//判断是否平行于平面</font><br>
if ((DotProduct<ZERO)&&(DotProduct>-ZERO)) <br>
return 0;</p>
<p> l2=(plane._Normal.dot(plane._Position-position))/DotProduct;</p>
<p> if (l2<-ZERO) <br>
return 0;</p>
<p> pNormal=plane._Normal;<br>
lamda=l2;<br>
return 1;<br>
}</p>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_30_files/l.png"><img src="Tutorial_30_files/l.png"></td>
<td valign="top" width="100%"><font face="Tahoma,Verdana,sans-serif" size="-1"> <font size="+1"><u>射线-圆柱的碰撞检测</u></font>
<br>
<br>
</font>计算射线和圆柱方程组得解。</td>
<td background="Tutorial_30_files/r.png"><img src="Tutorial_30_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3"><pre>int TestIntersionCylinder(const Cylinder& cylinder,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal,TVector& newposition)
</pre></font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_30_files/l.png"><img src="Tutorial_30_files/l.png"></td>
<td valign="top" width="100%">球-球之间的碰撞检测<br> <br>
球被表示为中心和它的半径,决定两个球是否相交就是求出它们之间的距离是否小于它们的直径。<br> <br>
在处理两个移动的球是否相交时,有一个bug就是,当它们的移动速度太快,回出现它们相交,但在相邻的两步检测不出它们是否相交的情况,如下图所示:<br>
<br> <center>
<img src="Tutorial_30_files/figure1.jpg"><br>
图 1
</center>
<br> <br>
有一个替代的办法就是细分相邻的时间片断,如果在这之间发生了碰撞,则确定有效。我们把这个细分时间段设置为3,代码如下:<font face="Tahoma,Verdana,sans-serif">
<center>
</center>
</font></td>
<td background="Tutorial_30_files/r.png"><img src="Tutorial_30_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_30_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_30_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_30_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"><font color="#ffffaa">//判断球和球是否相交,是则返回1,否则返回0</font><br>int FindBallCol(TVector& point, double& TimePoint, double Time2, int& BallNr1, int& BallNr2)<br>{<br> TVector RelativeV;<br> TRay rays;<br> double MyTime=0.0, Add=Time2/150.0, Timedummy=10000, Timedummy2=-1;<br> TVector posi;<br> <br> <font color="#ffffaa">//判断球和球是否相交</font><br> for (int i=0;i<NrOfBalls-1;i++)<br> {<br> for (int j=i+1;j<NrOfBalls;j++)<br> { <br> RelativeV=ArrayVel[i]-ArrayVel[j];<br> rays=TRay(OldPos[i],TVector::unit(RelativeV));<br> MyTime=0.0;</font></pre>
<p><font color="#aaffaa" size="3"> if ( (rays.dist(OldPos[j])) > 40) continue; </font></p>
<p><font color="#aaffaa" size="3"> while (MyTime<Time2)<br>
{<br>
MyTime+=Add;<br>
posi=OldPos[i]+RelativeV*MyTime;<br>
if (posi.dist(OldPos[j])<=40) {<br>
point=posi;<br>
if (Timedummy>(MyTime-Add)) Timedummy=MyTime-Add;<br>
BallNr1=i;<br>
BallNr2=j;<br>
break;<br>
}<br>
<br>
}<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -