降低Draw Call
关于draw call(batches)知道几件事:
- draw call和相机的视角有关,运行时每帧的draw call都不一样;
- 想知道一个场景draw call能达到的最大值,一般是把相机放到高空,能看到场景的大多数物体;
- 同一个相机位,运行时和没运行的draw call不一样,没运行没有启用静态合批,会比运行时大!要看实际draw call要运行时把相机放到高空俯瞰场景的大多数物体!
降低draw call(unity里叫batches)的方法有:
- 模型减少材质;
- 多模型共用材质;
- 烘焙灯光;
- 关闭阴影和雾;
- 遮挡剔除;
- 使用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**:可能被遮挡的物体(如草丛、箱子)。
- 
#### 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<Renderer>();
}
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多次。然后就研究调整参数把这几个房子也剔除了。

烘焙的遮挡剔除数据存了什么
烘焙的遮挡剔除数据主要存储了场景中物体之间的可见性关系和空间划分信息,用于运行时快速判断哪些物体被遮挡而无需渲染。具体内容如下:
一、核心存储内容
场景空间划分
Unity将场景划分为多个单元(Cells),每个单元包含该区域内的静态物体几何信息。这些单元会合并以减少数据量,形成层级化的空间结构。
可见性关系数据
记录单元之间的遮挡关系(如A单元完全被B单元遮挡)。
存储摄像机视角下哪些单元或物体可见(通过烘焙时预计算的视线测试结果)。
物体层级信息
每个物体的包围盒(Bounds)和所属单元关联,用于快速查询是否在摄像机可见范围内。
二、数据生成与优化
烘焙过程:Unity通过模拟摄像机视角,对静态场景进行光线投射,生成遮挡关系数据。
动态调整:若场景物体被移动或开关状态变化(如门打开),需重新烘焙数据。
性能优化:合并相邻单元以减少数据量,但可能牺牲部分精度(如薄遮挡体效果不佳)。
三、实际应用限制
静态场景适用性
仅对标记为“Static”的物体生效,动态物体会被忽略。
精度问题
薄遮挡体(如铁丝网)可能导致剔除失效。
大网格物体(如整座山)若部分可见,整个网格仍会被渲染。
四、与其他剔除技术的区别
视锥剔除:仅剔除镜头外的物体,不处理遮挡关系。
GPU深度测试:在渲染阶段剔除片元,而遮挡剔除在提交Drawcall前完成。
URP项目动态合批设置的位置
Unity性能优化篇(三) SRP/URP动态合批开启与注意事项_unity 开启动态合批-优快云博客
偏好>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<Mesh>(); 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


输出路径不能有中文。
Draw Call和SetPass Call的区别deepseek回答
想象你是一个画家(CPU),要在一张巨大的画布(屏幕)上画一幅画(渲染一帧画面)。你的助手(GPU)负责实际的涂抹颜料(绘制像素)。
-
Draw Call (绘制调用):
- 它是什么: 就是你告诉助手:“现在,把这个特定的物体画上去!”
- 比喻: 你递给助手一张小纸条,纸条上写着:“画一个红色的苹果”。或者“画那棵绿色的树”。每一个纸条就是一个 Draw Call。
- 关键点:
- 它发出命令让 GPU 去绘制一个具体的物体(或物体的一部分)。
- 每次你让 GPU 画一个东西,通常就需要一个 Draw Call。
- Draw Call 的数量很大程度上决定了 CPU 给 GPU 下达命令的繁重程度。 CPU 准备和发送这些“纸条”本身是需要大量工作的。Draw Call 太多,CPU 就会很忙,可能拖慢游戏(CPU 瓶颈)。
-
SetPass Call (设置通道调用):
- 它是什么: 就是在你让助手画某个特定物体之前,你告诉助手:“准备好,现在我们要用这种特定的方式来画画了!” 这里的“方式”主要是指使用的材质/着色器以及它所需的所有状态设置(颜色、纹理、混合模式、透明度规则等等)。
- 比喻: 在递给助手“画一个红色的苹果”纸条之前,你大声宣布:“注意!我们现在要用‘油画颜料 + 厚涂法 + 调色板A’的方式来画了!” 这个宣布就是一个 SetPass Call。
- 关键点:
- 它切换/设置渲染状态,为接下来的 Draw Call(s) 做准备。
- 它主要是关于改变 GPU 的“画画规则”(着色器程序、纹理、混合选项等)。
- SetPass Call 的数量很大程度上决定了 GPU 在绘制过程中切换状态的频繁程度。 每次切换状态(更换画笔、颜料、画法等)都会让 GPU 暂停一下当前工作,去准备新的规则,这会产生开销(GPU 状态切换开销)。SetPass Call 太多,GPU 就可能因为频繁切换状态而变慢(GPU 瓶颈的一种可能)。
总结区别:
| 特点 | Draw Call (绘制调用) | SetPass Call (设置通道调用) |
|---|---|---|
| 核心目的 | 命令 GPU 画一个具体的物体 | 命令 GPU 为绘制接下来的物体准备好一套新的‘画画规则’(主要是材质/着色器状态) |
| 类比 | “画这个苹果!” (下达绘制指令) | “现在换用油画颜料和厚涂法!” (切换绘画工具和技法) |
| 开销来源 | CPU 准备和发送命令的开销 (CPU 瓶颈) | GPU 切换渲染状态的开销 (GPU 状态切换瓶颈) |
| 数量关系 | 通常需要很多个(每个物体/材质实例都可能一个) | 通常比 Draw Call 少(同材质物体可批量绘制,只需切换一次状态) |
| 优化重点 | 减少次数 (CPU 性能优化关键) | 减少次数 (优化 GPU 效率,尤其是在材质复杂或切换频繁时) |
简单记忆:
- SetPass Call: “准备怎么画!” (设置材质/着色器状态)
- Draw Call: “开始画这个!” (执行绘制命令)
为什么重要?
在游戏或图形应用中,每帧都要渲染成千上万的物体。如果 Draw Call 太多,CPU 会不堪重负(CPU Bound)。如果 SetPass Call 太多(即使 Draw Call 减少了),GPU 也可能因为不停切换“画画规则”而效率低下(GPU Bound)。优化游戏性能时,开发者会想尽办法批处理物体(减少 Draw Call),以及尽量让使用相同材质的物体一起绘制(减少 SetPass Call)。
Unity 的 Stats 窗口里会同时显示这两项,就是让你监控它们是否成为性能瓶颈。
我的理解,类比到画图,SetPass Call是选工具、颜色、粗细,Draw Call是绘画本身。一次SetPass Call可能可以多次Draw Call,但是不可能一次Draw Call使用多次SetPass Call。
图片压缩格式
ASTC
ASTC(自适应可扩展纹理压缩)是一种高效的图像压缩技术,主要用于游戏和3D应用中的纹理处理。它的核心特点可以总结为以下几点:
1. 灵活压缩,省空间
支持从4x4到12x12像素的可变块大小,能根据图像内容自动选择最优压缩方式。
压缩率极高,比如一张1024x1024的图片用4x4块压缩后仅需1MB,比未压缩的RGBA格式小很多。
2. 画质好,细节保留多
相比传统压缩格式(如ETC2),ASTC在相同体积下能保留更多细节,比如文字边缘、渐变过渡更清晰。
支持HDR(高动态范围)和透明通道(Alpha),适合复杂场景。
3. 兼容性强
适用于iOS(A8芯片以上)、安卓(主流GPU)和现代游戏引擎(如Unity、Unreal)。
对非2的幂次方(NPOT)尺寸的图片也能完美支持。
4. 实际应用
游戏开发中常用它减少安装包体积,比如某应用通过ASTC压缩+其他优化,包体瘦身40%。
在移动端,ASTC能平衡画质和性能,避免因纹理过大导致卡顿。
简单说:ASTC就像给图片“智能瘦身”,既让文件变小,又尽量不损失画质,是游戏和3D应用的首选压缩技术。
425

被折叠的 条评论
为什么被折叠?



