[UE4] VR 基础功能实现:视野移动与 Stereolayer UI

1,637 阅读6分钟

1.Pico Neo 3 配置启动项

1.在电脑上下载 Steam,SteamVR,Pico 官方的游戏串流助手

2.将 Pico Neo 3 与电脑 USB 接口连接,在电脑中打开串流助手,然后在 VR 中打开串流助手,自动连接到电脑,然后电脑上自动打开 SteamVR

3.SteamVR 显示连接到 VR 设备之后再打开 UE 工程,这时工程中的 VR Preview 就可用了

image.png

VR 连接电脑有两种方式,无线和有线。

一开始我是用有线方式是可以的,但是最近提示我没有连接 USB 3.0 了,我已经把主机上 Gen 1 和 Gen 2 的口都试过了,电脑也重启过很多次了,设备管理器中 USB 驱动也更新了,就是不行。之后我就不会搞了。但是使用无线方式连接还是可以的。

如果无线方式连接后视野出现卡顿花屏,可以重新连接,或者重启电脑再连接。

无线有的时候会非常卡顿,怎么重启串流助手都不好使

有一次我使用无线连接的同时再加上 usb 线连接到电脑,虽然不是串流助手里面的有线连接,但依然比之前卡爆了的单独的无线连接好了很多

2.基础操作

2.1 使用左右手柄的摇杆控制摄像机的移动旋转

摄像机需要挂在一个 root 下面,VR 眼镜在游戏中相当于摄像机,直接控制摄像机是无效的,但是 VR 眼镜的空间是基于摄像机的父节点的,所以控制摄像机的父节点可以控制 VR 视野的移动旋转

image.png

image.png

这个蓝图的效果是,当左手柄的扳机没有按下时,推动左手柄的摇杆可以取 X 方向上的推动值调整摄像机的高度;当左手柄的扳机没有按下时,推动左手柄的摇杆可以取 Y 方向上的推动值调整摄像机的 Z 轴旋转;推动右手柄的摇杆可以调整摄像机的水平位置

如果是没有加入 VR 包的已有项目,不想再加入 VR 包,可以新建一个 VR 工程,然后导出这个 VR 工程的键位设置文件,然后在已有项目中先备份键位设置文件,然后再导入 VR 工程的键位设置

2.2 使用 StereoLayer 制作 VR UI

image.png

image.png

2.2.1 使用 widget component

由于 VR 设备的特殊性,没有连接 VR 和有连接 VR 是不同的两个 Widget 逻辑。

本来为了方便,我想对同一个 Pawn 内的 Widget Component 采用不同的设置,来适应不同的逻辑

但是首先遇到一个问题是,我不知道怎么更换 Widget Component 的 Widget Class,蓝图里似乎没有提供给我这个属性

于是我就想着,那就统一使用 create widget 嘛,这样我既可以选择我创建的 widget 的类型了

结果 create widget 得到的 widget 没有 get render target,就很离谱

一个是 widget object,一个是 widget component object,只有 widget component object 才有 render target

感觉很难理解……因为 widget 本质上不都是有一个渲染目标的吗,难道 component 的流程会不一样吗

我看到别人是可以把一个 widget 转到 render target

但是我不会用 C++,我做的 BlueprintFunctionLibrary 的 GENERATED_BODY() 总是报错……不懂

ue4 Widget to RenderTarget - HaiLiangFeng - 博客园 (cnblogs.com)

于是接下来我就只能想着,一直在 pawn 的摄像机下面放一个 widget component,赋予透明材质;没有连接 HMD 的时候使用 create widget,有连接的时候拿到这个 widget component 的 render target 给 stereolayer

但是之后又有问题,widget object 和 widget component 的类型不相同,所以我没办法放在一个数组里面,get all widget of class 也得到的只是场景中的所有 widget object。这就意味着当我有一个逻辑要与 widget 通信的时候,我只能手动地取 widget object 和 pawn 的 widget component,把连线连出很多

这是不优雅的,因此之后我又想到,干脆全都做 widget component,然后设置一个 actived widget component 的变量,这样就统一了

之后我才知道原来可以从 widget component 获得 widget,这样的话,widget 数组是可行的,当然,还是没有一个 actived widget component 好

最后我发现 screen 类型的 widget component 跟我想象中的 add to viewport 的效果不是一个东西,widget component 会显示一次,add to viewport 也会显示一次

因此还是要使用一个统一的 actived widget 而不是 actived widget component

这个时候因为我知道有 get widget 这个东西,所以我可以从 widget component 得到 widget 了,所以我才能统一起来

走错了好多路(感叹

2.2.2 Space

space 类型不管是什么,widget component 都是会显示在游戏中的,没有看到可能是因为法向或者摄像机位置不对,不是因为它没有 add to viewprot

image.png

Screen 类型,Widget 虽然处于世界中,但是看到这个 Widget 的时候它的坐标系会基于屏幕坐标系(但不是完全基于,跟 viewport 效果相似但不同)

image.png

World 类型,Widget 坐标系就是世界坐标系

或者说 widget component 控制了在世界中的显示方式,add to viewprot 控制了在视口中的显示,这两个是平行的

2.2.3 Stereo Layer Type

最后是 stereolayer 的位置问题

image.png

看官方给 Stereo Layer Type 的注释感觉完全没搞懂,只能根据实际效果分类了

World Locked 的效果是跟随人的头部运动 Tracker Locked 的效果是固定在 VR 坐标系的某处 Face Locked 没有显示,不知道是为什么

一般我觉得 World Locked 的效果就可以满足需要了吧,这时,Stereo layer 与摄像机之间的距离越远,Stereo layer 的显示小

2.2.4 隐藏 Widget Component

image.png

这几种设置 Widget Component 的可见性的方法,只有最后一种是有效的

可能是因为 Widget Component 本身负责渲染,而是它底下的 Widget 负责,所以才会这样?不懂,我瞎猜的

但是如果 HMD Widget 默认材质是透明的话,那么其实哪个 Widget 在两种情况下都不用设置可见性

因为戴上 HMD 的时候可以不将 NonHMD Widget Add ViewPort,这样 NonHMD Widget 就不显示了

没戴上 HMD 的时候 HMD Widget

2.2.5 Widget Interface

同理,对 Widget 蓝图装一个 Interface,然后对使用这个 Widget Class 的 Widget Component 调用 Interface 中的函数,没有响应,对 Widget Component 的 Get Widget 得到的 Widget 调用 Interface 中的函数才有响应

已经被 Widget Component 折磨够了,习惯了