您的当前位置:首页正文

生成随机地形

2024-10-18 来源:威能网
维普资讯 http://www.cqvip.com

…… G阻PHICS&强啊EPROG咖………………………………………………………………………………… 生成随机地形 申 晓 摘 要 本文介绍了如何动态生成简单的地形以及Perlin噪声的简单应用。 关键词Midpoint,中点位移 通常在游戏中,需要自带大量的地图数据,占用了不少空 间。在一些并不是很关键的地方,比如:远山、平原、丘陵等 地形,可以考虑用程序动态生成它们。这样不但节省了存储空 间,也相应提高了载入速度。 下面来看看如何生成地形的高度图,可以使用一种称为中 点位移(Midpoint Displacement)的方法。它的原理类似于分形 的思想:为简单起见,首先给四角的顶点赋予一个在【一128, 128】之间的随机值,然后由这四个顶点可以计算出正中间顶点 的高度:hCenter=(hA+hB+hC+hD)/4+delta,其中delta是 对当前结果进行适当调整,以尽量模仿真实的地貌状况。现在 可以通过这五个顶点来计算四条边上的中点,分别为hTop, hBottom,hLeft,hRight。连接这四个中点和正中间顶点hCen— ter,就可以把原来的大矩形分成四个新的小矩形。依此类推, 重复使用上述方法直到计算出所有顶点的高度为止。另外需要 注意的一点是上面提到的delta值,应该在每次迭代时,适当 缩小它的值,这样生成高度图的视觉效果才比较符合常理。如 下面的代码所示,ratio为【0,1】之间的比例系数: voidCMyD3DApplication::MakeHeightData(int}}Height Map,int left,int right,int top,int bottom,int delta.float ratio) { if(1::right—left)return; else { delta=max(delta,2): //上边中点 If(128==HeightMap【top】【(1eft+right)/2】) { HeightMap[top【(1eft+right)/2】:((HeightMap[top】【left】+ HeightMap[top¨right1)/2+l rand1)%delta-delta/2))/2; } //下边中点 if(128==HeightMap【bottom】【(1eft+right)/2】) { HeightMap【bottom】【(1eft+right)/2】:((HeightMap 【bottom】【left】+ HeightMap【bottom】【right】)/2+(rand()%delta— delta/2))/2;  ’- //左边中点 ! If(128==HeightMap【(top+botom)/2】【left】) { HeightMap【(top+bottom)/2】【left】=((HeightMap 【top】【left】+ HeightMap[bottom】【left】)/2+(rand()%delta—delta/ 2))/2; } /l/右边中点 |f(128==HeightMap【(top+bottom)/2】【right】) { HeightMap【(top+bottom)/2【right】=((HeightMap 【top】【right】+ HeightMap【bottom】【right】)/2+(rand()%delta— delta/2))/2; } //正中间点 If(128==HeightMap【(top+bottom)/2】 【(1eft+right)/2】) { HeightMap【(top+bottom)/2】【(1eft+right)/2】= ((HeightMap[top】【left】+ HeightMap[top】【right】+HeightMap【bottom】【left】+ HeightMap【bottom】【right】)/4+(rand()%delta— delta/2))/2; } MakeHeightData(HeightMap,left,(1eft+right)/2。top. (top+bottom)/2.(int)(delta}ratio),ratio): MakeHeightData(HeightMap,(1eft+right)/2.right.to p. (top 4-bottom)/2.(int)(delta II ratio),ratio): MakeHeightData(HeightMap.1eft,(1eft+right)/2. (top+bottom)/2.bottom,(int)(delta II ratio),ratio): MakeHeightData(HeightMap.(1eft+right)/2.right. (top+bottom)/2,bottom。(int)(delta}ratio),ratio): } } 开始时把地形中所有顶点高度都初始化为128,这样可以 避免过多的重复计算。当然还可以平滑一下四周的边界,使地 维普资讯 http://www.cqvip.com

…………………………………………………………_ 实用第一 智慧密集 形边缘看起来比较平缓。 现在的地形已经出显端倪,只是看起来比较陡峭,需要平 滑它,使用类似Perlin噪声的方法。它适用于生成各种维度的 纹理,可以模拟云彩、岩石、火焰等。这里只需考虑二维情况 即可。首先把整个地形平均分成几个部分,比如8 X 8的网 格,再为每个网格顶点分配一个随机的法线向量。对于地形中 的每个顶点,先找到包含它的网格单元,分别用这个顶点的位 置和网格四角的顶点做向量减法,就得到四个从四角指向该顶 点的方向向量。把这四个向量分别和对应四角的随机向量做点 乘,把结果带人下面的公式计算权值:W=6t 5—1St 4+ 10t 3,最后用这个值来调整每个顶点的高度值即可。另外为 了减少运算量,程序中创建了一张256个入口的向量查找表以 供随机分配使用。具体代码如下所示: voidCMyD3DApplication::MakePedinNoiseIintstep) 。 . ID3DXVECTOR2RandNormal[256l: 一 floatm=Q.魄 ~ intx=一、 。 inty=一1:  。0 stand(GetTickCount for(inti=0:i<256;-i--i-.) 、 //生铷琏 责包镝置 ’ floatxVal=randI}a%256一-1 28 0 RandNormal、n xe2*(xVal+128))'256"、; lfaotyVal=rand %256-128.Of; RandNormal[i].Y:2 (yVal+t28、 睫主 //向量归一化 m=(flaot)hypotIRandNormaI【l1.x,RandNormal[|1.y} ‘RandNormal【.1.x/=m 。 RandNormat[i、- 主 I  -、 //l ̄J分飘 宽霞蕊蒿霞 GridWidth=1+ /step;| 。_ 。  。—intGddHeight=1-i-m_TexHt ,¥哇啦薯l-_ --.j _ l[GddHeiD3D×ght・  EGTG OR2 G jt n勖 D3D C DR霪一|dth]; 。t 每0| 0l l 一 ≤_0一I   D3DXVECTOR2 *GridMap=newD3DXVECTOR2* [GddHeight] 。 _ :||誊 |《l i。 毒 for Y=Q <GridHeight;-i-|≮ ・ 薯 。 鼍 | _ | 一§llll l-c建| 薯 GddMap[y] &pGfidMaply*GridW' ̄th]; ’I_ _、 - i l 。; {-|| . 。.I srand(GetTickCount());3曩. | 鼍i 毫 誓_ 一薯j to!f = y<GridHeight; ̄++y),一—j j囊 囊毫 j  I。|。l| 。’ _|誊鼍3。尊|l for(x= X tGridWidth;-i-+x、 一 -: 。 ./, 每令鼹冁霞氮敬爱随吼 菠 重| GddMap yllxl=RandNormat[ 哟 警 娜 l ii,西i200酾7.1隔与t , /l/生成噪声 forly=0:Y<m_TexHeight;++y) ( int row=y/step; for(x=0:X<m_TexWidth;++x) ( intcol=x/step; POINTLeffTop={col}step.row}step}: POINTRightTop={(col+1)}step,row}step}: POINTLeftBottom={col}step,I row+1)}step}: POINTRightBottom={(col+1)}step,(row+1)・step}; 1/由当前点和四角点形成四个向量 一D3DXVECTOR2n1l1,Of・x—LeftTop.x,1.Of‘y— LeftTop.IY): D3DXVECTOR2n2(1.Of・X—RightTop.x.1.Of Y— RightT0p,y): D3DXVECTOR2n3I1.Of・X—LeftBottom.x,1.Of Y一 LeffBottom;y): D3DXVECTOR2n4(1.0 X—RightBottom。x,1.Of Y— 。RightBottom.y): / 归—一化四个向量 = m=(;float)hypot(n1.x,n1.y); if(o.Of==m} { n Y=0.0f: else {_ n T.x/=m: nl。y/=m: m=(float)hypot(n2.x,n2.Y 。if(O;ofj ; l n2ix=0.Of; n2 Y=0.Of; ) 。 f 。毫.n2 X1;m n2.y/=m: 一l_ .fI Itn3 ,x.n3ly): Q. ==辑、、 n3;x: . 、3 y=Q.Of; 叠 : i一一|甍 : lx,: n3;y;= 维普资讯 http://www.cqvip.com

B哪HICS&础嘲EPROG咖) ………………………………………………………………………………….! val=《val+1)/2: weight=6 powf《va1.5)一15 powf(va1.4)+ 10 powf《va1.3): floatt3=tl}weight+t2 《1-weight): m=《float)hypot《n4.x.n4.Y): if《O.Of==m) ( n4.x=0.Of; n4.Y=0.Of; //加权形成最终结果 t3=(t3+1)/2; m eightMap【Y】【x】=m HeightMap【Y】【x】} 0.8f+t3}0.2f; ) else ( n4.x/=m: n4.y/=m: ) ) delete【】pGridMap; delete【】GridMap; ) 一) //点乘作为四角点的高度噪声 floath1=GridMap【row】【col】.x}n1.x+ GridMap【row】【col】.Y n1.y: floath2=GridMap【row】【col+1】.x}n2.x+ GridMap【row】【col+1】.Y n2.v: floath3=GridMap【row+1】【col】.x}n3.x+ GridMap【row+1】【col】.Y n3.y: floath4=GridMap【row+1】【col+1】.x}n4.x+ GridMap【row+1】【col+1】.Y n4.y: 般为了获得比较真实效果,上面的过程要做多次,选择 不同粒度的网格大小,比如16 x16,32 x 32等。然后把每次 的值累加起来作为最终结果。 最后为了方便光照,还得给每个顶点设置一个法向量,可 以通过如下的简单方法进行计算:设顶点在垂直方向上的投影 为T<0,1,adjust (H【Y】【x+1】一H【yJ【x一1】)>,在水平方 //计算当前点的权值 floatval=powf《1.Of}(x<<13),1.Of}x): val=《1.Of一《《int)《val}(val}val}15731+ 789221)+1 37631 2589)&0x7FFFFFFF)/ 1073741824.Of): 向上的投影为S<1,0,adjust}(H【Y+11【x】一H【Y一1】 【x】)>,其中的aajust是用来调整向量幅度的,二维数组H【i】 …是每个顶点的高度值。然后做T x S,即可得到此顶点近似 的法向量<Tz/m,Sz/m,一1/m>, val=《val+1)/2; 其中m=sqrt(Tz Tz+sz sz+1)。代码很简单,可参考 附带的工程,就不再叙述了。所附例程是在VS NET2002+ Win XP下调试通过,需要安装DX9 SDK。 floatweight=6 powf《va1.5)一15 powf(va1. 4)+10 powf《val,3): floattl=hl}weight+h2}《1一weight): floatt2=h3}weight+h4}(1-weight): val=powf《1.Of}《Y<<13).1.Of Y): 参考文献 Perlin Noise val=(1.Of一《《int)《val}(val}val}15731+ 789221)+1376312589)&0x7FFFFFFF)/ 1073741824.Of): -(收稿日期:2006年12月15日) 七七七七七七  ̄r'-cr"-or"-or"- ̄r'-cr"-or"-or"-or"-or"-or"-or"-or"-or"-or"- ̄r'-cr"-or"-or"- ̄r'-cr"-or"-or"-or"-or"-or"- ̄r'-cr"- ̄r'-cr"-or"-or"- ̄r'-cr"-or"-or"-or" (上接第58页) forI:=OtoRealLen一1 dobegin pdst:=pDst+Char(nLeft)://额外得到一个目标解码字节 nByte:=O: //组内字节序号初始化 nLeft:=O: //残余数据初始化 end; p-:=StrTolnt( ¥ +《Copy(s.4}I+1.4)): Move《p-.sStr.2): Result:=Result+sStr; end; nSrc:=nSrc+2: end; //修改源串的指针和计数值 //返回目标串长度 Dispose(P): end; ‘ result:=pdst; end; 该程序在WinXP专业版+Delphi 7的环境下,使用数据 线连接Motorola V501手机,运行通过,当然,SPCOMM要作 为Component安装。 functiontFormSms.UniCodeToGB5(s:String):WideString; var P:PWOrd; I.RealLen:Integer; 参考文献 1.赵兰涛、苏彦华.Delphi串口通信技术与工程实践 2.大富翁论坛:<http://www.delphibbs.com/keylife/i— blog_show.asp?xid=18528> sStr:WideChar; begin New(P): RealLen:=Length(s)div4;//计算UNICODE真实长度 (收稿日期:2006年11月8日) 

因篇幅问题不能全部显示,请点此查看更多更全内容