[翻译]XNA 3.0 Game Programming Recipes之thirty-one

PS:自己翻译的,转载请著明出处格
                                             5-9 计算精确的地形高度在顶点之间使用双线插值
问题
               当你创建一个游戏,利用地形,你经常需要知道地形的准确高度在某一点上。这将是这种情况,例如,当移动一个模型在地形上(参看4-17节),当找点和地形之间的碰撞(下一节),或者防止相机与地形想碰撞(参看2-6节)。
               在过去的章节中你确定了地形的每个顶点的3D位置,您已经知道确切的高度在这些点上。所有顶点之间的位置,但是, 您需要某种形式的插值准确地找到所需的高度,在这些位置上。
解决方案

                   如果这些点在你想知道高度与你地形的一个顶点发生碰撞,在这个点你知道地形的精确高度。如果这个点不能与一个顶点精确的碰撞,这个点是在你地形的一个三角形内。由于这三角形是平面线形的表面,你可以找到三角形的任何点的精确高度,用插值在定义三角形的三个顶点的高度之间。         
它的工作原理
               你开始一个X坐标和一个Z坐标,你想知道在你地形上一个点的相应的Y坐标。你找找到它是靠这个点所在的三角形的三个顶点的插值高度。
                 这意味着你首先必须找到其中的一点所在的三角形,这是不是小事,因为它起来。但首先我会向您介绍插值。
Linear Interpolation
                 某种插值是必须的,如果你能仅仅访问离散的数据点,但是你想知道这个值在这些点之间的。这种情况下被图5-17左边部分所介绍。

                 一些个别的X值,你知道精确的Y值。如X=2,你知道Y=10,如果X=3,Y=30。但是你不知道Y为多少时,X=27。

                 使用线形插值,你找到Y的值当X=27,用一条直线连接精确的点,如5-17图。线形插值总是表示你的X值在0到1之间。0表示你想知道精确的Y值所对应最低的X值,1对应最高的X值。在这个例子中,你想找到X=2.7相应的Y值,可能是0.7,意思是说"百分之70在2和3之间"
                 图5-12左边部分,百分之0对应的是一个Y值是0,百分100对应的Y是20,所以百分之70对应的是17。很容易明白,但是图象的右部分如何呢?十四给了一个相对的值0.33,由于它是百分之33在13和16之间。但是百分之33在35和46之间是多少呢?显然,你想知道代码去为你计算。
                 首先你想要一些代码去找到相对值在0和1之间。从你的X值,你首先减去最低的X值,这样你的最小的值变成了0。下一步,你不得不测量它,这样你的最大值变成了1。你可以做到这一点除以之间的差额最大和最小x值。哇。
                 这是图5-17左部分它做了些什么:

                 接下来,你刚好相反,以找到相应的Y值:你首先测量这个值(用乘以最大和最小的Y值的差异),你增加最低的Y值:

                 这里你运用一个规则到"容易"例子在图5-17的左边,但是你能用这个方法去做任何线形插值。作为一个不同的例子,让我们运用它到图5-17的右边。在这种情况下,你知道=13相应的Y=35和X=16相应的Y=46,但是你想知道Y对应的X=14。所以,首先你找到相对值在0和1之间:

                 一旦你知道相对值,你已经准备去找到相应的Y值:

                 最后,我们准备进行浮点计算。图5-17的右边部分,你可以找到X=14对应Y=38.67。在现实中 ,大多数插值将导致
一个浮点值,这种做法是对应这一认任务的。
提示:XNA提供功能去做这个插值为你,如果你想改写Vector2s,Vector3s,或者Vector4s。例如,如果你想知道哪个Vector2是百分之70在(5,8)和(2,9)之间,你可以使用Vector2.Lerp(new Vector2(5,8),new Vector2(2,9),0.7f)。
Bilinear Interpolation

                 在你地形的这种情况下,所有的(X,Z)值,你已经定义一个顶点为你知道的确定的Y值。为所有(X,Z)值在这些不连续的点,你不知道精确的Y值,所以你将会做某种插值。这时,你将会找到一个相对值在0和1之间,都为X和Z。
                 一旦你找到了这些值,你能计算出准确的Y值用这两步,如这节所示。
Finding the Relative Values
                 给任何的(X,Z)坐标,你需要去找到准备高度Y在你的地形上。你开始找到相对值为X和Z,利用前面的公式讨论。只有在这个时候,你必须去应用它两次,因为你已经工作在这三个方面了。

1 int xLower=(int)xCoord;
2 int xHeight=xLower+1;
3 float xRelative=(xCoord-xLower)/((float)xHeight-(float)xLower);
4 int zLower=(int)zCoord;
5 int zHeigher=zLower+1;
6 float zRelative=(zCoord-zLower)/((float)zHeight-(float)zLower);
                在你的地形,每一个整数X和Z的值,你已经定义了一个顶点,所以你知道确定的Y值在这些点。所以任何浮点的X值,你会发现最低的X值用计算它成一个整型(例子,2.7将成为2)。你找到了X高度值用增加1到这个值(2.7将会是3作为一个高X值)。了解最低和最高的范围,它很容易去找到相对值在0和1之间使用前面的公式。你得到同样的Z值。
Finding the minY and maxY Values
                现在你知道你的相对值在0和1之间,下一步是找到确定的Y值。虽然,你首先需要知道最小的Y和最大的Y值,正如你前面线形插值的例子。这些值是高度在顶点用高和低X和Z值来描述。你需要知道你的点在哪个三角形上,以便知道哪个顶点你需要用这高度作为Y值。
                你知道你的点P的X和Z坐标,所以你知道四个顶点围绕你的点的。它很容易找到它们的Y坐标:
1 float heightLxLz=heightData[xLower,zLower];
2 float heightLxHz=heightData[xLower,zHigher];
3 float heightHxLz=heightData[xHigher,zLower];
4 float heightHxHz=heightData[xHigher,zHigher];

                 这种符号,LxHz意思是"较低的X坐标,更高的Z坐标。"
Determining Which Triangle the (X,Z) Point Is In
                 你的四个顶点被用来绘制你的地形的两个三角形。虽然,这里有两种方法去定义它们,如图5-18所显示。这个方法这个三角形被绘制影响了点P的高度,如你所看见的图象。

                 虽然两个四方格的四个顶点有同样的坐标,你可以看见在四方格内几乎任何点的高度,不同于两种情况。在为一个例子,中间点是突出的,所以你可以很容易的看见它们的不同。
                 对于原因我们将会讨论,三角形的首选的围绕顺序是如图5-18右图所示。
                使用这个围绕顺序,它很容易决定哪个三角形点在它的上面。两个三角形的边框被对角线给予。在图象的右部分,这条线相对应点用X和Z坐标,如果xRelative+zRelative的总值是确定的1!
                例如,如果这点正是在四个点之间的,如图5-18所士,xRelative和zRelative都是0.5f,所以总数是1,意思是在对角线上。如果这个点定位有点左,xRelative变的很小,这个总数变的比1小。同样把持Z的坐标,所以如果总数比1小,(X,Z)坐标是在右下三角形的里面;否则,这个点是在右上三角形的里面:

1 bool pointAboveLowerTrianle=(xRelative+zRelative<1);

注意:利用这段时间去保证你自己的,所有的三角形定义在图5-16被绘制象图5-18右边显示那样。
Finding the Exact Height
                现在你知道相对值,高度周围的四个顶点,点所在的三角形,你已经最后准备计算确定的高度。
                如果这个点在你的三角形的左下,然后当pointAboveLowerTriangle是true,接下来是如何能找到任何位置的高度在这个三角形使用双线形插值:

1 finaHeight=heightLxLz;
2 finalHeight+=zRelative*(heightLxHz-heightLxLz); 
3 finalHeight+=xRelative*(heightHxLz-heightLxLz);

                前面说明的单独的插值,你开始于Y值的lowestX。因为这是"双"插值,你开始于Y的值的lowestXlowestZ
                在单一的插值,你增加最大Y和最小Y之间的高度差,乘以相对应的X值。在双线性插值,你这样做的为zRelative和xRelative的值。
                换句话说,你开始于左下顶点的高度。这一高度,你添加在这个顶点和一个高度Z坐标顶点之间的高度差,乘以非常近的真正的Z坐标是第二次的顶点。同样保存在最后一行:为了这个高度,你添加高度差在左下顶点和右下顶点之间,乘以非常近的真正X坐标作为右下的顶点。            
                如果这个在右上三角形里面,当pointAboveLowerTriangle为false时,事情有些不同,你需要这些代码:

1 finalHeight=heightHxHz;
2 finalHeight+=(1.0f-zDifference)*(heightHxLz-heightHxHz);
3 finalHeight+=(1.0f-xDifference)*(heightLxHz-heightHxHz);

                作为开始的高度,你得到右上角的顶点,你遵循同样的程序:你增加高度差异,乘以相对距离。
代码
                这个方法包含了所有的在前面解释过的代码。基于任何(X,Z)坐标,是否是整型还是浮点型,这方法返回确定的高度在这一点的上方。首先你检查这个点,是否要求在地形上。如果不是,返回一个默认的高度为10。

 1 public float GetExactHeightAt(float xCoord,float zCoord)
 2 {
 3     bool invalid=xCoord<0;
 4     invalid|=zCoord<0;
 5     invalid|=xCoord>heightData.GetLength(0)-1;
 6     invalid|=zCoord>heightData.GetLength(1)-1;
 7     if(invalid)
 8       return 10;
 9     int xLower=(int)xCoord;
10     int xHigher=xLower+1;
11     float xRelative=(xCoord-xLower)/((float)xHigher-(float)xLower);
12     int zLower=(int)zCoord;
13     int zHigher=zLower+1;
14     float zRelative=(zCoord-zLower)/((float)zHigher-(float)zLower);    
15     float heightLxLz=heightData[xLower,zLower];
16     float heightLxHz=heightData[xLower,zHigher];
17     float heightHxLz=heightData[xHigher,zLower];
18     float heightHxHz=heightData[xHigher,zHigher];
19     bool pointAboveLowerTriangle=(xRelative+zRelative<1);
20     float finalHeight;
21     if(pointAboveLowerTriangle)
22     {
23          finaHeight=heightLxLz;
24          finalHeight+=zRelative*(heightLxHz-heightLxLz); 
25          finalHeight+=xRelative*(heightHxLz-heightLxLz);
26     }
27     else
28     {
29          finalHeight=heightHxHz;
30          finalHeight+=(1.0f-zDifference)*(heightHxLz-heightHxHz);
31          finalHeight+=(1.0f-xDifference)*(heightLxHz-heightHxHz);
32     }
33     return finalHeight;
34 }

 

posted on 2009-08-06 15:51  一盘散沙  阅读(281)  评论(0编辑  收藏  举报

导航