奇遇 Unity XR SDK 开发文档 - iQIYIVR/QIYU_VR_v3 GitHub Wiki
本文档介绍在Unity游戏开发引擎环境下,开发者使用奇遇 Unity XR SDK(以下简称SDK)制作运行在奇遇VR一体机设备上的VR应用和游戏。
- 基于UnityXR Plug-in标准接口框架,提供VR应用开发包。
- 采用先进的由内而外的追踪系统,达到毫米级精度。
- 奇遇3手柄控制器为六自由度控制器,实现直观自然的手部运动仿真。
- Singlepass、Foveation Rendering、Vulkan等高级渲染功能提高性能。
- 高质量3D音频,为数字音频工作站提供插件。
- 提供免费的DLC上传和下载服务,帮助开发者减少APK下载大小。
| 软件要求 | |
|---|---|
| Unity Editor | 必须使用unity2019.4.22f1以上版本 |
| Android SDK | API Level 26(Android 8.0) 及以上 |
| JDK | JDK 1.8.0及以上 |
| 硬件要求 | |
| 奇遇3一体机 | QIYU OS v1.6.1及以上 |
SDK通过zip包格式提供,开发者导入后可看到如下目录:

- Assets目录:SDK的模型,材质,shader等资源
- Editor目录:SDK用编辑器工具
- Rumtime目录:SDK相关运行时脚本
- Samples目录:SDK相关Samples例子工程
- package.json文件:SDK配置文件,导入SDK的入口
奇遇3是爱奇艺智能科技有限公司(简称:爱奇艺智能)研发的6自由度一体式VR设备,搭载高通XR2芯片,采用基于计算机视觉技术的Inside-out毫米级定位追踪方案,拥有一对6自由度定位追踪的手柄控制器。下表列举了奇遇3设备的基本参数:
| 屏幕 | 单眼分辨率2160 x 2160,刷新率 90HZ |
|---|---|
| 芯片 | 高通骁龙 XR2 |
| 内存 | 8GB |
| 存储 | 128GB |
| 网络 | WiFi 6 |
| 蓝牙 | BT 5.1 |
| 声音 | 双麦克风录音,双扬声器 |
| 追踪摄像头 | 四个语言追踪摄像头 |
| 电池 | 5500mAh |
| 接口 | USB Type-C,3.5mm 耳机插口 |
| 定位追踪 | 头部和手部Inside-Out毫米级定位追踪 |
| 手部追踪范围垂直方向160°、水平方向160° | |
| 控制器 | 两个6自由度手柄控制器 |
| 视场角 | 95° |
了解如何导入SDK软件包,以及如何针对您的开发环境进行基本测试。
- 我们假设您已经了解了什么是虚拟现实及其使用的术语。 如果不是,请检查Unity XR词汇表。
- 强烈建议您在使用SDK之前,先阅读Unity XR文档,然后正确安装Unity Editor和ADB调试工具。
打开Unity Editor,新建工程
图3.1 创建工程
修改Platform为Android平台
图3.2 修改Platform
导入SDK PackageManager选择加号->Add package from disk按钮加载上面解压目录的package.json文件,XR插件就会自动导入。
图3.3 导入SDK
导入后,点击“Yes”,启用Unity new input System,Unity Editor会自动重启。
图3.4 启用Unity new input System
导入以后会看到Qiyu XR Plugin;如果有需要,点击Import into Project导入Sample工程。
图3.5 导入Samples
新建场景,创建XRRig,XRRig提供的功能参见4.1UnityXR介绍。
图3.6 创建XR Rig
必须在ProjectSettings—>XRPlug-in Management里的勾选“Qiyu”选项
图3.7 开启Qiyu
设置推荐配置,可通过“Menu/Qiyu/Modify Player Settings”一键自动设置为推荐配置。
图3.8 常用菜单功能
| 配置项 | 推荐值 |
|---|---|
| GraphicsAPIs | OpenGLES3 |
| ApiCompatibilityLevel | .NET 4.x |
| minSdkVersion | AndroidApiLevel26 |
| Scripting Backend | IL2CPP |
| Target Architectures | ARM64 |
| Default Orientation | LandscapeLeft |
| vSyncCount | Every V Blank |
表3.1 工程推荐配置
如果需要使用自定义AndroidManifast.xml文件,可以点击Qiyu->Tools->Create AndroidManifast按钮创建SDK需要的默认配置模板,在此基础上进行修改。不需要的时候可以点击Delete AndroidManifast按钮进行删除。
图3.9 创建AndroidManifast配置
打包,安装进一体机运行
奇遇UnityXR SDK基于UnityXR Plug-in Framework(https://docs.unity3d.com/Manual/XR.html)开发,目前支持以下UnityXR子系统,具体接口说明参见UnityXR说明文档:
| Subsystem | Reference |
|---|---|
| XRDisplaySubsystem | https://docs.unity3d.com/Manual/xrsdk-display.html |
| XRInputSubsystem | https://docs.unity3d.com/Manual/xrsdk-input.html |
| XRNodeState | https://docs.unity3d.com/ScriptReference/XR.XRNodeState.html |
| XRSettings | https://docs.unity3d.com/ScriptReference/XR.XRSettings.html |
本指南介绍了UnityXR为开发者提供的统一XR Rig prefab及功能。
图4.1 XR Rig配置面板
用于设置追踪原地的模式。 Device:以头显位置和方向作为参考进行追踪,Recenter会复原虚拟相机的位置 Floor:以头显检测到的地面为参考面进行追踪,Recenter不会改变虚拟相机的高度 注:对于多场景应用中,XRRig的使用注意,参见7.1 XRRig使用注意
本指南介绍了奇遇为开发者提供的一些常用功能,如果需要,请将QiyuManager prefab拖进场景。
图4.2 QiyuManager 预制体
图4.3 QiyuManager 配置面板
详细说明参见4.6.1注视点渲染
设置RenderTexture缩放系数,默认为1(推荐),即采用系统提供的尺寸,开发者可根据场景需要调整。如果小于1,画面清晰度会降低,但帧率会提升,功耗降低;如果大于1,画面清晰度会进一步提升,但是帧率会降低,功耗和内存会增加。建议最大值不要超过1.5。
- HMD 3Dof:MainCamera的Tracked Pose Driver组件的Tracking Type改为Rotation Only。
图4.4 头3Dof 模式
- Controller 3Dof:调用接口Utils.SetTrackingPosition(false)。
本指南描述了SDK支持的输入交互功能。
UnityEngine.XR.InputDevices封装了所有的设备输入接口,目前包括手柄控制器的输入接口。开发者可查阅XR Interaction Toolkit教程(https://docs.unity3d.com/Packages/[email protected]/manual/index.html)接入输入功能。
如果开发者需要在场景中使用奇遇3手柄模型,可将QIYI3_Handle拖进XRcontroller指定Model Prefab位置。
图4.5 奇遇3手柄按键示意图
图4.6 使用奇遇3手柄模型
奇遇 SDK中提供了VR输入法键盘,方便开发人员将虚拟键盘放置在应用程序中。
- 将VRInputField Prefab 拖动到UI中。
- 单击控件以弹出虚拟键盘。
- 可参考SGKeyboard.unity 示例场景。
图4.7 VR输入法键盘 4. 开发者可根据需要调节Controller参数,为了提升键盘操作的体验,推荐Device-based模式下,手柄按键阈值使用0.5。
图4.8 XR Controller属性面板 5. 设置左右手输入,如果只需要使用其中一个,可以将另外一个值NULL。
图4.9 输入法配置面板 6. 注意必须把ProjectSettings里的Active Input Handling设置为Both
图4.10 Both设置
本指南介绍了在Unity中创建引人入胜的VR音频体验的开发资源。
-
添加AudioSource组件,设置3D音效
-
开发者可在ProjectSettings-Audio中配置空间音频插件
Resonance Audio是一个多平台的空间音频SDK,可提供高保真度、强大的空间音频技术,对于VR游戏和视频的真实体验有很大的帮助。 插件下载地址:https://resonance-audio.github.io/resonance-audio/develop/unity/getting-started
图4.11 空间音频插件设置
本指南介绍了有助于提升性能的高级渲染功能。
注视点渲染(Foveation Rendering)可以优化VR场景的渲染,该技术通过为视野中心提供全分辨率(无损),降低周边视野(人眼焦点区域之外)分辨率的方式来达到优化渲染的目的。静态注视点渲染(FFR)是指将视野焦点固定在视口中心位置,实现从中心向周围逐渐降低清晰度的效果。
图4.12 Foveation Rendering原理示意图 开启和配置"Foveated Rendering"选项如下图所示,在QiyuManager对象上QiyuManager.cs脚本中控制
图4.13 Foveation Rendering 配置界面 Foveation Level等级越高帧率越高,但是像素损失越多,会影响边缘区域清晰度,请根据渲染需要选择合适的等级。开发者也可以通过5.1提供的接口设置注视点渲染级别或自定义注视点渲染参数。
UnityXR提供了Single Pass立体渲染技术(https://docs.unity3d.com/Manual/SinglePassStereoRendering.html),通过一个Camera实现立体渲染,可降低50%的DrawCall,对于CPU占用高的场景帧率提升明显。 开发者可通过Project Settings->XR Plug-in Management->Qiyu,选择MultiView,该选项全局生效。
图4.14 MultiView选项
Vulkan是一种现代图形API,与许多方面与OpenGL ES类似(OpenGL ES是奇遇3应用程序开发中使用的主要图形API),可以带来更好的CPU渲染性能,但无法提高GPU性能。 具体打开Vulkan设置的步骤如下:
- 打开Unity Editor > Build Settings > Player Settings > Settings for Android
- 找到Other Settings,勾掉 Auto Graphic API选项,在Graphic API下方添加Vulkan。
- 在Graphic API下将Vulkan排到OpenGLES上面。
图4.15 启用Vulkan Vulkan已知问题
- 在我们的性能测试中,发现Vulkan API 大致相当于OpenGL ES性能,可能某些游戏的性能有一些提升,如果您的应用程序使用Vulkan时,相比OpenGL ES,性能有下降,请向我们提交错误,我们将评估修复。
- Vulkan API目前为实验性质的功能,可能引起应用程序的中断或崩溃,如果您的应用程序使用Vulkan后没有出现问题,我们鼓励将项目升级到Vulkan。
- Vulkan API不支持MutilView和FFR功能。
本指南介绍了奇遇提供的简化开发者部分工作的功能。提供入口Menu-Qiyu
图4.16 菜单功能
一键自动修改工程配置至推荐配置,详细介绍参见快速入门步骤8
如果开发者需要在Manifest文件中加入额外的内容(比如权限),可通过“Menu-Qiyu-Tools-Create Manifest”一键自动生成Manifest文件。详细介绍参见快速入门步骤9
注视点相关API
- 设置注视点等级
Utils.SetFoveationLevel((int)FoveationLevel.High);- 设置注视点参数
Utils.SetFoveationParamets(30,30,30,30);UnityXR提供了以下接口:
- 获取围栏点数据
UnityEngine.XR.InputDevices.GetDeviceAtXRNode(UnityEngine.XR.XRNode.Head).subsystem.TryGetBoundaryPoints(List<Vector3> boundaryPoints)- 围栏改变监听事件
UnityEngine.XR.InputDevices.GetDeviceAtXRNode(UnityEngine.XR.XRNode.Head).subsystem.boundaryChanged对于UnityXR未提供的接口,QiyuBoundary类开放了更多功能的接口,供开发者使用。
- 获取围栏是否是自定义围栏
public bool GetConfigured()- 测试围栏中的Node结果
public BoundaryTestResult TestNode(Node node)- 测试围栏中的Point结果
public QiyuBoundary.BoundaryTestResult TestPoint(Vector3 point)- 获取所有围栏点集
public Vector3[] GetGeometry()- 获取围栏尺寸范围
public Vector3 GetDimensions()- 获取围栏是否可见
public bool GetVisible()- 设置围栏常驻显示(系统设置中的围栏开关会覆盖此接口)
public void SetVisible(bool value)如果您需要使用奇遇平台功能,必须先按照以下内容初始化奇遇SDK:
API:
/// <summary>
/// 初始化SDK
/// </summary>
/// <param name="app_id">APPID</param>
/// <param name="developer_id">DeveloperID</param>
/// <param name="app_secret">App 秘钥</param>
/// <param name="sign_key">App 接口签名Key</param>
public static void InitQiyuSDK(string app_id, string developer_id, string app_secret, string sign_key)
{
QiyuSDKCorePlugins.QVR_InitQiyuSDK(app_id, developer_id, app_secret, sign_key);
}参数说明:
- developer_id、app_secret、sign_key:将在商务为您分配开发者账号信息后自动生成,你可在登录奇遇开发者网站后,点击网站右上角“开发者名称”进入账户页面查看。
- app_id:请您在登录奇遇开发者网站后,点击“发布管理—应用管理”创建您的应用,系统将会给每个应用生成唯一app_id。
注意:初始化接口必须在Start函数或后面的时机调用,不能在Awake函数里调用否则会崩溃 Demo :
//First, you need to monitor the SDK initialization result
QiyuMessageListener.AddListener(QiyuMessageCode.QiyuSdkInit, ret =>
{
QiyuPlugin.MessageResult<QiyuPlugin.SDKInit> msg = ret[0] as QiyuPlugin.MessageResult<QiyuPlugin.SDKInit>;
if (msg.IsSuccess())
{
}
});
//Initialize SDK
QiyuPlugin.InitQiyuSDK(
"70519169",
"820903",
"04c8f3a2d398a09debdb34902f278e2a",
"bc85d655c3416d5abdd98d4f7184fa22");app初始化完毕后,开发者应该首先初始化sdk,来验证开发者身份,所有平台接口都需要身份验证成功后调用。否则会以下监听代码中返回初始化失败:
QiyuMessageListener.AddListener(MessageCode.QiyuSdkInit, ret =>
{
QiyuPlugin.MessageResult<QiyuPlugin.SDKInit> msg = ret[0] as QiyuPlugin.MessageResult<QiyuPlugin.SDKInit>;
if (!msg.IsSuccess())
{
///没有初始化成功的时候会调用
}
});在应用程序中获取奇遇用户的帐户状态和信息。 API:
/// <summary>
/// 获取Qiyu账户是否登录
/// </summary
public static bool IsQiyuAccountLogin()
{
return QVRSDKCorePlugins.QVR_IsAccountLogin() == (int)Bool.True;
}
/// <summary>
/// 获取Qiyu账户信息
/// </summary>
/// <param name="callback">请求的回调函数</param>
public static void GetQiyuAccountInfo(RequestCallback callback)
{
QiyuSDKCorePlugins.QVR_GetQiyuAccountInfo(QiyuMessageManager.AddRequest(callback));
}Demo:
// Get Qiyu Account information
QiyuPlugin.GetQiyuAccountInfo(
RequestCallbackByJson<QiyuPlugin.MessageResult<QiyuPlugin.QiyuAccountInfo>>.Create((QiyuPlugin.MessageResult<QiyuPlugin.QiyuAccountInfo> msg) =>
{
if (msg.IsSuccess())
{
Debug.Log("GetQiyuAccountInfo= " +msg.data.icon +" "+ msg.data.name +" "+ msg.data.uid);
}
}));开发者在获取奇遇账号信息时,应先判断是否已经登录奇遇账号,只有登录成功后,才会获取到账户信息。
if (QiyuPlugin.IsQiyuAccountLogin())
{
QiyuPlugin.GetQiyuAccountInfo(
RequestCallbackByJson<QiyuPlugin.MessageResult<QiyuPlugin.QiyuAccountInfo>>.Create((QVRPlugin.QVRMessageResult<QVRPlugin.QiyuAccountInfo> msg) =>
{
if (msg.IsSuccess())
{
uid.text = msg.data.uid;
name.text = msg.data.name;
pic.text = msg.data.icon;
}
}));
}
else {
//跳转到Home进行登录
QiyuPlugin.LaunchHome("show", "login");
}当您有两个独立的应用程序时:例如一个单人游戏和一个多人游戏。如果你想要在两个应用程序中实现应用程序深度链接,用户可以从单人应用程序加入多人游戏应用。 深度链接需要在发出请求的应用程序和目标应用程序中进行集成。接下来的部分将描述这两个应用程序所需的实现。 API:
/// <summary>
/// 打开其他应用
/// </summary>
/// <param name="app_id">应用id</param>
/// <param name="key">深度连接Key</param>
/// <param name="value">深度连接value</param>
public static void LaunchOtherApp(string app_id, string key, string value)
{
QiyuSDKCorePlugins.QVR_LaunchOtherApp(app_id, key, value);
}
/// <summary>
/// 获取深度连接信息
/// </summary>
/// <param name="callback">回调函数</param>
public static void GetDeepLink(RequestCallback callback)
{
QiyuSDKCorePlugins.QVR_GetDeepLink(QiyuMessageManager.AddRequest(callback));
}Demo:
- 从A app 打开 B app, 调用LaunchOtherApp 并传入深度链接参数。
- B app 在初始化完毕之后,调用GetDeepLink 函数获取之前传入的深度链接参数。
QiyuPlugin.LaunchOtherApp("70519169", "show", "1");
QiyuPlugin.GetDeepLink(
RequestCallbackByJson<QiyuPlugin.QiyuMessageResult<QiyuPlugin.DeepLinkParam>>.Create((QiyuPlugin.MessageResult<QiyuPlugin.DeepLinkParam> ret) =>
{
}));奇遇提供免费的DLC上传和下载服务,以帮助开发者减少APK的包体大小和用户的下载更新成本。
- DLC上传 当您的安装包过大,用户下载应用的成本过高,例如一些图片、视频等需要和应用程序关联,奇遇为您提供了更简单的DLC资源文件上传(DLC文件必须是压缩文件,可最多支持上传5个,每个文件最大3.5G),您可以自由定义在哪些场景下需要去下载DLC文件,以减少APK大小。 同时DLC会关联APK的版本,那么该APK版本下的DLC可以支持随时更新,无需更新APK,以减少用户的下载更新成本。
- 获取DLC
- 您上传DLC文件后,您可以通过以下接口获取DLC信息 API:
/// <summary>
/// 获取DLC更新信息
/// </summary>
/// <param name="app_id">AppID</param>
/// <param name="curVersion">当前应用版本</param>
/// <param name="callback">回调函数</param>
public static void GetAppUpdateInfo(string app_id, string curVersion, RequestCallback callback)
{
QiyuSDKCorePlugins.QVR_GetAppUpdateInfo(QiyuMessageManager.AddRequest(callback), app_id, curVersion);
}Demo:
QiyuPlugin.GetAppUpdateInfo(
"70519169",
"1",
RequestCallbackByJson<QiyuPlugin.MessageResult <QiyuPlugin.AppUpdateInfo>>.Create((QiyuPlugin.MessageResult<QiyuPlugin.AppUpdateInfo> msg1) =>
{
if (msg1.IsSuccess())
{
}
}));- 获取到DLC信息后,由开发者根据DLC信息完成下载资源文件,并定义下载更新的场景和交互。此时用户在打开应用时,才能获取应用的完整功能和体验。
- 如果游戏中有多个场景,每个场景都放置XR Rig,那么每次切换到新场景,都会自动重置position和rotation,TrackingOriginMode也会重新计算。
- 如果想要整个App只有一个XR Rig,可以制作一个启动场景放入XRRig,或者单例,然后调用GameObject.DontDestroyOnLoad让XR Rig保持不销毁。其他场景不放置XR Rig,这种情况在切换场景的时候可以保证position和rotation不被重置,TrackingOriginMode也不会重新计算。
- 如果不销毁XR Rig,需要同时保证XR Interaction Manager,QiyuManager同时不被销毁。
- 在使用单XR Rig的时候,如果跳转到其他场景中射线无法交互,则需要通过代码设置Canvas上的Event Camera,另外进入新的场景后需要重新初始化XRRayInteractor(可能是Unity的bug),这里我们只需要做一下隐藏和显示就可以了。具体示例如下,将该脚本挂载到UI Canvas上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class QiyuCanvasController : MonoBehaviour
{
Canvas canvas;
private void Awake()
{
canvas = GetComponent<Canvas>();
canvas.renderMode = RenderMode.WorldSpace;
canvas.worldCamera = Camera.main;
}
// Start is called before the first frame update
IEnumerator Start()
{
XRRayInteractor[] xRRayInteractor = FindObjectsOfType<XRRayInteractor>();
foreach (XRRayInteractor xrRay in xRRayInteractor)
{
xrRay.gameObject.SetActive(false);
yield return new WaitForEndOfFrame();
xrRay.gameObject.SetActive(true);
}
}
// Update is called once per frame
void Update()
{
}
}- 奇遇Unity SDK v0.4版本及以前版本迁移到UnityXR SDK v1.0.0版本时,必须删除老的SDK所有文件(QYVRSDK、QIVR Sample),再通过Unity Package Manager导入新的XR插件。
- 1.0版本统一规范了XR接口名称,在删除掉老版本SDK、导入XR sdk后,如果出现unity Editor Log报错,需要根据本开发文档和UnityXR开发文档,替换相应的接口名称。
- 挂在原“QVR Camera”预制体及其子物体上的脚本、组件,请根据需要移至“XR Rig”预制体上。
如果需要不同系统语言下显示不同AppName,需要在打包的时候导入Android的多语言配置文件,在每个语言string.xml里配置不同app_name字段,多语言package例子可以从这里下载: