U
章 04世界与游戏循环7 课 — 点击打开
04 / 07 · 10 分钟
世界与游戏循环

让场景保持流畅

到目前为止的项目

Assets/

Scenes/

Arena.unity

TerrainLOD Groups

Scripts/

PropScatter.cs

Prefabs/

module kit (6 pieces)

项目设置

GPU instancingocclusion bakelayerCullDistances

你已经有的这一课新增

当初竞技场只是灰色地板上摆十一个物体的时候,能跑到每秒几百帧。等周围种上几百棵树就不行了 —— 除非你把这节课里的四件事都做了。

一个只跑 12 FPS 的场景不算场景,是一张截图。从 12 到 60 之间的差距,四个技巧就能填上大部分。

动态图解

远处的物体改用更简单的 mesh。玩家永远看不见切换的那一下。

1. 先测量,再动手改

  1. 1

    打开 Window▸Analysis▸Profiler,看 CPU 和 Rendering 那两行。

  2. 2

    在 Game view 的 Stats 面板里看 Batches 和 Tris —— 要一边让 Knight 走动一边看,不要站着不动。

  3. 3

    CPU 时间高 → draw call 太多,或者脚本干了太多活。GPU 时间高 → 像素太多、重复绘制或 shader 太重。

2. LOD 组

  1. 1

    选中一个道具,Add Component → LOD Group。

  2. 2

    把高面数 mesh 拖进 LOD 0,中等面数的进 LOD 1,低面数的进 LOD 2。

  3. 3

    设置 Culled 那一档,让物体在它只剩几个像素高时彻底不画。

  4. 4

    树、建筑和石头受益最大。小石子不值得花这份配置的功夫。

3. 砍掉 draw call

  • Static Batching:所有不动的物体都勾上 Static。Unity 会在 build 时把它们合并成共享的 mesh。

  • GPU Instancing:重复几百次的东西,在它的 material 上勾上 Enable GPU Instancing。500 块一样的石头变成一个 draw call。

  • material 越少,batch 越少。同样的两个物体用同一个 material 就能合并,换成不同 material 就不行。

  • 把 texture 打包成图集:一张装着十二种道具的 2048,胜过十二张 512。

4. 遮挡剔除

  1. 1

    视锥剔除(不画屏幕外的东西)是自动的。遮挡剔除(不画墙后面的东西)就不是。

  2. 2

    把墙和建筑标记为 Occluder Static,然后 Window▸Rendering▸Occlusion Culling▸Bake。

  3. 3

    室内场景和密集城市值得做。在什么都能看见的空旷原野上做了也没用。

5. 缩短摄像机的可视距离

the cheapest optimisation in Unity
// Camera Far = 1000 by default. Most levels need 150.
Camera.main.farClipPlane = 150f;

// hide the ugly cut-off with fog
RenderSettings.fog = true;
RenderSettings.fogMode = FogMode.Linear;
RenderSettings.fogStartDistance = 90f;
RenderSettings.fogEndDistance = 145f;

按 layer 分别设剔除距离

C# 脚本
void Start()
{
    float[] distances = new float[32];      // one entry per layer
    for (int i = 0; i < 32; i++) distances[i] = 150f;

    distances[LayerMask.NameToLayer("SmallProps")] = 35f;   // pebbles vanish early
    distances[LayerMask.NameToLayer("Grass")] = 25f;

    Camera.main.layerCullDistances = distances;
}