超阈限空间VR复现

视频教程已同步发布至B站:https://www.bilibili.com/video/BV1Lg4y1F7Xd

UE版本:5.1.1

创建一个虚拟现实游戏项目

image-20230514165545262

描边选中

主要用到了后期处理体积的后期处理材质

image-20230514165929810

这里的PP_Highlight材质文件,直接从上面提供的工程文件里面迁移过来,后面会专门出视频讲解原理

image-20230514165904867

逻辑实现

打开默认的Pawn文件

在右手食指处创建一个场景组件,用于指示手指的方位

image-20230514171545987

再事件图表里新增一个Tick函数

image-20230514171227184

当我们按下Grasp键的时候,就对当前命中的物体进行对应操作

没按下的时候,就检测当前方位是否有命中物体,如果命中了,就让命中的物体显示出白色描边

选中和描边

LineTrace的核心逻辑如下

image-20230514171704378

SetGlowingEdge的核心逻辑如下

检测击中的物体是否为StaticMeshActor(这里可以改成你想要的任何类型)

  1. 看这个物体是否可以被抓取
  2. 如果可以抓取,就把这个物体设为TmpHitTarget,并判断它是否有效
  3. 然后再看上一帧命中的物体,命名为TmpLastTarget,看它是否有效,这里会有如下四种情况
    • TmpHitTarget有效,TmpLastTarget有效,且这二者相等,说明这两帧都指向同一个物体,逻辑不变
    • TmpHitTarget有效,TmpLastTarget有效,且这二者不相等,说明这两帧都指向的物体不同,那就取消上一帧那个物体的描边,且将TmpLastTarget设为TmpHitTarget,并让新的TmpLastTarget开启描边
    • TmpHitTarget有效,TmpLastTarget无效,说明上一帧没有命中物体,从这一帧开始命中,那就将TmpLastTarget设为TmpHitTarget,并让新的TmpLastTarget开启描边
    • TmpHitTarget无效,TmpLastTarget有效,就说明从现在开始不指向新物体了,那就将TmpLastTarget取消描边,且设为空
  4. 如果发现这个物体不能被抓取的话,就不走上面的逻辑,直接将TmpHitTarget和TmpLastTarget都设为不可描边,同时无效

image-20230514171836220

设置描边的SetCustomDepth函数逻辑如下

这里指示简单的渲染了一下自定义深度,具体的描边逻辑会在上面的材质和后期处理体积里面的执行

image-20230514172726051

最后还需要再Grasp事件里面补充一些逻辑

image-20230514182923768

恒定缩放

如果按下了Grasp键,就需要锁定命中物体,并根据摄像头的位置和旋转,实时计算目标的缩放,让它在视野内位置恒定的大小

详细逻辑在Tick里面的SetTargetScaleByCamera里实现

image-20230514174649740

在物体运动的过程中,摄像机的位置不会发生改变,我们需要根据第一帧中,摄像机与目标物体之间的位置 \(D0\) 和此时目标物体的缩放 \(L\)。实时计算出后续运动过程中,目标物体的缩放 \(Ln\)

这里的常量是 \(D0\)\(L\),我们只需要维护 \(\frac{L}{D0}\) 不变就可以了,这里有如下公式 \[ \frac{L}{D0}=\frac{Ln}{Dn} \\ Ln=\frac{Dn}{D0}L \] 所以实时缩放就这样算出来了,接下来用蓝图来实现出来(会有一些不同,需要多理解一下)

image-20230514175556942

image-20230514175606626

恒定位置

这部分逻辑与缩放有一定类似,如果按下了Grasp键,就需要锁定命中物体。

在第一帧计算出以下三个变量

  • 从摄像头处出发,沿摄像头向前向量命中的坐标(忽略目标物体),保存摄像头到这个坐标的距离 \(D2\)
  • 摄像头与目标物体之间的距离 \(Dn\)
  • \(Dn\)\(D2\) 之间的比值 \(Q\)

然后在接下来的运动中,只需要保证每一帧的 \(Q\) 不变就好(当然,位置策略也可以自己调整)

详细实现逻辑如下

image-20230514182559725

image-20230514183918787

image-20230514183932611