
1. 项目概述从“乱勾Static”到精准优化在Unity项目性能优化的工具箱里Occlusion Culling遮挡剔除绝对是一把利器但也是一把容易用错的“双刃剑”。很多开发者尤其是刚接触大型场景优化的朋友看到Static下拉菜单里的“Occluder Static”和“Ocludee Static”两个选项常常会陷入困惑“这俩到底啥区别是不是全勾上就完事了” 于是一个常见的“性能优化”操作就变成了选中场景里所有静态物体然后无脑勾上这两个复选框。结果呢烘焙时间长得离谱运行时剔除效果诡异甚至可能因为错误的设置导致性能不升反降。这篇文章我们就来彻底掰扯清楚Occluder和Occludee这两个核心概念让你告别“乱勾Static”的懵懂阶段真正理解并驾驭遮挡剔除为你的游戏或应用带来实实在在的帧率提升。简单来说Occlusion Culling解决的核心问题是摄像机看不到的物体就不应该送去渲染。这听起来理所当然但Unity的默认渲染流程视锥体剔除只负责剔除摄像机视锥体之外的物体对于视锥体内但被前面物体比如一堵厚墙完全挡住的物体它无能为力。遮挡剔除就是用来解决这个问题的。而Occluder和Occludee正是定义“谁挡谁”、“谁能被挡”的关键角色。理解它们是配置高效遮挡剔除方案的第一步也是避免踩坑、让烘焙数据真正发挥作用的前提。无论你是正在为开放世界地图卡顿发愁还是想优化室内复杂场景的渲染搞懂这两个标签都能让你的优化工作事半功倍。2. 核心概念拆解Occluder与Occludee的本质区别要正确使用必须先理解定义。很多文档的解释过于学术化我们用人话和实际场景来重新梳理一遍。2.1 Occluder场景中的“挡板”你可以把Occluder遮挡物想象成舞台上的实心背景板或者厚重的幕布。它的核心职责是阻挡视线让后面的东西“消失”在摄像机的视野里。核心特性它是一个“主动”的角色。在Unity进行遮挡计算无论是实时计算还是预烘焙时系统会检查这些Occluder物体的几何形状通常是其包围盒或简化后的网格并将其视为不透明的、坚实的障碍物。如果一个物体被标记为OccluderUnity就会用它来判断它后面相对于摄像机的物体是否被完全挡住。生活化例子一栋大楼、一座山、一面厚厚的承重墙、一个巨大的集装箱。这些都是典型的Occluder。摄像机在这边它们能完全挡住后面的小房子、树木或NPC。技术细节在烘焙Occlusion Culling数据时Occluder的网格会被用于生成场景的“遮挡体”信息。这个信息决定了从不同视角看哪些空间区域是被填满遮挡的。2.2 Occludee场景中的“演员”而Occludee被遮挡物则是舞台上的演员、道具。它的核心特性是它可以被前面的“挡板”挡住但它自己通常不或无法去挡住别人。核心特性它是一个“被动”的角色。标记为Occludee意味着这个物体有资格被其他Occluder物体遮挡。如果它完全位于某个Occluder后面Unity的遮挡系统就会在运行时将它从渲染队列中剔除节省宝贵的GPU资源。生活化例子放在房间里的桌子、椅子、散落在地上的武器、一个NPC角色、一棵树。它们自己可能很薄如一张纸或者有缝隙如栅栏不足以可靠地遮挡后方物体但它们完全可能被一堵墙整个挡住。技术细节只有被标记为Occludee的物体才会被纳入遮挡剔除的“可剔除对象”列表。如果一个物体连Occludee都没勾选那么无论它前面有多少OccluderUnity都不会尝试去遮挡它它永远会被渲染只要在视锥体内。2.3 关键误区澄清为什么可以“既是又是”这是最让人困惑的点。从字面意思看一个物体怎么能同时是“挡板”又是“演员”呢这岂不是矛盾一点也不矛盾这恰恰是大多数静态物体的正确状态。我们回到舞台的比喻一个高大的书架Occluder它能挡住后面书桌上的台灯Occludee。但同时这个书架本身也可能被它前面更厚的一堵墙另一个Occluder完全挡住。此时对于墙来说书架就成了“被遮挡物”Occludee。所以一个物体的“身份”是相对的、取决于观察视角的对于它后面的小物体而言它是Occluder。对于它前面的更大物体而言它是Occludee。因此对于一个典型的、实心的、不透明的静态物体比如场景中的建筑、岩石最合理的设置就是同时勾选“Occluder Static”和“Occludee Static”。这意味着“我既可以挡住别人也可以被别人挡住请把我纳入遮挡计算的双方考量中。”那么什么情况下应该只勾选一种呢仅Occluder不勾选Occludee这种物体巨大无比在游戏的所有可能视角下都不可能被其他任何物体完全挡住。例如作为远景一直存在的、贴在天球上的天空盒网格或者一个包裹整个游戏世界的、巨大的不可见碰撞体如果用它做遮挡。标记它为仅Occluder可以告诉Unity“只用我来挡别人不用费心计算有没有东西能挡我因为不可能有。” 这能轻微优化烘焙和运行时计算。但这种情况非常少见需要谨慎判断。仅Occludee不勾选Occluder这种物体本身不适合作为可靠的遮挡物。主要有三类透明或镂空物体比如铁丝网、栅栏、窗户除非是脏玻璃这种半透遮挡物。它们无法完全阻挡视线如果被当作Occluder会导致它们后面的物体被错误地剔除造成渲染错误本该看到的物体消失了。非常薄或面积很小的物体比如一张纸、一片树叶、一根电线。它们的遮挡能力极不稳定从稍微侧一点的角度看就可能失效依赖它们做遮挡会导致剔除结果闪烁物体时隐时现弊大于利。动态物体虽然动态物体一般不标记Static但这里提一下原理。一个移动的NPC如果你把它当Occluder那么它一走动背后的剔除数据就全乱了会导致严重的渲染错误。所以动态物体通常通过其他方式如动态遮挡剔除插件处理绝不标记为Static Occluder。注意Unity的官方文档和社区回答中确实存在一些历史版本表述不清的问题导致了“Occluder和Occludee互斥”的误解。现在的共识和实践已经非常明确对于绝大多数实心静态物体双勾选是最佳实践。3. 静态标记Static Flags的深度解析与配置策略理解了概念我们再来看看操作界面——Inspector窗口顶部的Static复选框。点击下拉箭头你会看到一列选项“Occluder Static”和“Occludee Static”就在其中。这个Static系统是Unity管理优化功能的核心。3.1 Static标记的真正含义给一个物体打上Static标记并不仅仅是“让它不动”那么简单。它的深层含义是向Unity引擎承诺这个物体在运行时Runtime的变换位置、旋转、缩放永远不会改变。这是一个非常重要的契约。基于这个契约Unity就可以在编辑期Editor time或构建时Build time放心地针对这个物体进行一系列预计算将运行时的计算开销转移到编辑期从而提升游戏性能。Occlusion Culling数据烘焙就是其中最典型的预计算之一。其他还有Lightmapping光照烘焙、Navigation Static导航网格生成、Batching Static静态合批等。所以第一个大坑就是如果你给一个之后会移动、旋转或缩放的物体标记了Static然后又去动态修改它的Transform不仅相关的优化会失效比如光照错乱还可能引发难以排查的渲染或物理问题。3.2 如何正确配置场景物体的Static属性面对一个复杂的场景我们不应该全选然后无脑勾选。一个科学的配置流程能节省大量烘焙时间并得到更准确的剔除结果。1. 分类筛选物体大型、实心、不透明建筑/地形选中这些物体勾选Occluder Static和Occludee Static。通常它们也同时是Lightmap Static接受光照烘焙和Navigation Static参与导航网格计算。中型静态道具如箱子、雕像、大型家具同样双勾选Occluder Static和Occludee Static。它们既能挡住更小的物品也可能被墙壁挡住。小型静态道具如杯子、书本、武器通常也双勾选。但如果你有成千上万个这样的小物体需要考虑它们作为Occluder的价值。有时为了简化遮挡数据可以只勾选Occludee Static不让它们参与遮挡计算以提升烘焙速度。透明/镂空物体栅栏、玻璃窗、链条只勾选Occludee Static绝不勾选Occluder Static。确保它们能被墙挡住但不会错误地挡住后面的东西。纯装饰性面片公告板树木、贴花通常只勾选Occludee Static。它们很薄不适合做遮挡物。永远在视野最前层的物体UI Canvas、始终在摄像机近裁剪面附近的特效不要勾选任何Occlusion Static。因为它们不可能被遮挡参与计算纯属浪费。动态物体NPC、可移动机关、玩家角色保持所有Static复选框未勾选。它们的遮挡需要通过其他技术如动态遮挡剔除、层次Z缓冲等处理。2. 利用图层Layer进行批量管理这是专业工作流的关键。不要手动一个一个点选物体。在Tags Layers中创建专用的图层例如Static_OccluderAndOccludeeStatic_OccludeeOnlyDynamic。将对应类别的物体分配到这些图层。然后你可以使用Unity的搜索过滤功能或者编写简单的编辑器脚本批量修改同一图层下所有物体的Static属性。这能极大提升场景配置效率并保持一致性。3. 烘焙前的检查清单✅ 确认所有标记为Static的物体在运行时真的不会动。✅ 确认透明/镂空物体没有错误标记为Occluder。✅ 确认动态物体没有标记任何Static。✅ 使用场景视图的“Occlusion Culling”可视化模式预览遮挡效果是否合理。4. Occlusion Culling工作流与烘焙参数详解配置好Static标签只是第一步接下来需要通过Window Rendering Occlusion Culling打开面板进行烘焙。这个面板里的参数决定了烘焙数据的质量和大小。4.1 烘焙流程步骤对象过滤Object Filtering在Occlusion窗口的Object标签页确认场景中参与烘焙的物体范围。通常保持默认即可它会自动包含所有标记了Occluder Static或Occludee Static的物体。烘焙设置Bake Settings这是核心环节切换到Bake标签页。Smallest Occluder最重要的参数之一。它定义了能被当作有效遮挡物的最小物体尺寸世界单位。比如设置为1那么任何尺寸小于1x1x1的物体即使标记了Occluder Static在烘焙时也会被忽略其遮挡作用。这能有效防止大量小物件如石子、小草产生巨量无用的遮挡数据极大减少数据量和烘焙时间。设置原则比你这个尺寸小的物体你认为它不足以可靠地遮挡住后面的物体。Smallest Hole定义遮挡物中可以被“看穿”的最大孔洞尺寸。如果一个洞的直径小于这个值遮挡系统会认为这个洞不存在依然会剔除洞后面的物体。对于有窗户的建筑需要将此值设置为小于窗户的尺寸否则窗户后面整个房间都会被错误剔除。通常需要根据场景中典型孔洞如门、窗的大小来调整。Backface Threshold背面剔除阈值。当摄像机看到一个物体的背面通常不可见超过这个百分比时该物体将不会被当作遮挡物。对于封闭的室内场景墙的内侧是背面这个设置可以防止室内墙体被当作遮挡物避免错误剔除。通常保持默认值100即可意味着只有完全看到背面时才不作为遮挡物。执行烘焙Bake点击Bake按钮。这个过程可能会很耗时取决于场景复杂度、Smallest Occluder的设置和烘焙分辨率。烘焙完成后会在场景文件同级目录生成一个OcclusionCullingData文件。可视化与调试Visualization烘焙后在Scene视图左上方的下拉菜单中选择Occlusion Culling。然后在Visibility面板中你可以用鼠标拖动预览摄像机实时看到哪些物体被剔除了显示为红色线框或完全消失。这是验证烘焙结果是否正确的最直接方法。4.2 参数设置经验谈Smallest Occluder从场景中典型小型遮挡物如路灯柱、稍大的石头的尺寸开始尝试。可以先设一个稍大的值如2.0烘焙快但可能粗糙。如果发现有些该被挡住的物体没被挡住再逐步调小这个值。在复杂场景中从1.0到0.5的调整可能会让烘焙时间成倍增加需权衡利弊。烘焙分辨率在Bake标签页的Settings折叠栏下。更高的分辨率如Width/Height设为1024或更高会产生更精确的遮挡数据但数据量更大加载可能稍慢。对于大型开放世界可能需要使用较低的分辨率如512来平衡精度和内存。对于小型室内场景可以使用高分辨率如1024来获得像素级精确的剔除。“保守”与“激进”Smallest Occluder调大、Smallest Hole调小属于“保守”策略烘焙快、数据小但可能漏掉一些遮挡机会该剔除的没剔除。反过来则是“激进”策略剔除更积极但烘焙慢、数据大且容易发生过度剔除不该剔除的剔除了。通常从“保守”开始逐步向“激进”调整直到在视觉正确性和性能提升之间找到最佳平衡点。5. 实战案例室内场景与开放世界配置对比理论说再多不如看实际案例。我们分别看一个室内FPS场景和一个开放世界RPG场景该如何配置。5.1 案例一室内FPS场景如反恐精英地图场景特点空间分割明确多个房间、走廊遮挡物多为厚实的墙壁和门视线转折多剔除潜力巨大。配置策略Static标记所有墙体、地板、天花板、大型固定家具书架、柜子勾选Occluder Static和Occludee Static。它们是完美的遮挡物。窗户玻璃只勾选Occludee Static。确保玻璃能被墙挡住比如从隔壁房间看但它本身不能挡住房间内的物体。铁丝网、栅栏门只勾选Occludee Static。小型道具弹药箱、油桶双勾选。它们在走廊里也能形成有效遮挡。玩家、可移动道具、门动画不勾选任何Static。烘焙参数Smallest Occluder: 0.5。室内道具尺寸相对统一且较小需要较精细的遮挡。Smallest Hole: 0.8。略小于标准门宽假设1.0确保角色透过门缝能看到隔壁时不会因为遮挡剔除而让整个隔壁房间消失。Backface Threshold: 100。室内墙体背面明确保持默认。预期效果当玩家在一个房间内时厚实的墙壁会将隔壁所有房间的渲染负载完全剔除帧率得到显著提升。透过门缝或窗户能看到隔壁房间的内容符合预期。5.2 案例二开放世界RPG场景如野外森林与城镇场景特点视野开阔遮挡物多为山脉、大型建筑群但也有大量树木、岩石等中型遮挡物。视线遮挡不如室内那么彻底。配置策略Static标记远山、大型山脉、巨型岩石勾选Occluder Static和Occludee Static。它们是世界级遮挡物。城镇建筑、城堡双勾选。建筑群之间互相遮挡效果明显。树木需要谨慎处理。对于树干粗壮、树冠茂密的树可以双勾选。对于树叶稀疏、树干很细的树建议只勾选Occludee Static避免因其形状复杂和不规则导致剔除错误和烘焙数据膨胀。小型岩石、灌木丛通常只勾选Occludee Static。它们数量极多作为Occluder价值有限且会大幅增加计算量。让它们被大山或建筑遮挡即可。地面地形通常作为Occludee Static参与但它作为Occluder的意义不大除非是深谷悬崖。有时为了简化地形可以不参与Occlusion烘焙依靠视锥体剔除和LOD。NPC、野生动物、可采集物不勾选Static。烘焙参数Smallest Occluder: 2.0 - 5.0。开放世界尺度大忽略小物体的遮挡作用聚焦于山脉、建筑等大型遮挡物能极大加速烘焙和减少数据量。Smallest Hole: 2.0。对应建筑之间的街道、峡谷等空隙。考虑使用分块烘焙Bake Cells在Occlusion窗口的Object标签下可以设置View Cell Size。将大世界分割成多个单元格分别烘焙和管理可以优化运行时数据加载。预期效果当玩家在山谷中时两侧的山脉能有效剔除山谷外的广大区域。在城镇中密集的建筑能互相剔除背后的建筑。对于开阔平原遮挡剔除效果有限此时应主要依赖视锥体剔除和层次细节LOD系统。6. 常见问题、性能陷阱与调试技巧即使配置正确在实际项目中还是会遇到各种问题。这里记录一些典型的坑和解决方法。6.1 常见问题速查表问题现象可能原因排查与解决思路物体闪烁时隐时现1. 物体被错误地当作Occluder但其形状如栅栏导致剔除不稳定。2.Smallest Hole设置过大小孔洞后的物体被错误剔除摄像机微动时又出现。3. 遮挡数据分辨率过低边界计算不精确。1. 检查闪烁物体及其附近物体的Static标记确保镂空/透明物体未标记Occluder。2. 适当减小Smallest Hole值或确保有孔洞的物体不被当作Occluder。3. 尝试提高烘焙分辨率重新烘焙。该被挡住的物体依然被渲染1. 遮挡物未标记Occluder Static。2. 遮挡物尺寸小于Smallest Occluder设置。3. 摄像机与物体间存在多个遮挡物但数据烘焙不连续。4. 物体本身未标记Occludee Static。1. 确认遮挡物勾选了Occluder Static。2. 测量遮挡物尺寸调整Smallest Occluder。3. 在Scene视图用Occlusion可视化模式逐步移动摄像机观察剔除过程检查遮挡链是否完整。4. 确认被遮挡物勾选了Occludee Static。烘焙时间过长1.Smallest Occluder设置过小大量微小物体参与计算。2. 场景中标记为Occluder的物体过多或过于复杂高面数。3. 烘焙分辨率设置过高。1. 增大Smallest Occluder过滤掉小物体。2. 审查场景将不适合作为Occluder的物体小道具、植物改为仅Occludee。3. 对于大型场景尝试降低烘焙分辨率或使用分块烘焙。烘焙数据文件巨大同上原因类似。此外可能使用了过高的Backface Threshold精度。同上。另外检查是否对大量复杂网格如树木进行了Occluder标记考虑用简化的代理碰撞体代替复杂网格进行遮挡烘焙高级用法。移动平台如Android/iOS上效果差或出错1. 遮挡数据过于复杂加载或计算开销大。2. 可能使用了不支持的烘焙设置或特性。1. 采用更“保守”的烘焙策略更大的Smallest Occluder更低的分辨率。2. 确保所有参与烘焙的物体都使用了移动平台支持的Shader和渲染状态。复杂植被、粒子系统等可能不适合参与静态遮挡。6.2 高级调试技巧Scene视图可视化这是最基本的调试工具。除了看物体的显示/隐藏还可以在Occlusion Culling窗口的Visualization下开启Show Portals和Show Visibility Lines能看到摄像机视锥体如何被遮挡体切割以及可见性的计算路径对于理解复杂遮挡关系非常有帮助。Frame Debugger在游戏运行时打开Window Analysis Frame Debugger。逐步查看每一帧的绘制调用Draw Calls你可以清晰地看到哪些物体因为遮挡剔除而被跳过。这是验证运行时剔除是否生效的终极工具。脚本查询可以通过编写简单的调试脚本在运行时输出某个物体是否被当前摄像机遮挡。使用Renderer.isVisible属性需要注意它综合了视锥体和遮挡剔除的结果。更精确的遮挡查询可以使用Camera的相关API但通常可视化工具已足够。烘焙代理体Bake Proxy对于极其复杂但形状规则的物体如一棵细节丰富的树可以创建一个简单的长方体或胶囊体碰撞器将其标记为Occluder Static而将原始的高面数树模型标记为仅Occludee Static。这样遮挡计算基于简单的代理体快速且稳定而渲染的依然是精美的模型。这是一种平衡精度和性能的高级手段。6.3 性能陷阱提醒动态物体是盲区静态遮挡剔除对动态物体无效。一个在墙后跑动的NPC依然会被渲染。对于大量动态物体需要结合其他技术如动态遮挡剔除插件如Unity的Entity Occlusion Culling (ECS)或第三方解决方案。基于距离的LOD与裁剪对于远处的动态物体直接根据距离隐藏或简化。手动管理对于已知的、移动范围受限的动态物体如房间内的NPC可以通过触发器Trigger或逻辑判断来手动启用/禁用其渲染器。过度剔除的代价过于激进的剔除设置很小的Smallest Occluder很大的Smallest Hole可能导致物体在应该被看到的时候突然“弹出”Pop-in破坏游戏体验。这种视觉瑕疵比多渲染几个三角形更糟糕。永远优先保证视觉正确性再考虑性能优化。内存与加载时间复杂的遮挡数据会增加场景的磁盘大小和内存占用也可能略微增加场景加载时间。对于需要流式加载的开放世界需要精心设计分块策略和数据压缩。理解Occluder和Occludee并正确配置Static标签是掌握Unity遮挡剔除的基石。它不是一个“勾上就有魔法”的选项而是一套需要结合具体场景进行思考和调优的精细工具。从区分“挡板”和“演员”开始到有策略地批量标记再到耐心调整烘焙参数并反复调试验证这个过程本身就是一次对场景空间结构和渲染管线的深度理解。别再乱勾Static了从现在开始让你的每一次勾选都有的放矢让遮挡剔除真正成为你项目性能优化的坚实支柱。