[UE5] 在UE5中使用世界位置偏移时的阴影问题

在本文中,我想讨论两个关于使用UE5时遇到的问题,即残影问题。

第一个问题是Distance Field Shadows(距离场阴影),第二个问题是Virtual Shadow Maps(虚拟阴影贴图)。
请注意,我并没有涵盖所有关于残影的问题。


Distance Field Shadows(距离场阴影)引起的阴影问题

在UE5.1中,如果将SkyLight设置为Movable,并且使用材质的World Position Offset对网格进行了偏移,会导致阴影残留在原始网格的位置。
请添加图片描述
而UE4.27中的相同情况不会产生类似的现象
请添加图片描述

这是因为在UE5.1中,默认情况下启用了"Generate Mesh Distance Fields",并且手动禁用了Lumen。
请添加图片描述
请添加图片描述

通过Mesh Distance Fields生成的网格是在任何变形(如World Position Offset)之前创建的。这里所描绘的扭曲阴影是Distance Field Ambient Occlusion。

Distance Field Ambient Occlusion参考了Mesh Distance Fields,因此阴影仍然保留在网格的原始位置上。
请添加图片描述

而4.27中没有发生这种情况的原因是默认没有启用网格距离场。
请添加图片描述
当然,在4.27启用生成网格体距离场时与5.1具有相同的现象。


以下是一些解决方法

  • 启用Lumen
    尽管Lumen在某种程度上也引用了Mesh Distance Fields的机制,但对于不支持Lumen软件光线追踪的部分(如World Position Offset),它会确保外观没有问题。(可能是通过ScreenTrace进行处理吗?)

  • 禁用Distance Field Shadows
    通过取消Actor的Details>Lighting>Affect Distance Field Lighting复选框的选中状态,您可以使该Actor不再使用Distance Field Shadows,从而修复阴影的偏移。

请添加图片描述
请添加图片描述

Virtual Shadow Maps(虚拟阴影贴图)时出现的阴影问题,

接下来,我们将再次使用默认设置的UE5.1,并使用World Position Offset(世界位置偏移)进行观察。

这次,我们将让球体持续移动。
请添加图片描述
看起来阴影被放置在了错误的位置。这个问题不是由Mesh Distance Fields(网格距离场)引起的,而是由UE5的新功能Virtual Shadow Maps(虚拟阴影贴图)引起的。

在这个场景中,有一个Directional Light(定向光)和一个Skylight(天空光)。在UE5中,Directional Light的Cascade Shadow(级联阴影)部分被替换为Virtual Shadow Maps。

Virtual Shadow Maps在动态地为大量细节对象投射阴影时采取了缓存的策略,以减轻负载。

它将阴影分割成细致的部分和粗糙的部分,并判断哪个部分的阴影缓存需要更新,以实现近处细节丰富、远处粗糙的效果。
在这里插入图片描述
让我们实际看一下哪些页面正在被更新。我们选择Viewport中的Virtual Shadow Maps > Cached Page。

更新了阴影信息的部分将显示为红色,而未更新且显示为缓存的部分将显示为绿色。
在这里插入图片描述
然后,围绕着运动的球体的页面都以红色进行了更新,
但是边缘部分是绿色的,也就是没有更新。
因此,阴影仍然显示出来。

以下是一些解决方法

  • 不缓存

通过使用命令 r.Shadow.Virtual.Cache 0,可以将其设置为不缓存状态(始终持续更新)。
在执行此命令的情况下查看缓存页面。
在这里插入图片描述
可以看到全部都是红色,整个页面始终处于更新状态。
当然,由于不断更新,阴影也不会残留。
在这里插入图片描述

然而,这样做会剥夺整个场景中虚拟阴影贴图的缓存优势,因此在负载方面可能不是很理想…

  • 调整角色的Bounds Scale

似乎Virtual Shadow Maps的更新范围是根据角色的Bounds来确定的。
对于原始球体的Bounds,更新范围如下所示。
在这里插入图片描述

对于在World Position Offset中移动的范围,Bounds较小,因此更新的页面也较小。

让角色的Bounds Scale调整为3。
在这里插入图片描述
更新的部分变得更广泛,阴影也能正确绘制!

Lumen和Virtual Shadow Maps,虽然这里没有提到Nanite(+Mesh Distance Fields),但它们彼此互补。
因此,关闭其中一个可能会导致问题发生,所以在更改设置时要小心。

UE5的动画蓝图使用USkeletalMeshComponent的GetSocketLocation()方法获取骨骼位置,可以按照以下步骤进行: 1. 获取骨骼所在的USkeletalMeshComponent 在动画蓝图,可以使用以下方法获取骨骼所在的USkeletalMeshComponent: ``` USkeletalMeshComponent* skeletalMeshComponent = TryGetPawnOwner()->FindComponentByClass<USkeletalMeshComponent>(); ``` 这里使用TryGetPawnOwner()方法获取控制器的所有者(一般是角色),然后使用FindComponentByClass()方法查找该所有者的USkeletalMeshComponent对象。 2. 获取骨骼Socket位置 ``` FVector socketLocation = skeletalMeshComponent->GetSocketLocation(socketName); ``` 这里使用USkeletalMeshComponent的GetSocketLocation()方法获取指定骨骼Socket的位置,参数为骨骼Socket的名称。返回值为FVector类型,表示骨骼Socket的位置。 需要注意的是,skeletalMeshComponent是一个指向USkeletalMeshComponent的指针,可以通过该指针调用GetSocketLocation()方法。如果skeletalMeshComponent不是指针,可以使用其他适当的方法调用GetSocketLocation()方法。 3. 在动画蓝图使用骨骼Socket位置 获取骨骼Socket位置后,可以在动画蓝图使用位置进行动画操作。例如,可以使用SetLocation()方法将Mesh的位置设置为骨骼Socket的位置: ``` GetOwningComponent()->SetWorldLocation(socketLocation); ``` 这里使用GetOwningComponent()方法获取动画组件的引用,然后使用SetWorldLocation()方法将Mesh的位置设置为骨骼Socket的位置。 需要注意的是,如果你在使用SetWorldLocation()方法发现Mesh的位置没有改变,可能是因为Mesh的Collision属性禁用了移动,需要在Mesh的Collision属性启用移动。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值