> 技术文档 > Unity性能优化笔记_batches怎么降

Unity性能优化笔记_batches怎么降


降低Draw Call

关于draw call(batches)知道几件事:

  1. draw call和相机的视角有关,运行时每帧的draw call都不一样;
  2. 想知道一个场景draw call能达到的最大值,一般是把相机放到高空,能看到场景的大多数物体
  3. 同一个相机位,运行时和没运行的draw call不一样,没运行没有启用静态合批,会比运行时大!要看实际draw call要运行时把相机放到高空俯瞰场景的大多数物体!

降低draw call(unity里叫batches)的方法有:

  1. 模型减少材质;
  2. 多模型共用材质;
  3. 烘焙灯光;
  4. 关闭阴影和雾;
  5. 遮挡剔除;
  6. 使用LOD;

模型减少材质

>

见blender烘焙贴图的文章。 

遮挡剔除

在测试中遇到了1400次draw call的情况。把运行暂停,把场景里的对象分组失活,发现:

失活城镇3:1402>1119。失活城镇1:1397>953。此处城镇1是相机视野内的但是离得很远已经被地形完全挡住的城镇,但是造成了400多次Draw Call

直接问deepseek:

在 Unity 中,要让被地形遮挡的物体不调用 Draw Call,需要通过 **遮挡剔除(Occlusion Culling)** 技术实现。以下是完整的实现步骤和优化方法:

---

### **一、核心原理**
- **遮挡剔除(Occlusion Culling)**:通过预计算或运行时检测,跳过对相机视野中**被其他物体完全遮挡的物体**的渲染,从而减少 Draw Call 和 GPU 负载。
- **地形作为遮挡体**:将地形标记为遮挡物(Occluder),其他物体标记为被遮挡物(Occludee),Unity 会自动处理遮挡关系。

---

### **二、实现步骤**

#### 1. **启用遮挡剔除**
   - 打开 **Window > Rendering > Occlusion Culling**。
   - 在 **Bake** 选项卡中,确保 **Occlusion Culling** 功能已启用。

#### 2. **标记静态物体**
   - 选中地形和需要参与遮挡的静态物体(如岩石、建筑等),在 Inspector 右上角勾选:
     - **Occluder Static**:地形等遮挡其他物体的对象。
     - **Occludee Static**:可能被遮挡的物体(如草丛、箱子)。
     - ![Static Flags](https://docs.unity3d.com/uploads/Main/OcclusionCullingStaticFlags.png)

#### 3. **烘焙遮挡数据**
   - 在 **Occlusion Culling** 窗口的 **Bake** 选项卡中调整参数:
     - **Smallest Occluder**:设置地形细节级别(例如 `10`,单位:米,值越小精度越高)。
     - **Smallest Hole**:遮挡孔洞的最小尺寸(通常保持默认 `0.25`)。
   - 点击 **Bake** 生成遮挡数据,完成后会在场景中生成 **Occlusion Culling Data** 文件。

#### 4. **验证效果**
   - 在 Scene 视图顶部下拉菜单中选择 **Occlusion Culling** > **Visualization**。
   - 移动相机,被地形遮挡的物体会显示为**红色(未渲染)**,可见物体为**绿色(已渲染)**。

---

### **三、动态物体的处理**
若需要被遮挡的物体是动态的(如移动的敌人),需结合以下方法:

#### 1. **脚本检测遮挡**
   ```csharp
   using UnityEngine;

   public class DynamicOcclusion : MonoBehaviour {
       private Renderer rend;
       void Start() {
           rend = GetComponent();
       }

       void Update() {
           // 检测物体是否被地形遮挡
           if (Camera.main != null) {
               Vector3 viewportPos = Camera.main.WorldToViewportPoint(transform.position);
               bool isVisible = GeometryUtility.TestPlanesAABB(
                   GeometryUtility.CalculateFrustumPlanes(Camera.main),
                   rend.bounds
               );

               rend.enabled = isVisible; // 根据可见性开关渲染器
           }
       }
   }
   ```
   - 将此脚本附加到动态物体上,根据可见性动态启用/禁用渲染。

#### 2. **LOD(细节层次)配合**
   - 对中远距离物体使用低模(LOD1/LOD2),减少被遮挡时的计算开销。

---

### **四、注意事项**
1. **遮挡烘焙参数优化**
   - **Smallest Occluder** 值过大可能导致小物体无法遮挡其他物体,建议根据场景比例调整。
   - 复杂场景可分层烘焙:先烘焙地形,再烘焙建筑等大型物体。

2. **性能权衡**
   - 遮挡剔除的预计算需要时间,适合静态场景。
   - 动态遮挡(如上述脚本)会增加 CPU 开销,需测试平衡。

3. **地形设置**
   - 确保地形的碰撞体(Collider)完整,否则可能无法正确遮挡。

---

### **五、常见问题**
#### Q1:烘焙后遮挡无效?
   - 检查物体是否标记为 **Occludee Static**。
   - 调整 **Smallest Occluder** 值,确保小于遮挡物的尺寸。

#### Q2:如何减少遮挡数据体积?
   - 增大 **Smallest Occluder** 和 **Smallest Hole** 的值。
   - 移除不必要的静态物体标记。

---

### **六、替代方案**
- **视锥体剔除(Frustum Culling)**:Unity 默认启用,仅渲染相机视锥体内的物体。
- **硬件遮挡查询(Hardware Occlusion Query)**:适合高端设备,但需手动实现。

通过合理配置遮挡剔除,可显著减少地形遮挡区域的 Draw Call,尤其适用于开放世界或复杂室内场景! 🌟

照做之后在遮挡剔除Visualization看效果。远方有一些房子被剔除了,还有一些应该剔除的没剔除。这时候再运行,看向远方的小镇,batches最多只有700多次了,失活远方小镇batches还会降到500多次。然后就研究调整参数把这几个房子也剔除了。

URP项目动态合批设置的位置

Unity性能优化篇(三) SRP/URP动态合批开启与注意事项_unity 开启动态合批-CSDN博客

偏好>Core Render Pipeline>All Visible>项目设置>Graphics>Scriptable Render Pipeline Settings>Rendering

开放地图的性能优化

已经知道玩家视野里远方的物体会增加巨量不必要的draw call,遮挡剔除第一可能剃不干净,第二如果玩家在视野开阔的地方,远方的物体没有被遮挡,遮挡剔除也没有用,此时只能用LOD。

所以,如果场景物体没有LOD或者没有自动隐藏的程序,不要做开放地图。

模型生成LOD低模的方法

问了deepseek:

LOD Group,Generate LODs?

1. 使用Unity内置的LOD Group组件(自动简化) **适用场景**:快速生成中等质量的LOD **步骤**: a. 选择房子模型,添加到场景 b. 添加`LOD Group`组件 c. 在LOD Group中设置不同层级的距离 d. 使用Unity的自动生成功能: - 点击`LOD0`,然后点击\"Generate LODs\" - 设置简化百分比(如LOD1:50%, LOD2:20%) - Unity会自动生成简化网格 **优点**:快速、无需外部工具 **缺点**:简化算法较简单,可能出现破面

没找到它说的Generate LODs。我又问我的unity LOD Group没有Generate LODs,它说在 Unity 中,LOD Group 组件确实没有内置的 \"Generate LODs\" 按钮,但您可以通过多种专业方法高效创建 LOD 模型。

使用Blender的Decimate修改器

**专业级高质量简化** **步骤**: a. 导入房子模型到Blender b. 选择模型,进入编辑模式,确保所有部分正确合并 c. 添加`Decimate`修改器 d. 设置简化方式: - `Collapse`:通用简化(推荐) - `Planar`:保留平面特征 - `Un-Subdivide`:适用于高细分模型 e. 调整Ratio(0-1)控制简化程度 f. 应用修改器并导出 **高级技巧**: - 使用`Weighted Normal`修改器保持法线平滑 - 分部件简化:对复杂结构(如屋顶、窗户)单独简化

Decimate中文叫精简,这个方法可以。但是编辑模式看不到效果,需要到物体模式。

UnityMeshSimplifier?

```csharp using UnityEngine; using System.Collections.Generic; public class LODGenerator : MonoBehaviour { public Mesh originalMesh; public float[] lodPercentages = { 0.7f, 0.3f, 0.1f }; void Start() { GenerateLODs(); } void GenerateLODs() { var lods = new List(); foreach (float percent in lodPercentages) { Mesh simplified = SimplifyMesh(originalMesh, percent); lods.Add(simplified); } // 创建LOD Group并设置 } Mesh SimplifyMesh(Mesh mesh, float ratio) { // 实际项目中应使用简化算法(如Quadric Mesh Simplification) // 这里使用Unity内置简化(需要Unity 2019.3+) var simplifier = new UnityMeshSimplifier.MeshSimplifier(); simplifier.Initialize(mesh); simplifier.SimplifyMesh(ratio); return simplifier.ToMesh(); } } ``` **注意**:需安装`Unity Mesh Simplifier`包(Package Manager)

AMAZ3D LOD lite

输出路径不能有中文。