7 进阶功能

7.1 配置EyeBuffer大小

SDK支持响应Unreal的“vr.pixeldensity”命令,开发者可以通过该命令来配置EyeBuffer(RenderTexture)的大小。

使用方法:

方式一:打开文件 Project/Config/DefaultEngine.ini,然后在“[/Script/Engine.RendererSettings]”标签下添加字符串“vr.pixeldensity=1”,如果该命令等于一或者没有该命令,则EyeBuffer大小为Pico的默认大小,如果该值不等于一,则会在Pico默认的EyeBuffer大小的基础上进行缩放。 如下图所示:

_images/9.1.png

图7.1 设置EyeBuffer大小

方式二:可以通过蓝图调用控制台命令实现该效果。使用节点“Execute Console Command”节点,调用“vr.pixeldensity 1”命令(命令中字符串和数字之间有一个空格)。同样数字部分为EyeBuffer的倍数。但是要保证该命令的执行必须足够早,建议放在关切蓝图的EventBeginPlay后。

_images/9.0.png

图7.2 设置EyeBuffer大小

原通过项目设置 > 插件 > PicoMobile中的“Multiples of RT size”参数配置EyeBuffer大小的功能已废弃。

Tips: 建议开发者不做修改,仅在特殊需求场合使用自定义RenderTexture大小。对于该选项开发者必须了解以下两点:

  • RT设置过小,会带来性能的提升,减少延迟,但同时也导致了分辨率降低;
  • RT设置过大,会带来性能的降低,增加延迟,因此不建议RT设置超过硬件建议纹理尺寸;
  • 目前RT可设置参数大小范围为0.5 - 2

7.2 眼球追踪

Pico Neo2 Eye设备支持眼球追踪, 眼球追踪可以追踪眼球注视位置,配合注视点渲染可以优化渲染性能。眼球追踪功能的开关在 项目设置 > 插件 > PicoMobile,勾选“EnableEyeTracking”即可打开眼球追踪功能。如图:

_images/9.2.png

图7.3 眼球追踪

可以通过以下阶段获取眼球的位置与方向。

_images/7.2.1.png 功能 获取眼球的位置和方向(仅Neo2 Eye支持, 需在项目设置中勾选”Enable Eye Tracking”)
输入
输出 眼球的位置和方向
返回值 True:成功,False:失败。

7.3 注视点渲染

注视点渲染(Foveation Rendering)可以优化VR场景的渲染,该技术通过为视野中心提供全分辨率(无损),降低周边视野(人眼焦点区域之外)分辨率的方式来达到优化渲染的目的。 这里提供了两种使用注视点渲染的方式:

方法一:在打包之前,可以在“ 项目设置 > 插件 > PicoMobile”中勾选“Enable FoveationRendering”开启注视点渲染功能,并在“Foveation Level”下拉框指定Level即可(SDK默认提供了三个Level:Low/Med/High)。

_images/9.3.png

图7.4 FoveationRendering设置

方法二:打包之后,可以通过蓝图节点动态的修改Foveation Rendering的level(注意:打包前,必须勾选“Enable FoveationRendering”开启注视点渲染功能)。

_images/7.3.1.png 功能 获取Foveation Rendering等级
输入
输出 Foveation Rendering等级
返回值 True:成功,False:失败。
_images/7.3.2.png 功能 设置Foveation Rendering等级
输入 Foveation Rendering等级
输出
返回值 True:成功,False:失败。
_images/7.3.3.png 功能 设置Foveation Rendering参数
输入 Foveation Rendering控制参数
输出
返回值 True:成功,False:失败。
  • Foveation Gain:Vector2类型,X/Y轴方向外围像素的缩减率,值越大缩减的越多。
  • Foveation Area:float类型,以注视点为中心,以Foveation Area值为半径的范围内保持全分辨率。
  • Foveation Minimum:float类型,最小像素密度限制。
  • Foveation Level:提供了Low,Med,High,Top High四种预定义选择。每种级别对应了不同的Foveation参数。

注:除非开发者对“Foveation Rendering”技术有深入的了解,可以使用自定义参数来调整FFR优化细节,否则建议开发者使用官方预定义Level。SDK提供四种种Level:

Low [3.0f, 3.0f, 1.0f, 0.125f]

Med [4.0f, 4.0f, 1.0f, 0.125f]

High [6.0f, 6.0f, 1.0f, 0.0625f]

Top High [7.0f, 7.0f, 0.0f, 0.0625f]

7.4 用户权限验证

为了保护开发者内容的版权,SDK提供了用户权限验证功能,分别在内容研发调试阶段和正式发布到Pico应用商店提供用户权限验证。

功能入口:Project Setting -> Plugins -> PicoMobile -> Platform,勾选 User Entitlement Check选项。

用户权限验证不要求用户联网,SDK提供验证结果的返回码,但不会做额外处理,开发者需要在程序中自行处理验证失败的情况。 比如,如果收到“未成功”的结果,向用户展示失败原因并退出应用,或者进入Demo模式,提示用户去Pico应用商店购买完整版内容。

7.4.1 开发调试阶段模拟权限验证

在研发阶段,开发者通过在配置界面填入开发机SN号模拟用户权限验证过程,并增加验证失败后的处理逻辑,以测试效果。

确保User Entitlement Check选项勾选的前提下,勾选 Entitlement Check Simulation选项,开启开发调试阶模拟权限验证。 Device SN通过Project Setting->Plugins->PicoMobile->Platform中的Device SN Code List传入。

_images/9.4.png

图7.5 用户权限验证模拟

7.4.2 正式上线后的权限保护

通过AppID获取用户是否具有应用要求的权限。APPID是Pico开发者平台分配给应用的唯一识别ID,可通过 https://developer.pico-interactive.com/developer/overview 申请和查看。

在最新的SDK中,通过Project Setting->Plugins->PicoMobile->Platform下的App ID传入App ID,SDK在应用启动时执行权限验证。 开发者可以通过“Pico Entitlement Verify Set Callback Delegates”接口绑定代理来获取校验结果。

权限验证回调结果蓝图:

_images/7.4.2.1.png 功能 返回验证结果code
输入
输出
返回值

权限验证结果如下表所示:

Code 含义
0 成功
-2 服务不存在
-3 服务绑定失败
-4 捕获异常代码
-5 超时未收到服务返回值
10 单击Home键
11 APPID缺失
13 包名和APPID不匹配
20 用户未登录
21 用户未购买
31 未查询到此应用
32 购买SN号与本机SN号不匹配

注意: 模拟验证中填入SN号的开发机,在内容上线到Pico应用商店后,默认通过用户权限验证验证,不会再进行正式的权限验证。 如果需要开发机在应用上线后也进行正式的用户权限验证,请在编译正式版本时,关闭“Entitlement Check Simulation”。

7.5 MultiView

如果想要开启MultiView,需要进入Unreal Editor > Settings > Project Settings > Engine > Rendering > VR,然后选择Mobile Multi-View和Mobile Multi-View Direct两个。必须同时勾选以上两项才能起效。注意 : MultiView功能开启需要在OpenGL ES3.1条件下,OpenGL ES2 不支持MultiView。

_images/9.5.png

图7.6 开启MultiView

7.6 Pico VR Compositor Layers(StereoLayer)

StereoLayer是UE4引擎提供的Layer组件,在VR中,可将单独的纹理发送至VR头戴,并将其重新投射到和不同于项目其他内容的单独渲染通道中。

_images/9.6.png

图7.7 场景中的overlay

_images/9.7.png

图7.8 Stereo Layer相关属性

目前仅支持该组件的以下属性:Texture、Stereo Layer Type、Stereo Layer Shape、Priority、Left Texture、Quad Size。其他属性会在后续版本中逐渐实现。

如何创建一个StereoLayer:

1、 创建一个Pawn,可以拖入到level中。

2、 选择Pawn或者打开Pawn蓝图,添加Component中的Stereo Layer。

3、 Stereo Layer的属性中可以选择Stereo Layer Type有FaceLocked、WorldLocked、TrackerLocked,暂时FaceLocked与TrackerLocked效果相同。

4、 设置Stereo Layer Shape为Quad Layer。

5、 设置Property来确定多个layer的层级关系。

注:

建议不要把Stereo Layer添加到相机组件下。

建议使用正确的坐标位置关系放置模型和叠加层,否则会存在景深冲突,引起视觉不适。

7.7 Pico VR Splash Screen

SDK提供了一个在切换场景时显示一张贴图的方式,成为SplashScreen。开启SplashScreen共有两种方式,分别是通过项目设置和使用蓝图。

方式一:使用项目设置来开启SplashScreen:

打开项目设置,依次进入:Plugins->PicoMobile->SplashScreen(配置界面如下):

_images/9.8.png

图7.9 SplashScreen相关属性

属性名 属性作用
Enable Auto Show 是否自动显示(只有勾选了切场景是才会显示)
Texture Path 贴图
Transform in Maters 贴图显示的Transform属性,单位为米
Quad Size in Maters 显示贴图四边形的大小

表7.1Pico VRSplashScreen属性解读

方式二:使用蓝图来开启SplashScreen:

_images/7.7.1.png 功能 清除SplashScreen当前的属性配置(会设置为不自动显示)
输入
输出
返回值
_images/7.7.2.png 功能 设置是否自动显示SplashScreen
输入 是否自动显示
输出
返回值
_images/7.7.3.png 功能 设置SplashScreen属性
输入 Texture、Translation in Meters、Rotation、Size in Maters、 Auto Show(属性含义见表7.1)
输出
返回值

7.8 Platform系统

SDK继承了Unreal的OnlineSubsystem模块,实现了其中的部分功能,并开放给开发者。该模块的功能,暂时只支持成就系统。

需要使用Pico提供的OnlineSubSystem模块,需要进行以下步骤

  • Step1:启用Online SubSystem Pico 插件
_images/7.10.png

图7.10 开启Online Subsystem Pico 插件

  • Step2:关闭Plugin->Online Platform 下除Online Subsystem、Online Subsystem Utils插件外的其他插件
  • Step3:在[ProjectDirectory]/Config/Android/ 路径下新建AndroidEngine.ini文件,并添加以下内容:
[OnlineSubsystem]
DefaultPlatformService=Pico
  • Step4:在[ProjectDirectory]/Source/[ProjectName]/ProjectName.Build.cs文件中添加以下内容来加载必要引擎模块
PublicDependencyModuleNames.AddRange(new string[]{"OnlineSubsystem", "OnlineSubsystemPico" });
  • 7.8.1 成就系统

开发者需要登录开发者平台https://developer.pico-interactive.com/,在管理中心中进行成就的定义,具体步骤如下:

  1. 点击“查看”进入应用详情页。如果您还没有任何应用,请先“创建应用”。
_images/7.11.png

图7.11 开发者平台

  1. 在详情页面底部找到并点击“平台服务配置 – 成就”。
_images/7.12.png

图7.12 开发者平台

  1. 在成就页面可以看到您已创建的所有成就。如果您还没有任何成就,请点击“创建”。
_images/7.13.png

图7.13 开发者平台

  1. 按要求填写成就的信息。填入的API 名称必须代码中的保持一致。
_images/7.14.png

图7.14 开发者平台

以下为成就部分的接口说明:

1、 初始化接口:

FOnlineSubsystemPico::InitWithAndroidPlatform(FPicoInitOnCompleteDelegate&& Delegate)

该接口为成就系统的初始化接口,调用该接口,可对成就系统进行初始化,接口传入一个Delegate,返回初始化是否成功。调用该接口需要用户在PUI中登录自己的账号,并需要开发者在Project -> PicoMobile -> Platform中填入其中的对应参数(详见8.11章节)。为防止应用在后台是用户切换账户,该接口要求开发者在每次Resume都需要调用一次。 调用示例如下:

void UAchievementWidgetClass::InitPicoOnlineSubSystem()
{
    OnlineSubsystemPico*PicoSubsystem=static_cast<FOnlineSubsystemPico*>(IOnlineSubsystem::Get());
    if (PicoSubsystem)
    {
        PicoSubsystem->InitWithAndroidPlatform(FPicoInitOnCompleteDelegate::CreateUObject(this, &UAchievementWidgetClass::OnInitPicoSubSystemComplete));
    }
}
void UAchievementWidgetClass::OnInitPicoSubSystemComplete(bool Result)
{
}

注意:以下接口,部分接口不要求先调用初始化接口,部分接口要求初始化,对于需要初始化的接口,仅需整体初始化一次。

2、 向服务器请求所有成就定义并缓存到本地

IOnlineAchievements::QueryAchievementDescriptions(const FUniqueNetId& PlayerId, const FOnQueryAchievementsCompleteDelegate& Delegate)将定义的所有成就的信息缓存到本地,Delegate返回请求是否成功。调用该接口,不需要事先调用初始化接口。调用实例如下:

void UAchievementWidgetClass:: QueryAchievement()
{
    auto AchievementInterface = Online::GetAchievementsInterface();
    auto UserID = new FUniqueNetIdPico(0);
    if (AchievementInterface)
    {
        AchievementInterface->QueryAchievements(*UserID, FOnQueryAchievementsCompleteDelegate::CreateUObject(this, &UAchievementWidgetClass::OnQueryAchievementComplete));
    }
}

void UAchievementWidgetClass:: OnQueryAchievementComplete (const FUniqueNetId& PlayerId, const bool bWasSuccessful)
{

}

3、 向服务器请求所有成就进度并缓存到本地

IOnlineAchievements::QueryAchievements( const FUniqueNetId& PlayerId, const FOnQueryAchievementsCompleteDelegate& Delegate)接口可以将所有成就的进度信息缓存到本地,Delegate返回请求是否成功。调用该接口,需要事先调用初始化接口和QueryAchievementDescriptions接口。调用示例如下:

void UAchievementWidgetClass:: QueryAchievement()
{
    auto AchievementInterface = Online::GetAchievementsInterface();
    auto UserID = new FUniqueNetIdPico(0);
    if (AchievementInterface)
    {
        AchievementInterface->QueryAchievements(*UserID, FOnQueryAchievementsCompleteDelegate::CreateUObject(this, &UAchievementWidgetClass::OnQueryAchievementComplete));
    }
}

void UAchievementWidgetClass:: OnQueryAchievementComplete (const FUniqueNetId& PlayerId, const bool bWasSuccessful)
{

}

4、 修改成就进度

IOnlineAchievements::WriteAchievements(const FUniqueNetId& PlayerId, FOnlineAchievementsWriteRef& WriteObject, const FOnAchievementsWrittenDelegate& Delegate) 接口可以修改成就的完成进度。通过WriteObject传入需要修改的成就的名字与要修改的进度,Delegate返回请求是否成功。调用该接口,需要事先调用初始化接口和QueryAchievementDescriptions接口。调用示例如下:

void UAchievementWidgetClass::WriteAchievement(FString AchievementName, int32 Value)
{
    auto AchievementInterface = Online::GetAchievementsInterface();
    auto UserID = new FUniqueNetIdPico(0);
    if (AchievementInterface)
    {
        FOnlineAchievementsWritePtr WriteObject = MakeShareable(new FOnlineAchievementsWrite());
        WriteObject->SetIntStat(*AchievementName, Value);
        FOnlineAchievementsWriteRef WriteObjectRef = WriteObject.ToSharedRef();
        AchievementInterface->WriteAchievements(*UserID, WriteObjectRef,
            FOnAchievementsWrittenDelegate::CreateUObject(
                this, &UAchievementWidgetClass::OnAchievementsWritten));
    }
}

void UAchievementWidgetClass:: OnAchievementsWritten(const FUniqueNetId& PlayerId, const bool bWasSuccessful)
{

}

5、 获取缓存到本地的所有成就的进度

IOnlineAchievements::GetCachedAchievements(const FUniqueNetId& PlayerId, TArray<FOnlineAchievement>& OutAchievements) 接口可以获取缓存到本地的所有成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下:

auto AchievementInterface = Online::GetAchievementsInterface();
auto UserID = new FUniqueNetIdPico(0);
TArray<FOnlineAchievement>Achievements;
if (AchievementInterface)
{
    auto State = AchievementInterface->GetCachedAchievements(*UserID, Achievements);
}

6、 通过成就名称获取缓存到本地的成就进度

IOnlineAchievements:: GetCachedAchievement(const FUniqueNetId& PlayerId, const FString& AchievementId, FOnlineAchievement& OutAchievement)接口可以通过名字获取缓存到本地的成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下:

auto AchievementInterface = Online::GetAchievementsInterface();
auto UserID = new FUniqueNetIdPico(0);
FOnlineAchievement Achievement;
if (AchievementInterface)
{
    auto State = AchievementInterface->GetCachedAchievement(*UserID, AchievementName, Achievement);
}

7、 通过成就名称获取缓存到本地的成就定义

IOnlineAchievements::GetCachedAchievement( const FUniqueNetId& PlayerId, const FString& AchievementId, FOnlineAchievement& OutAchievement)接口可以通过名字获取缓存到本地的成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下:

auto AchievementInterface = Online::GetAchievementsInterface();
auto UserID = new FUniqueNetIdPico(0);
FOnlineAchievement Achievement;
if (AchievementInterface)
{
    auto State = AchievementInterface->GetCachedAchievement(*UserID, AchievementName, Achievement);
}