.. _8 进阶功能: 8 进阶功能 ============================ 8.1 配置EyeBuffer大小 ----------------------------------------------------------- SDK支持响应Unreal的“vr.pixeldensity”命令,开发者可以通过该命令来配置EyeBuffer(RenderTexture)的大小。 使用方法: 方式一:打开文件 Project/Config/DefaultEngine.ini,然后在“[/Script/Engine.RendererSettings]”标签下添加字符串“vr.pixeldensity=1”,如果该命令等于一或者没有该命令,则EyeBuffer大小为Pico的默认大小,如果该值不等于一,则会在Pico默认的EyeBuffer大小的基础上进行缩放。如下图所示: .. image:: _static/8.1.png 图8.1 设置EyeBuffer大小 方式二:可以通过蓝图调用控制台命令实现该效果。使用节点“Execute Console Command”节点,调用“vr.pixeldensity 1”命令(命令中字符串和数字之间有一个空格)。同样数字部分为EyeBuffer的倍数。但是要保证该命令的执行必须足够早,建议放在关卡蓝图的EventBeginPlay后。 .. image:: _static/8.2.png 图8.2 设置EyeBuffer大小 For example, if you wanted to reduce the number of pixels to render of your VR project by about 20% you would set vr.PixelDensity=sqrt(1-0.2). If you wanted to increase the number of pixels to render of your VR project by about 20%, you would input vr.PixelDensity=sqrt(1+0.2). Tips: 建议开发者不做修改,仅在特殊需求场合使用自定义RenderTexture大小。对于该选项开发者必须了解以下两点: 1. RT设置过小,会带来性能的提升,减少延迟,但同时也导致了分辨率降低; 2. RT设置过大,会带来性能的降低,增加延迟,因此不建议RT设置超过硬件建议纹理尺寸; 推荐范围:0.5~2。 8.2 眼球追踪 ----------------------------------------------------------- Pico Neo3 Pro 设备支持眼球追踪, 眼球追踪可以追踪眼球注视位置,配合注视点渲染可以优化渲染性能。眼球追踪功能的开关在 项目设置 > 插件 > PicoXRSetting,勾选“EnableEyeTracking”即可打开眼球追踪功能。如图,在PicoXRSettings里设置 .. image:: _static/8.3.png 图8.3 眼球追踪 可以通过蓝图节点获取眼球的位置与方向,详细说明见7.4 Eye Tracking(眼球追踪)相关函数库。 8.3 注视点渲染 ----------------------------------------------------------- 注视点渲染(Foveation Rendering)可以优化VR场景的渲染,该技术通过为视野中心提供全分辨率(无损),降低周边视野(人眼焦点区域之外)分辨率的方式来达到优化渲染的目的。 这里提供了两种使用注视点渲染的方式: 方法一:在打包之前,可以在“ 项目设置 > 插件 > PicoXRSetting”中勾选“Enable FoveationRendering”开启注视点渲染功能,并在“Foveation Level”下拉框指定Level即可(SDK默认提供了4个Level:Low/Med/High/Top High)。 .. image:: _static/8.4.png 图8.4 FoveationRendering设置 方法二:打包之后,可以通过蓝图节点动态的修改Foveation Rendering的level(注意:打包前,必须勾选“Enable FoveationRendering”开启注视点渲染功能),详细说明见7.5 Foveation Rendering(注视点渲染)相关函数库。 8.4 应用版权保护 ----------------------------------------------------------- 为了配合开发者平台及应用商店对于开发者应用的版权保护,SDK需要在应用开发阶段及正式发布后进行许可校验,为开发者提供应用版权保护机制。 8.4.1 开发调试阶段模拟权限验证 ----------------------------------------------------------- Device SN通过Edit—>Plugins—> OnlinePicoSettings—>Platform传入,用于开发机模拟权限验证。 .. image:: _static/8.5.png 图8.5 版权校验模拟 8.4.2 AppID与Public Key权限验证 ---------------------------------------------------------------- AppID与Public Key权限验证通过调用“Pico Entitlement Verify App Delegate”蓝图接口实现,绑定回调事件后,通过回调可以获取版权验证结果,详细接口说明见 7.6 应用版权保护函数库章节。 **注意:** 模拟验证中填入SN号的开发机,在内容上线到Pico应用商店后,默认通过用户权限验证验证,不会再进行正式的权限验证。如果需要开发机在应用上线后也进行正式的用户权限验证,请在编译正式版本时,关闭“Entitlement Check Simulation”。 权限验证回调结果蓝图: 8.5 MultiView -------------------------------------------------------- 如果想要开启MultiView,需要进入Unreal Editor > Settings > Project Settings > Engine > Rendering > VR,然后选择Mobile Multi-View。 **注意 :** OpenGL ES2 不支持MultiView。 .. image:: _static/8.5.1.png 图8.6 开启MultiView 8.6 StereoLayer ---------------------------------------------------------- StereoLayer是UE4引擎提供的Layer组件,在VR中,可将单独的纹理发送至VR头戴,并将其重新投射到和不同于项目其他内容的单独渲染通道中。 .. image:: _static/8.6.1.png 图8.7 场景中的overlay .. image:: _static/8.6.2.png 图8.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添加到相机组件下。 建议使用正确的坐标位置关系放置模型和叠加层,否则会存在景深冲突,引起视觉不适。 8.7 Splash Screen ------------------------------------------- SDK提供了一个在切换场景时显示一张贴图的方式,成为SplashScreen。开启SplashScreen共有两种方式,分别是通过项目设置和使用蓝图。 方式一:使用项目设置来开启SplashScreen: 打开项目设置,依次进入:Plugins->PicoXR Settings->SplashScreen(配置界面如下): .. image:: _static/8.7.1.png 图8.9 SplashScreen相关属性 +---------------------------------------------------------+---------------------------------------------------------+ |属性名 |属性作用 | +---------------------------------------------------------+---------------------------------------------------------+ |Auto Show Splash Screen |是否自动显示(只有勾选了切场景是才会显示) | +---------------------------------------------------------+---------------------------------------------------------+ |Texture Path |贴图 | +---------------------------------------------------------+---------------------------------------------------------+ |Transform in Maters |贴图显示的Transform属性,单位为米 | +---------------------------------------------------------+---------------------------------------------------------+ |Quad Size in Maters |显示贴图四边形的大小 | +---------------------------------------------------------+---------------------------------------------------------+ 方式二:使用蓝图来开启SplashScreen,详细说明见 7.7 SplashScreen相关函数库。 8.8 Boundary(安全区) ------------------------------------------- Pico Neo设备,默认情况下是6Dof模式,为保护用户安全,我们开发了Boundary功能,该功能的作用就是在用户划定的范围内是安全区,视为安全区。当用户离开安全区时,头戴内会显示显示世界中的内容,以防用户撞伤或出现其他意外。 SDK中开放了一些关于Boundary功能的相关接口,详细接口说明见 7.8 Boundary(安全区)相关函数库。 8.9 Platform系统 ------------------------------------------- SDK继承了Unreal的OnlineSubsystem模块,实现了其中的部分功能,并开放给开发者。该模块的功能,暂时只支持成就系统。 需要使用Pico提供的OnlineSubSystem模块,需要进行以下步骤 - Step1:启用Online SubSystem Pico 插件 .. image:: _static/8.9.1.png 图8.10 开启Online Subsystem Pico 插件 - Step2:关闭Plugin->Online Platform 下除Online Subsystem、Online Subsystem Utils插件外的其他插件 - Step3:在[ProjectDirectory]/Config/Android/ 路径下新建AndroidEngine.ini文件,并添加以下内容: .. code-block:: ini [OnlineSubsystem] DefaultPlatformService=Pico - Step4:在[ProjectDirectory]/Source/[ProjectName]/ProjectName.Build.cs文件中添加以下内容来加载必要引擎模块 .. code-block:: c++ PublicDependencyModuleNames.AddRange(new string[]{"OnlineSubsystem", "OnlineSubsystemPico" }); - Step5:在项目设置->插件->OnlinePicoSettings->Payment下,填写所有信息(Is Foreign、Merchant ID、App ID、App Key、Pay Key)。 8.9.1 成就系统 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **准备工作** 开发者可以从管理中心进入到创建应用阶段,点击创建应用,然后进入相应平台完善应用的相关信息。 开发者在接入成就系统时,需要在开发者平台创建应用并获取相应字符串。 申请流程如下: - 1. 在 `Pico 开发者平台`_ 页点击 `成为开发者`_ 按钮。 .. _Pico 开发者平台: https://developer.pico-interactive.com/ .. _成为开发者: https://devcenter.pico-interactive.com/#/organization - 2. 申请成为开发者 - 3. 创建应用 - 4.创建成就信息 点击 **查看** 进入应用详情页。如果您还没有任何应用,请先 **创建应用**。 开发者在接入成就系统时,需要在开发者平台创建应用并获取 **应用参数** ,对应流程如下: 在 **平台服务** 菜单找到并点击 **成就** 。 .. image:: _static/8.9.1.1.png 图8.9.1 开发者平台 在成就页面可以看到您已创建的所有成就。如果您还没有任何成就,请点击 **创建**。 按要求填写成就的信息。填入的API 名称(即API Name)必须代码中的保持一致。 成就类型说明: - 简单类型:通过单个事件或目标完成来解锁,无成就进展 - 计数器类型:到达指定目标个数时解锁(e.g. 完成5个解锁,target=5) - 位域类型:到达指定范围的指定目标个数时解锁(e.g. 完成指定7个目标中的3个解锁,Target=3,Bitfield Length=7) **注意:** 由于int32的长度限制,比特位类型的成就比特位长度不能超过10,计数类型的成就目标值不能超过2147483648。 **接口调用** **使用注意事项:** - 请先使用Pico账号登陆设备,再使用成就接口和功能。 - 为了避免由于设备账号切换、退登导致的成就数据出现误差,请在应用Resume()中重新调用一次初始化,以确保应用获取正确的用户登陆信息。 - 开发调试阶段可以通过以下方式调试和测试: - Logcat; - 通过开发者平台-应用-成就信息页查看数据。 1、 初始化接口: .. code-block:: c++ FOnlineSubsystemPico::InitWithAndroidPlatform(FPicoInitOnCompleteDelegate&& Delegate) 该接口为成就系统的初始化接口,调用该接口,可对成就系统进行初始化,接口传入一个Delegate,返回初始化是否成功。调用该接口需要用户在PUI中登录自己的账号,并需要开发者在Project -> PicoXR Settings-> Platform中填入其中的对应参数(详见 **准备工作** )。为防止应用在后台是用户切换账户,该接口要求开发者在每次Resume都需要调用一次。调用示例如下: .. code-block:: c++ void UAchievementWidgetClass::InitPicoOnlineSubSystem() { OnlineSubsystemPico*PicoSubsystem=static_cast(IOnlineSubsystem::Get()); if (PicoSubsystem) { PicoSubsystem->InitWithAndroidPlatform(FPicoInitOnCompleteDelegate::CreateUObject(this, &UAchievementWidgetClass::OnInitPicoSubSystemComplete)); } } void UAchievementWidgetClass::OnInitPicoSubSystemComplete(bool Result) { } **注意:** 以下接口,部分接口不要求先调用初始化接口,部分接口要求初始化,对于需要初始化的接口,仅需整体初始化一次。 2、 向服务器请求所有成就定义并缓存到本地 .. code-block:: c++ IOnlineAchievements::QueryAchievementDescriptions( const FUniqueNetId& PlayerId, const FOnQueryAchievementsCompleteDelegate& Delegate) 该接口将定义的所有成就的信息缓存到本地,Delegate返回请求是否成功。调用该接口,不需要事先调用初始化接口。调用实例如下: .. code-block:: c++ void UAchievementWidgetClass::QueryDescriptions() { auto AchievementInterface = Online::GetAchievementsInterface(); auto UserID = new FUniqueNetIdPico(0); if (AchievementInterface) { AchievementInterface->QueryAchievementDescriptions(*UserID, FOnQueryAchievementsCompleteDelegate::CreateUObject(this, &UAchievementWidgetClass::OnQueryDescriptionsComplete)); } } void UAchievementWidgetClass::OnQueryDescriptionsComplete(const FUniqueNetId& PlayerId, const bool bWasSuccessful) { } 3、 向服务器请求所有成就进度并缓存到本地 .. code-block:: c++ IOnlineAchievements::QueryAchievements( const FUniqueNetId& PlayerId, const FOnQueryAchievementsCompleteDelegate& Delegate) 该接口可以将所有成就的进度信息缓存到本地,Delegate返回请求是否成功。调用该接口,需要事先调用初始化接口和QueryAchievementDescriptions接口。调用示例如下: .. code-block:: c++ 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、 修改成就进度 .. code-block:: c++ IOnlineAchievements::WriteAchievements(const FUniqueNetId& PlayerId, FOnlineAchievementsWriteRef& WriteObject, const FOnAchievementsWrittenDelegate& Delegate) 该接口可以修改成就的完成进度。通过WriteObject传入需要修改的成就的名字与要修改的进度,Delegate返回请求是否成功。调用该接口,需要事先调用初始化接口和QueryAchievementDescriptions接口。调用示例如下: .. code-block:: c++ 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、 获取缓存到本地的所有成就的进度 .. code-block:: c++ IOnlineAchievements::GetCachedAchievements(const FUniqueNetId& PlayerId, TArray& OutAchievements) 该接口可以获取缓存到本地的所有成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下: .. code-block:: c++ auto AchievementInterface = Online::GetAchievementsInterface(); auto UserID = new FUniqueNetIdPico(0); TArrayAchievements; if (AchievementInterface) { auto State = AchievementInterface->GetCachedAchievements(*UserID, Achievements); } 6、 通过成就名称获取缓存到本地的成就进度 .. code-block:: c++ IOnlineAchievements::GetCachedAchievement(const FUniqueNetId& PlayerId, const FString& AchievementId, FOnlineAchievement& OutAchievement) 该接口可以通过名字获取缓存到本地的成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下: .. code-block:: c++ auto AchievementInterface = Online::GetAchievementsInterface(); auto UserID = new FUniqueNetIdPico(0); FOnlineAchievement Achievement; if (AchievementInterface) { auto State = AchievementInterface->GetCachedAchievement(*UserID, AchievementName, Achievement); } 7、 通过成就名称获取缓存到本地的成就定义 .. code-block:: c++ IOnlineAchievements::GetCachedAchievement( const FUniqueNetId& PlayerId, const FString& AchievementId, FOnlineAchievement& OutAchievement) 该接口可以通过名字获取缓存到本地的成就的进度。调用该接口,需要事先调用初始化接口与QueryAchievements接口。调用示例如下: .. code-block:: c++ auto AchievementInterface = Online::GetAchievementsInterface(); auto UserID = new FUniqueNetIdPico(0); FOnlineAchievement Achievement; if (AchievementInterface) { auto State = AchievementInterface->GetCachedAchievement(*UserID, AchievementName, Achievement); } 8.10 配置屏幕刷新率 ------------------------------------------- SDK提供配置屏幕刷新率的功能,通过设置Display Refresh Rates相关选项来进行配置,配置方式如下: 1. Default:系统默认 2. RefreshRate72:刷新率上限72hz 3. RefreshRate90:刷新率上限90hz .. image:: _static/8.10.1.png 图8.15 屏幕刷新率设置 8.11 大空间(Large Space) ------------------------------------------- **使用场景:** 将一台头戴创建的安全区,导出给其它头戴使用。支持最大面积10m*10m。 **适用设备:** Pico Neo 3 Pro/Pico Neo 3 Pro Eye **使用流程:** 1. 用户使用一台头戴创建好地图后,把地图导出、拷贝至其他设备中,可以调用PXR Save Large Space Maps接口保存大空间地图,PXR Export Maps接口导出大空间地图,PXR Import Maps接口导入大空间地图,接口详细说明见7.9 Large Space(大空间)相关函数库说明。其他设备可以共用这一套地图,处于统一坐标系中,且头戴不需要统一真实世界的某一个位置唤醒(头戴在真实世界中任一位置唤醒后,可以识别到地图,且虚拟场景中的位置与真实世界的位置一致,不会以头戴位置为坐标原点)。如下图: .. image:: _static/8.11.1.png 图 8.16 整体使用流程 2. 进入Edit->Project Settings…,展开Plugins子项下的OnlinePico Settings,先后勾选:“Use Pico Advance Interface”、“Enable Large Space”两个选项,开启应用支持大空间,如图 8.17所示。也可以在应用中调用**PXR Set Large Space Enable**蓝图接口,实时开启应用支持大空间,接口详细说明见7.9 Large Space(大空间)相关函数库说明 。 .. image:: _static/8.11.2.png 图 8.17 应用支持大空间设置 3. 应用中调用 **PXR Switch Large Space Scene** 蓝图接口,实时开启设备的大空间功能,接口详细说明见7.9 Large Space(大空间)相关函数库说明 。 8.12 MRC 混合现实捕捉 ------------------------------------------- 混合现实捕捉(MRC)允许您记录和分享虚拟现实内容。让真实人物直接进入虚拟场景,并代替虚拟形象,无缝地显示虚拟世界与真实人物的交互。 1. 首先对应用进行MRC的支持。适配新的SDK。 2. 安装Runtime和新的应用。先开启一次应用看应用是否正常启动。 3. 准备一部苹果12及以上的手机和5Gwifi,手机与头戴需处于同一WIFI下。 4. 在头戴中安装校准应用和新的录屏软件。 5. 手机中安装MRC测试版手机助手,头戴与手机需登录同一用户账号。 6. 根据手机助手的提示进行MRC视频录制。 说明:任何使用支持MRC的Pico UE SDK均可以使用MRC的功能。以下是目前MRC支持的UE版本。除以下版本,其他UE引擎版本均不可使用MRC功能。 +-----------------------------------+---------------------+-----------------------+---------------------------------+ | |4.24 |4.26 |4.27 | +-----------------------------------+---------------------+-----------------------+---------------------------------+ |OpenGL+Multi-View关闭 |支持 |支持 |支持 | +-----------------------------------+---------------------+-----------------------+---------------------------------+ |OpenGL+Multi-View开启 |支持 |开发者需修改Shader支持 |开发者需修改Shader支持 | +-----------------------------------+---------------------+-----------------------+---------------------------------+ |Vulkan+ Multi-View关闭 |支持 |支持 |支持 | +-----------------------------------+---------------------+-----------------------+---------------------------------+ |Vulkan+ Multi-View开启 |支持 |不支持 |不支持 | +-----------------------------------+---------------------+-----------------------+---------------------------------+ **注意:** 4.26及以后OpenGL下支持Multi-View,需修改引擎Shader。非源码版引擎即可修改。 文件名:Engine/Shaders/Private/MobileSceneCapture.usf .. code-block:: c++ Output.UV = UVs; } #if MOBILE_MULTI_VIEW Texture2DArray InTexture; #else Texture2D InTexture; #endif SamplerState InTextureSampler; void MainCopyPS( FScreenVertexOutput Input, out float4 OutColor : SV_Target0 ) { #if MOBILE_MULTI_VIEW float4 SceneColor = Texture2DArraySample(InTexture, InTextureSampler, float3(Input.UV, 0)); #else float4 SceneColor = Texture2DSample(InTexture, InTextureSampler, Input.UV); #endif OutColor = SceneColor; // FP16 DeviceZ is stored in SceneColor.A