|
History:
- 2021.11.10 - 更新黄色球和蓝色框用途,Mesh 中的 Bounds 选项以及Fixed和缩放的关系
- 2021.12.18 - Actor AttachToParent
<hr/>用 UE 4.26 ActionRPG 示例项目,对 Bounds 进行学习和总结。 一、Bounds 是什么 / 有什么用
开门见山:
Bounds 是用于进行 可见性剔除(蓝色框)以及LOD计算(黄色球) 的。 任何的游戏引擎,最终呈现出在屏幕上的效果,都是经过和很多变换和计算从三维世界空间,转成屏幕像素空间才能够被玩家看到的,这个过程中,摄像机的位置,FOV,物体的位置,透明度,深度值等等信息,都能影响物体在最终屏幕上的位置和大小,如果每个物体的每个点都要计算,计算量太过庞大,所以每个物体利用八个顶点组成的长方体 Bounds 进行可见性剔除,对于完全不可见的物体,就可以在流程中很早地舍弃掉,减少很多计算。
UE 中用于可见性剔除的 Bounds 全都是 AABB(Axis-Aligned Bounding Box)的,即轴平行包围盒,类型是 FBoxSphereBounds。不管是实时计算的,还是固定(Fixed)的,都会因为旋转而变化,使得始终与世界的 XYZ 轴平行。
蓝色框用于可见性剔除
上图中可以看到,蓝色的长方体线框就是实际用于计算的 AABB Bounds,如果蓝色长方体的八个顶点都不在视窗内,物体就被剔除了(随之那个黄色的球体框也看不见了)。所以可以看到,在镜头转动至看不到蓝色线框的时候,黄色线框也就消失了,物体的 Mesh 也就不绘制了。关于 Bounds 的可见性剔除,最重要的就是上边这个 GIF 了(武器没有消失是因为和主角是单独的两个 Actor,用不同的 Bounds 计算剔除)。
2. Mesh LOD 计算
可以看到,上图中 Bounds 除了蓝色的长方体方框,还有与之对应的黄色球体框,它的目的,是用于计算物体在屏幕内的大小(Scale)的,这个 Scale 会用于美术人员制作的 Mesh LOD。
这是因为 Mesh LOD 的计算和配置其实不是真的 Distance,而是 Screen Size,屏幕占比,比如屏占比 1.0 到 0.5 都是 LOD0,即最高等级 LOD,0.5 到 0.3 是 LOD1,即粗糙一点的 LOD,以此类推。所以黄色框的是球形,不管摄像机从哪个角度看,距离一定,Screen Size 就一定。
黄色球体框用于 LOD 计算
二、Bounds 的一些设置和代码
2.1 Bounds 的显示命令
Viewport 中预览模式下查看 Bounds
Play之后,在命令行窗口输入Show Bounds即可显示所有 Bounds。
一个 Actor 如果没有 Mesh,空的 Actor,是没有 Bounds 的,一个带有 Mesh 的默认 Character(Mesh 是空的),也是没有 bounds 的。
可以看到在没有运行时,选中 Actor,是有蓝色框和黄色框的,但是实际运行起来是看不到的,这个因为预览时默认是有一个 Sphere 的,所以有 Bounds。
如果给 MeshComponent 添加一个 SkeletalMesh,比如一把剑,Bounds 就有了:
这里也可以看出来,Bounds 和真正可见的部分,不一定是吻合的,大部分情况下 Bounds 是能完全包住可见部分的,这样就没问题(如果Bounds 太大,会导致不管在场景中怎么转摄像机,都不能剔除这个物体,增加无用计算量);但是如果 Bounds 小了,就会出现,我认为能看到的东西,转了一点点镜头突然就看不到了的情况,这个在 ( 三、Bounds 相关的一些问题)中记录。
2.2 Bounds 的设置
主要记录 SkeletalMeshComponent 上的配置,以及 Component 上的配置(这些参数都是运行时可调的!可以很方便地看到效果!!):
Bounds 相关配置
1. Bounds Scale - Bounds 倍率
- 所在类: UPrimitiveComponent
- 用途:在 CapsuleComponent 上就可以配,但是实际是不生效的,在 SkeletalMeshComponent 上设置才生效,就是字面意思,Bounds 的倍率,下图是设置成 4 的效果:
2. Use Attach Parent Bounds - 使用父节点 Bounds
如果勾选了则这个 Component 的 Bounds 不自己计算,而是直接使用他 Parent 的,从注释也可以看到,这个选项如果选了,可以大幅提升一个很多个 Component 在一个 Parent 下的效率。
最常见的就是,一个主角,头、上身、胳膊、下半身、腿、分别是单独的 SkeletalMeshComponent,都挂在一个总的 MeshComponent 下,勾选和不勾选的对比如下(其中左图是所有 Mesh 都没有选择使用 Parent,右图五个子 Mesh 以及主 Mesh 都选择了使用 Parent,可以看到减少了很大的计算量,但是由于主 Mesh 是空的,所有 Bounds 大小不太对):
如果主 Mesh 也勾选了 UseAttachParent,那么会使用 RootComponent 的 Bounds,一般来说 RootComponent 是胶囊体,即使用胶囊体的 Bounds。
特殊:
- 角色的武器一般都是挂在人身上的(武器Actor AttachToParent到角色身上),不管怎么切换挂点(背上,手上),都可以其实 Parent 都是角色的 RootComponent。如果武器的 RootComponent 选择了 UseAttachParent,那么武器的 Bounds 直接就使用角色的了(相当于是两个 Actor 用一个 Bounds,和上面说的一个 Actor 上的各个Mesh不一样)
武器没有 UseAttachParent
武器使用 UseAttachParent
3. Include Component Location Into Bounds
在 USkeletalMeshComponent::CalcBounds 中,会判断是否勾选,如果勾选了,则会根据 ComponentLocation 重新计算 Bounds:
FBoxSphereBounds NewBounds = CalcMeshBound(RootBoneOffset, bHasValidBodies, LocalToWorld);
if (bIncludeComponentLocationIntoBounds)
{
const FVector ComponentLocation = GetComponentLocation();
NewBounds = NewBounds + FBoxSphereBounds(ComponentLocation, FVector(1.0f), 1.0f);
}
把所有 Bounds 都关了,只剩头的,下图左右分别是没有勾选 Include Component Location Into Bounds 以及勾选的效果:
4. Use Bounds from Master Pose omponent
代码里 USkinnedMeshComponent::CalcMeshBound(...):
// Use MasterPoseComponent&#39;s PhysicsAsset if told to
else if (MasterPoseComponentInst && bCanUsePhysicsAsset && bUseBoundsFromMasterPoseComponent)
{
NewBounds = MasterPoseComponentInst->Bounds;
}
目前没用过,没有效果演示。
5. Skip Bounds Update When Interpolating
使用的地方,即插值就不更新了:
void USkeletalMeshComponent::FinalizeAnimationUpdate()
{
// ...
// update bounds
if(bSkipBoundsUpdateWhenInterpolating)
{
if(AnimEvaluationContext.bDoEvaluation)
{
// Cached local bounds are now out of date
InvalidateCachedBounds();
UpdateBounds();
}
}
else
{
// Cached local bounds are now out of date
InvalidateCachedBounds();
UpdateBounds();
}
}
6. Component Use Fixed Skel Bounds - 使用固定 Bounds
Component Use Fixed Skel Bounds
上图左右两个 BP 位移的区别就是 Mesh 上左边勾选了 Component Use Fixed Skel Bounds,右边没有勾,可以看到区分有两个:
1. 顾名思义,使用了 Fixed Bounds,Bounds 不会根据Mesh Pose 的变化而更新,减少了不少的计算量
2. 由于使用的是 Fixed,所以默认回比自动计算的大,为了把 Mesh 包住(用的就是默认 Mesh 的 Bounds)
实际在角色 Mesh 的界面中,原始的 Bounds 是比角色大一圈的(如上边 GIF 左边的),并不贴合(可以通过左侧的 Asset Details 中 Bounds 的设置调整,Positive 就是 XYZ 正方向的延展,单位是 cm,UE 里正常的长度单位都是厘米),这个需要使用 Fixed Bounds 才生效(但是要注意这个改小了,就可能会出现 Mesh 没有被 Bounds 包住的情况)。
注意:
1. 使用了 Fixed,且 Bounds 没有把 Mesh 完整包裹住(比如播了一个 Mesh 动画),就会出现文章开头那样,Mesh 在镜头转至特定角度后直接消失的情况。
2. Fix 不 Fix 和Scale 没有关系,只是是不是会实时计算大小,Mesh 调整大小,Bounds 不管Fix 与否,都会随之变大
7. Consider All Bodies for Bounds - 考虑所有部位
目前没用过。
2.3 Mesh 中的 Bounds 选项
在 Mesh 的界面左侧,LOD 设置中可以设置 LOD Info,比如 LOD0 设的 Screen Size 是 1.0(一般都是) ,LOD1 的 Screen Size 设的 0.3,LOD2 设的 0.15, LOD3 设的 0.1,意思就是:
1.0 ~ 0.3,使用 LOD0;
0.3 ~ 0.15,使用 LOD1;
0.15 ~ 0.1,使用 LOD2;
0.1 ~ 0,使用 LOD3。
左上角会实时显示当前的 Current Screen Size,美术人员可以参照这个来制作和调整 LOD 参数(这些参数在 Mesh Info,Basic 里显示)。
如果想在 Mesh 的编辑界面看 Bounds,右上边三个选项,其中:
- Bound - 表示是否显示 Bounds
- In-game Bounds - 表示是否使用这个 Mesh 进行 Bounds 的计算,不勾则使用的是 Bones 即骨骼进行 Bounds 的计算(因为一个骨骼可以适配多个 Mesh)。
- Fixed Bounds - 即上文所说的是否使用 Fixed Bounds,和实际在角色 BP 中是一样的效果。
所以如果实际 BP 中使用的是这个 Mesh,则美术人员做 LOD 时需要勾选 In-game Bounds,如果实际使用角色时,使用 Fixed Bounds,美术人员制作 LOD 时也需要勾选,否则制作出的 LOD 实际使用效果就不对了。
2.4 Bounds 相关的代码、计算方式
所有 Bounds 都是 AABB 轴平行包围盒,所以像第一张图中看到的那样,计算部分代码为:
实际用于剔除的代码详见:USkinnedMeshComponent::CalcMeshBound,通过一次断点可以看到堆栈:
因为需要始终轴平行,所以可能看起来 Mesh 没有动,但是 Bounds 是变了的,比如默认 Place Actors 中的球(这是因为使用和局部坐标系轴平行的 Bounds 转到与世界坐标系轴平行的 Bounds):
用 Box 看的更清楚:
三、Bounds 相关的一些问题
由于 Bounds 直接影响物体是否可见,所以如果 Bounds 设置的有问题,很可能导致在物体应该可见的情况下,却看不到。
3.1 Bounds 过小时的问题
Bounds 过小,可能是因为距离太远,整个 Bounds 在屏幕中就是一个点了,这时候整个物体就看不见了(这种情况,很少见,且看不见了也并没有什么问题)。
还有一种需要注意的,就是 Bounds XYZ 的一个值特效小的时候(比如 Z 很小,就是 Bounds 很扁),如果镜头的正方向,正好与 Bounds 的 XY 平面平行,会由于计算进行精度误差(Bounds 的长方体在屏幕中就是一根线),导致整个物体看不见了。如下图所示(使用的时候 ActionRPG 的 P_Skill_03 特效,稍微改了一下):
Bounds 过小 / 过薄
出现这个问题的一个原因是,ParticleSystem 的特效,在更新 MeshRotation 的时候,Bounds 是不更新的(不知道是不是引擎的 Bug,还是设计如此),所以如果使用的 Mesh 是一个片状的形状的话(如上图),那么默认 Bounds 就是很扁的,当 Mesh 旋转成上图所示效果,Bounds 是完全包不住 Mesh 的:
Cascade 中旋转 Mesh, Bounds 不刷新
解决方案就是像 ActionRPG 一样,使用 Fixed Bounds:
- Tips:特效的 Bounds 是整个特效的设置,不是某一个发射器的,想从发射器的设置 Details 回到整个特效的设置,不需要关了重新打开,鼠标点击最右侧空白黑色处即可~~~
3.2 Bounds 过大的问题
Bounds 大不会出现上述稍微动一下镜头瞬间看不见了的 Bug,但是会增加计算量,比如粒子特效,发射出的粒子是随机的,Bounds 的计算就会根据速度等信息自动计算,但是这样计算出来的 Bounds 可能会很大(如下图,粒子实际飞不了那么远),而且一直在变化,也会有计算量,也可以用一个适当大小的 Fixed Bounds 解决。
3.3 Mesh 没有被 Bounds 包住的情况
在勾选了 Fixed Bounds 之后,很有可能在 Mesh 播放一些动画的时候 Mesh 从 Bounds 里出去了。就像文章一开头的 GIF 一样,出现镜头转动,Mesh 突然消失的情况。
这种问题也常见于头、上肢、下肢为分别不用的 Mesh Component 的时候,角色博了一个动画,同时还附带了一个镜头动画,镜头中角色头没了,或者上半身没了,或者下肢没了等,都是这个问题。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|