• [翻译]XNA 3.0 Game Programming Recipes之thirtyone


    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 }
  • 相关阅读:
    原生js可爱糖果数字时间特效
    jQuery绑定事件的四种方式
    jQuery选择器总结
    正则表达式
    this对象
    网页瀑布流效果实现的几种方式
    关于DOM
    SparkSQL读写外部数据源--数据分区
    SparkSQL读写外部数据源-通过jdbc读写mysql数据库
    SparkSQL读写外部数据源-基本操作load和save
  • 原文地址:https://www.cnblogs.com/315358525/p/1540458.html
Copyright © 2020-2023  润新知