静态网格体的碰撞设置和合并Actor,这两件事可以说是UE4新手从“摆场景”迈向“做项目”的分水岭。我刚入行那会儿,卡得最久的就是角色莫名其妙穿模,场景里几百个模型跑起来卡成PPT,后来才发现问题一个出在碰撞预设没搞懂,另一个出在Draw Call根本没做优化。这篇文章围绕静态网格模型的碰撞设置和合并静态网格体这两块,把原理、操作步骤和我在实际项目中踩过的坑一次性说清楚,适合刚开始学UE4、希望把场景跑得又稳又真实的新手参考,也适合已经会摆场景但始终没搞懂“碰撞为什么没生效”“合并完为什么崩了”的朋友。
1. 先把碰撞逻辑理清楚:UE4为什么需要一套自己的碰撞体系
1.1 查询碰撞和物理模拟,根本是两码事
很多新手一听到“碰撞”两个字,就直接想到“物体掉下来砸到地上弹起来”,但其实UE4里的碰撞包含了两套完全不同的逻辑。一套叫做查询碰撞(Query Collision),另一套叫做物理模拟碰撞(Physics Collision),两者的作用和处理方式截然不同。这不是抠字眼,而是很多碰撞设置“无效”的根本原因。
查询碰撞,简单说就是“逻辑层面的探测”。比如你用射线检测判断玩家准星对准了哪个敌人,或者用重叠检测判断角色是否走进了某个区域,这些都不需要真正的物理引擎介入,只是引擎在问“这里有没有东西,它是什么类型”。而物理模拟碰撞才是真正让物体发生物理反应的那一套,比如你丢一个球出去,球撞到墙被弹回来,这就是物理引擎的计算结果。
为了帮助你更快建立概念,我习惯用一个特别朴素的生活类比:查询碰撞就像你用手电筒往黑暗里照,灯光扫到东西,你只是“知道了那有东西”;物理模拟则是你真的闭着眼走过去,撞到墙了,你被拦住了,头还撞了个包。这两者虽然都要用到“碰撞体”这个数据,但用途不一样,消耗也不一样。
在UE4的Static Mesh(静态网格体)属性里,有一个Collision Enabled下拉框,里面能看到Query Only、Physics Only、Query and Physics、No Collision这几个选项。默认情况下大多数模型是Query and Physics,也就是两套都参与。但很多新手为了省性能,把某个模型改成Query Only,结果发现角色直接穿模了,原因就是这个模型只响应“查询射线”,不参与真正的“物理阻挡”。反过来,如果你把场景里纯装饰的物体改成Physics Only,它可能会挡住物理模拟的物体,但角色射线检测却扫不到它。搞清楚这个区别,后面所有碰撞设置都有了解释。
1.2 碰撞通道和预设:默认设置为什么经常“不起作用”
UE4的碰撞系统里还有一个让新手头大的概念:碰撞通道(Collision Channel)和碰撞预设(Collision Presets)。听起来很抽象,但实际上这就是一张“谁和谁怎么相处”的关系表格。
每个Actor/Object都有自己的Object Type(对象类型),比如WorldStatic、WorldDynamic、Pawn、PhysicsBody等。与此同时,它还维护了一张“我对其他通道是什么态度”的响应表,每个通道对应Block(阻挡)、Overlap(重叠)、Ignore(忽略)三种关系。而碰撞预设,就是UE4替你打包好的几套常用配置,比如BlockAll就是“阻挡所有能阻挡的东西”,OverlapAll就是“和所有东西都做重叠检测”。
那为什么新手经常会遇到“我明明设了碰撞,角色还是穿过去”的情况?最常见的原因是角色移动组件(Character Movement Component)里的碰撞设置和网格体的碰撞预设互相矛盾。比如角色胶囊体在Pawn通道里,而某个静态网格体的Object Type被设成了Pawn,它自然就不会挡住玩家角色,因为引擎认为“大家都是Pawn,默认不互相阻挡”。还有一种情况是,模型自身的碰撞预设是Ignore Pawn,这是很多从素材商店下载的模型常见的默认选项,导入后也没有人去改,结果自然是穿模。
所以我在给新手培训时,一直强调一个排查思路:先看Object Type,再看Collision Responses里你关心的那个通道是Block还是Ignore,最后再看移动组件那边有没有开启碰撞。这三步走完,80%的“穿模”问题都能定位到具体原因。
2. 静态网格体碰撞设置的完整实操
2.1 自动生成碰撞体的四种方式以及各自的适用场景
搞清楚了碰撞的逻辑,接下来就是动手给静态网格体设置碰撞体。这里的核心概念是Simple Collision(简单碰撞)和Complex Collision(复杂碰撞)。简单碰撞是用少量基本几何体去“包住”模型,用于物理模拟和大部分游戏逻辑,速度快、性能好;复杂碰撞则是直接用模型的三角面片进行计算,精度最高,但消耗也最大,一般只在特殊情况下才启用。
在UE4中,双击任意一个Static Mesh资源,打开Static Mesh编辑器,顶部菜单栏里有个Collision按钮,点开之后能看到很多选项,其中跟生成碰撞体直接相关的有四个:
第一种是Add Box Simplified Collision,生成一个长方体碰撞体,适合墙壁、地板、箱子这种规规矩矩的模型。第二种是Add Sphere Simplified Collision,生成一个球体碰撞体,适合柱子、树干、路灯这类大致呈圆柱形的物体。第三种是Add Capsule Simplified Collision,生成胶囊体碰撞体,适合栏杆、拱门这类上下有圆弧的细长物体。第四种是Auto Convex Collision,也就是自动凸包碰撞,它允许你自己设置凸包数量和精度,让多个凸包拼成一个贴合模型的碰撞外形,适合复杂的不规则模型。
我特别想提醒一点:新手经常觉得“碰撞体越精确越好”,于是在Auto Convex Collision里把凸包数量拉满,一个椅子生成十几个碰撞体。这其实是在给物理引擎增加负担,完全没有必要。游戏里的碰撞不是追求完美贴合,而是追求“玩家看着不觉得假”就行。一把椅子用3到5个凸包已经非常好用了,再多就是浪费性能。
2.2 手动调整碰撞体:从“能用”到“好用”的关键一步
自动生成的碰撞体通常不会一次到位,它可能比模型大了一圈,也可能歪到一边。这时候就需要手动调整。在Static Mesh编辑器里选中自动生成的简单碰撞体,右侧细节面板里可以直接修改它的位置、旋转和缩放值。你也可以在视口里按住相应的轴向拖动,把它移动到合适的位置。
这里有个非常实用的小技巧:在Static Mesh编辑器里按快捷键Alt+R、Alt+W、Alt+G之类的切换视图模式,或者直接点击视口左上角的视图模式下拉菜单,把显示方式切换成“碰撞可视化”相关选项,就能看到碰撞体的真实样子。我经常见到有人调整了半天,结果忘了打开碰撞显示,完全不知道自己的碰撞体长什么样。
另一种手动调整方式,是给同一个静态网格体添加多个简单碰撞体。比如一个L形的桌子,你可以用两个盒体拼成L形,或者用一个盒体加一个胶囊体组合,会比单纯用一个巨大的盒体贴合得多。组合碰撞体是UE4里非常常用且高效的做法。添加多个简单碰撞体之后,右键选中的碰撞体可以复制、粘贴位置,也可以删除,实际操作起来非常方便。
这里分享一个我自己的心得:调整碰撞体时,宁可让碰撞体略微比模型“瘦”一圈,也别让它比模型“胖”太多。胖了会导致玩家明明没碰到东西却被挡住了,非常影响体验;瘦一点点反而手感更好,玩家会觉得角色更灵活。尤其是门框、窗台、山体拐角这种地方,碰撞体稍微收一点点,能省掉大量玩家投诉。
2.3 复杂碰撞的坑:把模型面片直接当碰撞用的代价
在Static Mesh的Collision属性里,有一个非常显眼的选项:Use Complex Collision as Simple。钩上它之后,引擎会直接使用模型的三角形面作为碰撞体,省去了生成简单碰撞体的步骤,模型的阻挡外形瞬间变得极其精确。
这个选项看起来非常方便,但代价也很明显。首先,物理模拟和大部分游戏逻辑碰到这种三角面碰撞体时,性能消耗会成倍增加,尤其是在有大量物体相互作用的场景里,掉帧会非常严重。其次,三角面碰撞体在一些特殊形态下会让物理引擎产生“卡在缝隙里”、“抖动”、“被弹飞”等离奇问题,因为三角形的边缘和顶点非常容易让物理引擎产生不稳定的接触点。
我在实际项目里只会在一种情况下使用它:这个物体是纯背景装饰,玩家绝对碰不到,但又需要被射线检测命中。比如远山、远景建筑、高处的装饰物。对于玩家要行走的地面、要碰撞的墙壁、要交互的桌子,我从来不开Use Complex Collision as Simple,而是老老实实生成简单碰撞体。
3. 合并Actor(合并静态网格体)实操
3.1 为什么要合并:Draw Call与性能优化的底层逻辑
合并Actor这件事,表面上看起来是“把多个模型变成一个模型”,本质上是在优化渲染性能,核心目标就是减少Draw Call。很多新手对这个概念没有血肉感,我尽量用大白话讲清楚。
当你游戏运行时,CPU每次要绘制一个模型,都会向显卡发出一个绘制命令,这个命令就叫做Draw Call。每次Draw Call,CPU都要准备一大堆状态数据,比如网格体、材质、纹理、变换矩阵等等,显卡才肯动手画。如果场景里有一百个模型,那就有一百次Draw Call,CPU可能要花大量时间在这上面,严重影响帧率。
这里最容易产生误解的一点是:合并Actor不是“把所有模型焊死”,而是通过把多个静态网格体合并成一个新的Static Mesh资产,让引擎只需要一次Draw Call就能把整个模型画出来。这对静态场景来说简直是性能救星。比如一个房间里有五十个桌椅板凳,合并之后可能只需要三五次Draw Call,性能提升立竿见影。
但是,合并Actor绝不是无脑操作。如果一个物体需要独立移动、独立播放动画、独立被拾取、需要单独控制显隐,它就不应该被合并进去。合并是“牺牲独立性换取性能”,你必须在两者之间做好权衡。
3.2 打开Merge Actors工具:菜单路径和面板参数说明
UE4的合并Actor工具入口其实有点隐蔽,初学者经常找不到。正确的打开方式有两种:要么在关卡编辑器中选中多个Actor后,点击Window菜单,找到Developer Tools,再点击Merge Actors;要么在选中多个Actor之后,直接右键鼠标,在快捷菜单里找到Merge Actors选项。
打开Merge Actors窗口之后,你会看到一大排参数,第一次见到的人十有八九会懵。我来逐个拆解一下核心选项的含义。
第一个是Pivot Point,也就是合并后生成的新网格体的轴心点位置,它决定了合并后物体旋转和缩放时围绕哪个点。一般项目里选World Origin(世界原点)会比较稳定,也可以选First Actor(以第一个选中Actor的轴心作为合并后的轴心)。我个人经验是,如果合并出来的东西要重新摆放,选World Origin更可控,至少后面的旋转不会莫名其妙。
第二个是Mesh Merging,这里可以选“按整个Actor合并”或者“按材质合并”。它决定合并结果是生成一个网格体还是多个网格体。为了最大程度减少Draw Call,通常我们会选择尽量少的材质合并,但这样做会增加材质纹理烘培的复杂度。后面我会细说。
第三个是Material Merging,它决定是否对材质进行合并。开启后,引擎会尝试把多个材质合成一张材质图集,进一步减少材质切换的Draw Call。这里就需要注意材质节点的问题了:如果原模型用的是复杂的动态材质实例,材质合并后表现很可能会发生变化,比如UV坐标错乱、透明混合出问题等。那些用到大量时间偏移、世界位置偏移、顶点动画等材质节点的模型,合并材质时要格外谨慎。
最后一个要看的是Texture Resolution,它控制合并后生成的新纹理的分辨率上限。这个值不宜设得过大,建议根据实际模型尺寸和项目目标平台来定。手机上1024就够用了,没必要为了“精致感”硬拉到4096,换来的只是内存爆棚和加载卡顿。
3.3 合并的典型流程与参数建议
光讲参数不练手是没用的,我拿一个非常典型的场景设置来演示:一个房间里摆了二十把椅子、二十张桌子,以及若干装饰品,一共六十个静态网格体Actor,玩家需要在这些桌椅之间行走。
操作步骤很明确。首先,在关卡视口里框选所有要合并的静态网格体Actor。然后打开Merge Actors窗口。这里建议在Mesh Merging里先选择按Actor合并,也就是把选中的所有网格体合并成一组。Material Merging这边,如果所有桌椅都使用默认材质的颜色变化,可以考虑开启材质合并;如果它们使用了大量独立材质,我建议先关掉材质合并,看一下实际效果再决定要不要进一步优化。Texture Resolution建议从1024开始,观察效果再往上调。
点击Merge Actors按钮之后,UE4会生成一个新的Static Mesh资产,同时替换掉关卡中原来的Actor。这个新资产在内容浏览器里能被找到,建议立刻给它改一个有意义的名称,比如SM_Merged_Room01。否则时间一长,你会看到一堆名叫Merged_StaticMesh的资产混在内容浏览器里,到时候想找谁都找不到。
合并完成之后,我最常干的一件事是打开关卡的Draw Call统计信息,对比合并前后的数字变化。你可以使用快捷键Ctrl+Shift+H打开高分辨率截图窗口,或者在运行时用Console命令“stat SceneRendering”查看Scene的Draw Call数量变化,画面会非常直观。
3.4 合并前必须检查的三件事
合并Actor这个操作做熟了很快,但真正能避免返工的人,都会在动手前检查三件事。
第一件事是材质。如果你开启了材质合并,一定要检查合并后的材质表现是否符合预期。那些用了大量自定义材质节点(尤其是涉及UV动画、细节纹理混合、顶点色)的模型,合并后非常容易出问题。解决办法也很简单:合并前先复制一份原始材质,合并后再手动修复差异。
第二件事是碰撞设置。这里要特别强调,Merge Actors生成的新Static Mesh并不会自动保留你之前精心设置好的简单碰撞体。很多新手合并完之后,把所有重心放在材质和贴图上,结果运行起来角色直接穿过桌子,才发现碰撞全丢了。正确的做法是:合并完成之后,立刻打开新生成的Static Mesh资源,重新生成简单碰撞体,或者利用前面讲的Auto Convex Collision重新生成凸包碰撞,再检查每个主要部分有没有碰撞体。
第三件事是引用关系。合并之后,原来那些Actor可以被认为是“消失”了,所有指向它们的Level Blueprint引用、蓝图变量、热连接都会失效。如果场景里有别的系统通过名字或标签来找这些Actor,合并之后一定要重新指认。这里额外提一句,如果你后续在项目里做了外接设备映射,比如用方向盘、体感设备等外部输入去驱动角色或场景物体,那么你只需要确保输入映射绑定在Pawn或Player Controller上就没问题,合并Actor不会影响输入信号本身;但如果你依赖射线检测来判断玩家视角指向哪个场景物体做交互,那合并后的碰撞体是否完整就非常关键了,因为射线只会命中碰撞体,不会命中渲染网格。
4. 实战中结合两者:用碰撞与合并搭出可运行的室内场景
4.1 一个新手练习项目的搭建思路
前面分别讲了碰撞设置和合并Actor,现在把这两件事放到一个完整的练习项目里一起做,这才算真正掌握。我自己带新手时最喜欢布置一个任务:搭一个让角色可以走进去、在里面自由穿行的室内场景,房间里有桌子、椅子、柜子、柱子、门框,还有一些挂在墙上的装饰物。
第一步是搭建基础房间。用BSP或者外部导入的墙体模型拼好房间,给墙面地面设置最简单的盒体碰撞。第二步是摆放家具和装饰。这个时候不要急着合并,先把每个静态网格体的碰撞体单独设置好,逐个确认角色能正常碰撞。第三步才是合并,把房里的静态家具选中,执行Merge Actors,合并后再重新设置碰撞。
这个顺序非常关键。如果你先合并再设置碰撞,新生成的大网格体里不同部分的碰撞体不好单独调整,遇到某个椅子位置不对,你只能改整个合并体的凸包,局面会很被动。先逐个设置好碰撞,再合并,至少前期每个网格体的碰撞逻辑你已经验证过了,后面返工的成本会低很多。
4.2 合并前后的性能对比怎么看
在场景搭建完成且碰撞设置好之后,运行游戏,先记录一下合并前的性能状况。这里我建议看两个指标:一是Draw Call数量,二是帧率。打开控制台,输入stat SceneRendering,可以在屏幕上看到Draw Call的实时数字。找到一个固定视角,比如站在房间中央,记录下这个视角下的Draw Call数量。
然后退出运行,执行Merge Actors,再重新运行游戏,回到同一个视角,再看Draw Call的变化。在我实际带新手做测试时,一个六十个Actor的房间,合并前可能有两百到三百个Draw Call,合并后经常骤降到三四十个,画面还是那个画面,只是渲染性能轻了一大截。
不过我想提醒一句,帧率并不是衡量合并效果的唯一指标,甚至不是最可靠的指标。因为帧率受GPU负载、CPU负载、场景复杂度、后期处理特效等多方面影响,有时Draw Call明显减少了,帧率却没有太大变化,这很正常。真正能证明“合并有效”的,还是Draw Call和Profile记录下来的CPU消耗时间。所以不要光盯着帧率,要多看数据。
4.3 合并后的碰撞修复流程
合并完成之后,新生成的Static Mesh资产需要在Static Mesh编辑器中重新处理碰撞。操作流程是:打开新生成的Static Mesh,点击Collision菜单,选择Auto Convex Collision,设置一个合理的凸包数量(我一般先给8到12个),点击生成后再用碰撞可视化方式查看。
这里有个容易忽略的小细节:合并工具生成的网格可能非常大,包含很多分离的部分,自动凸包可能无法覆盖每个细节,尤其是桌子腿和椅子靠背这种细长结构。最好的办法是生成几个不同精度的凸包组合,或者手动用盒体碰撞体去补全关键的阻挡部分。
另外,合并后的网格体轴心点有时会落到世界原点,导致碰撞体看起来“漂移”了。这不是碰撞体本身的问题,而是轴心点位置造成的视觉错觉。你在调整碰撞体位置时,要记住轴心在哪,否则很可能把碰撞体挪到完全错误的位置。
5. 常见问题排查与避坑实录
5.1 碰撞不生效的几个隐藏原因
新手问得最多的问题是:“我明明设置了碰撞,为什么角色还是穿模?”这类问题我在论坛里看到过无数次,回答过无数次,背后的原因其实就那几类。
第一个原因是碰撞通道没有覆盖到角色所在通道。你需要检查静态网格体的Collision Responses里,是否对Pawn通道设置了Block。很多素材模型默认是Ignore Pawn,这也是最普遍的原因。
第二个原因是角色移动组件的问题。Character Movement Component的Movement Mode如果设置不当,或者Capsule Component碰撞设置与场景不匹配,也会导致穿模。比如角色的胶囊体半径设得非常小,只有几厘米,而场景门缝恰好比角色胶囊体大,角色就能从门缝里挤过去。
第三个原因是碰撞体的位置发生偏移。很多网格体从外部导入时,碰撞体的中心点和模型中心点并不重合。在Static Mesh编辑器里打开碰撞可视化,你会看到碰撞体可能歪在模型一角。把碰撞体归零到模型中心,再测试,问题通常就消失了。
第四个原因比较隐蔽:Use Complex Collision as Simple被勾选了,而且模型自身三角面极其复杂。这种情况下,角色会被卡在一些肉眼可见的缝隙里,看起来就像“碰撞失效”。解决办法是取消这个选项,改用简单碰撞体。
5.2 合并Actor后表现异常的修复经验
合并Actor之后的异常,主要集中在材质、碰撞、灯光这几个方向。我见到最多的是合并后材质变成一团黑或者出现大面积渲染错误。这通常是因为合并材质时,UE4试图生成材质图集,但原模型的UV坐标超出了0到1的范围。这类问题没有捷径,只能回到内容浏览器,检查合并生成的材质资产,看它的纹理坐标设置,再手动修复或者换回独立材质。
第二个常见异常是碰撞体丢失。前面已经强调过一次,Merge Actors不会自动保留原碰撞体,所以合并后角色穿模是非常正常的。你只需要重新给合并生成的新网格体添加简单碰撞体就能解决。记住这个规律之后,你就不至于在合并完成那天晚上对着屏幕怀疑人生了。
第三个要提醒的是静态光照烘焙问题。很多人合并前场景里的静态光照效果是好的,合并后重烘焙,发现阴影错乱、漏光,问题出在Lightmap UV上。合并生成的网格体可能没有完整保留原本的Lightmap UV通道,导致光照烘焙结果异常。解决办法是在合并时开启相关选项(如果有),或者在合并后重新生成Lightmap UV。这个问题在大型场景中尤其麻烦,所以我的建议是,尽量在小规模合并中就把光照逻辑验证好。
5.3 避坑清单速查表
我把自己这几年碰到的典型问题整理成一张表,方便你排查。这里每个坑都是真金白银踩出来的。
| 问题表现 | 常见原因 | 修复建议 |
|---|---|---|
| 角色穿过静态网格体 | 碰撞预设对Pawn通道为Ignore | 检查Collision Responses,改为Block |
| 角色卡在模型缝隙里 | 勾选了Use Complex Collision as Simple | 取消该选项,改用简单碰撞体 |
| 合并后角色直接掉出地图 | 合并生成的新网格体没有碰撞体 | 打开新Static Mesh,重新生成简单碰撞 |
| 合并后材质变黑、错位 | 材质合并导致UV坐标丢失 | 检查合并材质,必要时放弃材质合并 |
| 合并后阴影漏光、物体漂浮 | Lightmap UV缺失或损坏 | 在Static Mesh编辑器重新生成Lightmap UV |
| 场景里个别物体不能单独拾取 | 不该合并的动态物体被合并了 | 合并前排除需要独立操作的Actor |
除了表格里的内容,最后再说一个非常细节但实用的经验:当你合并大量静态网格体时,尽量把那些有着相似材质、相似碰撞需求、相似作用的模型分成一组合并,而不是一次把整个关卡都选中。这样合并出来的网格体更容易维护,碰撞设置也更方便,一旦某个区域出现问题,你只需要重新处理那一个组,不会波及整个场景。
我做项目到现在,已经养成了一个固定习惯:任何静态网格体在进入关卡之前,我都会先在内容浏览器里确认它的碰撞设置,再入库;任何要合并的Actor,我都会在合并之前检查材质和碰撞,合并之后第一时间重新补碰撞。这套流程虽然多花十几分钟,但能帮我省掉进入项目后期之后大量返工时间。希望这篇关于碰撞设置与合并Actor的笔记,能让你在UE4的路上少走几个我当年走过的弯路。