3、地形系统基础:地形创建与编辑、地形纹理绘制、树木与草地系统

聊到游戏场景构建,地形系统绝对是绕不开的基石。我入行那会儿,还在用高度图手撸地形,效率低得让人抓狂。现在引擎里的地形工具已经非常成熟了,但核心原理其实没变。说白了,就是「怎么让一块平坦的网格,变成你想要的任何地貌」。

3.1 地形创建与编辑

创建地形,第一步就是确定分辨率。分辨率越高,细节越丰富,但性能开销也越大。我个人习惯,开放世界用 1025x1025 或 2049x2049,小场景 513x513 就够用了。为什么是这些奇数?因为地形网格的中心点需要精确对齐,奇数尺寸能保证对称性。

核心参数速查表

参数推荐值说明
地形尺寸1000m x 1000m太大容易穿帮,太小不够用
高度图分辨率1025 x 1025每像素对应约1米
分段数64 x 64控制LOD层级,分段越多性能越好

编辑地形时,我建议你多用「笔刷」模式。抬高、压低、平滑,这三个操作能搞定90%的地形需求。嗯,这里要注意:千万别用「平铺」工具做整体地形,那玩意儿是给屋顶用的。我曾经在项目里用平铺工具刷了整片山地,结果远处看像一块块豆腐,近处看全是锯齿,重做了三天。

避坑指南:
我曾经在编辑地形时,不小心把高度图分辨率设成了1024x1024,结果地形边缘出现了明显的接缝。后来才发现,引擎要求高度图尺寸必须是 2^n + 1。你想想看,差一个像素,整个地形就废了。所以创建地形前,先确认好分辨率格式。

3.2 地形纹理绘制

地形纹理绘制,说白了就是给地形「上色」。但这里的上色不是简单的贴图,而是通过多层纹理混合来实现自然过渡。比如草地、泥土、岩石、雪地,它们之间要有平滑的渐变,不能像拼图一样生硬。

我常用的方法是「四层纹理混合」。每层纹理对应一个通道(R、G、B、A),通过权重图控制每层的可见度。举个例子:

// 伪代码:地形纹理混合
float4 weights = tex2D(weightMap, uv);
float3 color = tex2D(layer0, uv) * weights.r
            + tex2D(layer1, uv) * weights.g
            + tex2D(layer2, uv) * weights.b
            + tex2D(layer3, uv) * weights.a;

为什么是四层?因为RGBA四个通道刚好够用。超过四层就需要额外的权重图,性能会下降。我在项目中遇到过,为了追求细节,硬塞了六层纹理,结果帧率直接掉了一半。后来老老实实回到四层,效果其实差不了多少。

小技巧:绘制纹理时,先用大笔刷铺底色,再用小笔刷加细节。比如先刷一层草地作为基底,然后在凹陷处刷泥土,在凸起处刷岩石。这样自然过渡,看起来才真实。

纹理绘制还有一个关键点:纹理平铺次数。草地纹理平铺4次就够了,岩石纹理平铺2次,因为岩石细节少。平铺太多会显得重复,太少又模糊。我一般会在材质里加一个随机偏移,让纹理看起来不那么「整齐」。

3.3 树木与草地系统

树木和草地,是让地形「活」起来的关键。但也是性能杀手。你想想看,一片森林如果每棵树都单独渲染,再好的显卡也扛不住。所以引擎用了「实例化渲染」技术——把相同类型的树木合并成一个批次,一次绘制。

我建议你这样做:

  • 树木:使用 SpeedTree 或引擎自带的树木工具。每棵树用 3-5 个 LOD 层级,远处用 billboard(公告板)替代。我曾经在项目里,把树木 LOD 设成了 2 级,结果远处看像纸片,近处看又太密。后来改成 4 级 LOD,效果好了很多。
  • 草地:用「草地渲染器」或「程序化生成」。草地不能一棵一棵种,而是通过密度图控制生长区域。比如山坡上草少,山谷里草多。密度图可以用灰度图,白色区域长满草,黑色区域不长。

注意:草地数量不是越多越好。我见过有人把草地密度调到 100%,结果场景里全是草,连路都看不见了。一般来说,草地覆盖面积控制在 30%-50% 比较合理。另外,草地的碰撞检测一定要关掉,否则玩家走上去会卡顿。

树木和草地的摆放,我推荐用「规则+随机」的方式。规则是指:树木不能长在路中间,草地不能长在岩石上。随机是指:位置、大小、旋转角度要有变化。完全随机会显得杂乱,完全规则又像人工林。我习惯先画几条路径,然后在路径两侧随机种树,这样既自然又有引导性。

最后提一句性能优化:
树木和草地的绘制距离要控制好。近处用高模,远处用低模,再远处直接消失。我一般把树木的绘制距离设为 200 米,草地设为 50 米。超出这个范围,玩家根本看不清,何必浪费性能呢?

好了,地形系统的基础就这些。下一章我们会聊到「光照与阴影」,那是让场景真正「好看」的关键。到时候见。