《魔兽世界》地形研究

6 篇文章 0 订阅
    《魔兽世界》地形的惊艳之处,主要在于无缝连接的世界和精细的渲染效果,借助 WoWmapview 源码及能以线框模式查看 D3D 程序的分析工具,可以对其实现略窥一二。

 

组织方式

         《魔兽世界》采用分块的地形,这是它实现无缝地图的基础。

         WoWmapview源码来看,整块地形对应一个MapWorld,这块地形可以是整块卡利姆多大陆,整块东部王国,如果你在战场中,它还可以仅是这块战场地图。每个MapWorld分为64x64MapTile。每块MapTile又进一步分为16x16MapChunk

         在任何时刻,程序总是保存着玩家所在的及其周围的3x3MapTile,随着玩家的移动,这些MapTile会被动态更新,新的MapTile被加载以替换被卸载的旧MapTile。为了提高调度效率,魔兽引入了Cache机制,Cache中保存着最多16MapTile数据。需要加载新的MapTile时,首先会在Cache中查找;卸载的旧MapTile也不会被立刻删除,而是保存在Cache中以备再次调用。由于一段时间内玩家的活动范围通常不会有太大变化,这一Cache策略在应用中表现的非常出色。这是无缝地图的基本原理。

         作为魔兽地形的基本渲染单元,每个MapChunk包含9x9+8x8个地形顶点,顶点布局如下图示。

Terrain_Vertices

         为了提高渲染效率,魔兽采用二级静态LOD。即渲染时刻,根据每个MapChunk和相机的距离,使用两种精度的顶点索引。这是魔兽线框模式下位于虚空风暴地图边缘时的截图。

WOW_Terrain_W

         参考截图,第一级顶点索引方式可能是这样的。

Terrain_Indices

         很难根据线框模式下的魔兽世界判断出其第二级顶点索引方式。游戏中,采用低视野设置,远处的MapChunk会被视锥剪裁掉;采用高视野设置,远处的MapChunk仍会采取一级顶点索引进行绘制。实际上,我从没在实际游戏中见过采用二级顶点索引绘制的地形块。你可以参考WoWmapview,或者采用自己的二级顶点索引方式。一般情况下,二级顶点索引的索引个数会比一级索引减少一半。

         魔兽世界的地形是支持挖洞的。深入地底的矿洞,矮人村落中带有地下室的堡垒,都要用到这个功能。每个MapChunk支持挖4x4个洞,挖洞信息用一个int类型保存在MapChunk中,低16位对应4x4个洞每一个是否打开,高16位对应洞的类型。下面是丹莫罗深入地面的矮人地堡截图,可以较清晰地看到与地堡相接部位地形上所挖的洞。

WOW_Terrain_Hole_W

         水体信息也是保存在MapChunk中的。对应MapChunk的顶点,每块水体的顶点分布及其索引如下图。

Terrain_Water_Indices

         每个MapChunk保存了覆盖其上的水体信息的一系列flag值,这些flag值包含了水体各个单元是否开启,水体颜色,水体类型等。下图是途径暮色小溪时的截图,紫色的水体展示了水体顶点分布及索引方式。

WOW_Terrain_Water_W

 

渲染技巧

         魔兽采用多层地形纹理混合的方式来渲染地形,这也是各游戏普遍采用的方式。一般情况下,魔兽使用4张地形贴图和一张混合贴图,混合贴图的RGB通道表示前3次混合的权重,A通道表示是否为阴影。地形贴图一般在MapChunk单方向上重复张贴8次;而通常尺寸为64x64的混合贴图,仅重复一次,即每一个MapChunk对应一张混合贴图。这张64x64的贴图,在混合地形时,为地形的混合精细度提供了足够的保障。

         尚不清楚出于何种考虑,魔兽中保存了反映当前WorldMap粗略高度的一个64x64的顶点列表,对应64x64MapTile。渲染之初,使用当前雾的颜色作为输出色,首先渲染这个列表。这样做可能的一个原因,是当游戏视野设置很低时,稍远处的地形会被剪裁掉,而这个顶点列表在雾的配合下,提供远处的地形填充,不至于出现地形截断的效果。

         接着,针对活动的3x3MapTile逐一进行绘制。在每个MapTile中,使用四叉树管理其下的MapChunk,每个MapChunk根据相机和自身的实际距离,选择采用如下渲染策略:

         1. 距离很远。采用二级顶点索引,使用NoDetail渲染策略。仅设置雾颜色为顶点色,不考虑纹理采样和光照处理。

         2. 距离适中。采用二级顶点索引,使用Detailed渲染策略。光照,纹理混合,阴影等均会处理。

         3. 距离较近。采用一级顶点索引,使用与情况2相同的Detailed渲染策略。

         最后是水体的渲染。魔兽WLK之前的水体,基本上是采用30张水面轮替形成水波荡漾状来实现的。而在资料片《大灾变》中,加入了实时渲染的水体效果。

         上述魔兽世界地形渲染的基本技巧,尚不能得到实际游戏中那种令人印象深刻的地形效果。影响地形渲染效果的诸多因素当中,光照其实占了很大部分比重,处理好光照模型,渲染出来的地形会有意想不到的效果。正如厨师的秘制配方一样,魔兽地形画龙点睛之处在于高光贴图。

         由于环境光和直射光只能为地形顶点提供无差别的基本明暗效果,反射光作为能根据顶点位置不同而不同的差异性光照,被引入到魔兽地形的光照模型中。而单纯引入反射光又会使得地形看起来像涂了一层釉一样,所以魔兽将地形纹理的Alpha通道,作为其对应的高光贴图,控制该点反射光的强度。值得一提的是,魔兽的水体渲染的光照处理,也采用了与此极为类似的方式。这样的简单技巧已经足够将魔兽的地形渲染提升到像素级光照的精度,实际上,它在魔兽细腻天成的地形效果中,扮演者关键性的作用。

 

Demo

         得空实现了一个初步Demo,作为上述研究的验证及总结。它支持无缝地图,并且使用了文中提到的所有渲染技巧。

         这是展示地形混合、挖洞、二级静态LOD的截图。美工略显拙劣,每个MapChunk都采用了同样的混合纹理和高度图,所以会看到相同外貌的地形块多次重复。

Terrain_General

         这是展示地形光照效果的截图,高光贴图的使用大大提高了地形的精细度,经常出入奥山战场的玩家,应该对这种岩石的冷峻反光效果深有感触。

Terrain_Lighting

         这是展示水体效果的截图,遍布艾泽拉斯世界的大小水体,基本上都带有这种波光粼粼的魔兽烙印。

Terrain_Water

         Demo源码暂不公布,将会在进一步改善后作为成熟方案运用到实际项目中。Demo中用到的技巧,在本文中皆有论述,原理也比较简单,大家可自行尝试。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述 魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 …. N ( N <= 20 )。红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市。司令部有生命元,用于制造武士。 两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。 双方的武士编号都是从1开始计算。红方制造出来的第 n 个武士,编号就是n。同样,蓝方制造出来的第 n 个武士,编号也是n。 武士在刚降生的时候有一个初始的生命值,生命值在战斗中会发生变化,如果生命值减少到0(生命值变为负数时应当做变为0处理),则武士死亡(消失)。 有的武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。 武士降生后就朝对方司令部走,在经过的城市如果遇到敌人(同一时刻每个城市最多只可能有1个蓝武士和一个红武士),就会发生战斗。每次战斗只有一方发起主动进攻一次。被攻击者生命值会减去进攻者的攻击力值和进攻者手中sword的攻击力值。被进攻者若没死,就会发起反击,被反击者的生命值要减去反击者攻击力值的一半(去尾取整)和反击者手中sword的攻击力值。反击可能致敌人于死地。 如果武士在战斗中杀死敌人(不论是主动进攻杀死还是反击杀死),则其司令部会立即向其发送8个生命元作为奖励,使其生命值增加8。当然前提是司令部得有8个生命元。如果司令部的生命元不足以奖励所有的武士,则优先奖励距离敌方司令部近的武士。 如果某武士在某城市的战斗中杀死了敌人,则该武士的司令部立即取得该城市中所有的生命元。注意,司令部总是先完成全部奖励工作,然后才开始从各个打了胜仗的城市回收生命元。对于因司令部生命元不足而领不到奖励的武士,司令部也不会在取得战利品生命元后为其补发奖励。 如果一次战斗的结果是双方都幸存(平局),则双方都不能拿走发生战斗的城市的生命元。 城市可以插旗子,一开始所有城市都没有旗子。在插红旗的城市,以及编号为奇数的无旗城市,由红武士主动发起进攻。在插蓝旗的城市,以及编号为偶数的无旗城市,由蓝武士主动发起进攻。 当某个城市有连续两场战斗都是同一方的武士杀死敌人(两场战斗之间如果有若干个战斗时刻并没有发生战斗,则这两场战斗仍然算是连续的;但如果中间有平局的战斗,就不算连续了) ,那么该城市就会插上胜方的旗帜,若原来插着败方的旗帜,则败方旗帜落下。旗帜一旦插上,就一直插着,直到被敌人更换。一个城市最多只能插一面旗帜,旗帜没被敌人更换前,也不会再次插同颜色的旗。 各种武器有其特点: sword武器的初始攻击力为拥有它的武士的攻击力的20%(去尾取整)。但是sword每经过一次战斗(不论是主动攻击还是反击),就会变钝,攻击力变为本次战斗前的80% (去尾取整)。sword攻击力变为0时,视为武士失去了sword。如果武士降生时得到了一个初始攻击力为0的sword,则视为武士没有sword. arrow有一个攻击力值R。如果下一步要走到的城市有敌人,那么拥有arrow的武士就会放箭攻击下一个城市的敌人(不能攻击对方司令部里的敌人)而不被还击。arrow使敌人的生命值减少R,若减至小于等于0,则敌人被杀死。arrow使用3次后即被耗尽,武士失去arrow。两个相邻的武士可能同时放箭把对方射死。 拥有bomb的武士,在战斗开始前如果判断自己将被杀死(不论主动攻击敌人,或者被敌人主动攻击都可能导致自己被杀死,而且假设武士可以知道敌人的攻击力和生命值),那么就会使用bomb和敌人同归于尽。武士不预测对方是否会使用bomb。 武士使用bomb和敌人同归于尽的情况下,不算是一场战斗,双方都不能拿走城市的生命元,也不影响城市的旗帜。 不同的武士有不同的特点。 dragon可以拥有一件武器。编号为n的dragon降生时即获得编号为 n%3 的武器。dragon还有“士气”这个属性,是个浮点数,其值为它降生后其司令部剩余生命元的数量除以造dragon所需的生命元数量。dragon 在一次在它主动进攻的战斗结束后,如果还没有战死,而且士气值大于0.8,就会欢呼。dragon每取得一次战斗的胜利(敌人被杀死),士气就会增加0.2,每经历一次未能获胜的战斗,士气值就会减少0.2。士气增减发生在欢呼之前。 ninjia可以拥有两件武器。编号为n的ninjia降生时即获得编号为 n%3 和 (n+1)%3的武器。ninja 挨打了也从不反击敌人。 iceman有一件武器。编号为n的iceman降生时即获得编号为 n%3 的武器。iceman 每前进两步,在第2步完成的时候,生命值

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值