一、简述
PICO4 Ultra更新了空间网格能力,可以实时动态扫描现实场景,然后将场景中的内容转换成空间网格。通过对网格数据进行处理,将其保存为OBJ格式模型文件,并可以导入Unity 3D引擎中进行预览。
二、环境配置
1、Unity环境
开发所用Unity版本为2022.3.36f1c1,采用Unity的通用渲染管线(Universal Render Pipeline,URP)进行开发。
说明:本功能不局限于渲染管线,内置渲染管线一样使用,为了后续拓展其他功能,故此采用通用渲染管线。
2、SDK版本
PICO SDK版本为3.1.0,URP版本为14.0.11。
三、实现过程
1、创建项目
为了便于操作,可以直接创建URP 3D项目。

2、搭建XR环境
手动搭建参见:创建XR环境,也可以直接通过PICO Building Blocks一键完成搭建,这里需要分别配置好手柄追踪和手柄画布交互。
3、XR设置
(1)修改为地面追踪
将XR Origin的Tracking Origin Mode修改为Floor,并重置子物体Camera Offset的Position为零。


(2)开启空间网格能力
按照图示设置PXR_Manager。

Video Seethrough勾选来使用视频透视能力;Spatial Mesh勾选来使用空间网格能力,LOD用来设置网格精细度;MR Safeguard勾选来使用MR安全防护能力,此选项可以屏蔽掉VR模式的安全边界限制。
顺便说一下,Stage Mode选项勾选后可以屏蔽掉手柄Home键的长按校准视角功能。
(3)视频透视配置
修改相机参数,将Main Camera的Background Type修改为Solid Color,R、G、B、A数值都改为0。


(4)Project Validation设置
Project Validation可以帮助我们快速进行一些XR环境的配置,打开Edit-->Project Settings-->XR Plug-in Management-->Project Validation,分别点击警告信息右侧的Fix进行处理。

注意:
由于3.1.0版本SDK中遇到打包后左眼闪烁异常,所以以下几点请注意下。
1)不要直接Fix All;
2)上图是配置之后剩余的两项配置;
3)上图剩余两项配置可保留不处理,经测试,Fix后出现打包后左眼闪烁异常。
4、工程设置
(1)可编程渲染管线设置
在Project Settings内,将Graphics选项下的Scriptable Render Pipeline Settings修改为URP-Balanced(项目创建后默认是URP-HighFidelity)。

(2)Quality设置
将安卓平台的渲染质量等级修改为Balanced(项目创建后默认就是Balanced,若不是修改为该选项)。

(3)其他打包设置
请参见:完成项目配置。
5、挂载空间网格管理脚本
创建空物体,挂载PXR_SpatialMeshManager脚本。

此脚本有一个Mesh Prefab变量,Mesh Prefab 至少需要包含 Mesh Filter 组件。如果想显示扫描到的网格,则还需包含 Mesh Renderer 组件。另外,如果想做碰撞交互,还需要包含Mesh Collider组件。

这里,创建一个材质赋值于Mesh Prefab,着色器选择PICO自带网格着色器,并按照以下设置着色器参数。

6、网格处理工具类
这里,创建了两个网格处理工具类,分别进行合并式网格和分离式网格导出OBJ模型文件。详细源码见演示视频置顶评论区。
合并式导出的模型结构如下:

分离式导出的模型结构如下:

7、交互管理类
交互管理类用于处理UI交互及网格处理工具类方法的调用。代码如下。
cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScanModelingManager : MonoBehaviour
{
public static ScanModelingManager instance = null;
public Transform spatialMeshParent; //空间网格生成的父物体,即挂载PXR_SpatialMeshManager脚本的物体
public Button saveMeshButton; //保存按钮
public Text infoText; //信息文本
public string exportFileName = "SpatialMesh.obj"; //Obj文件名
public bool isMergeMesh = true; //是否导出合并的Mesh
public Toggle mergeMeshToggle; //合并网格设置Toggle
private List<MeshFilter> spatialMeshes = new List<MeshFilter>();//扫描生成的空间网格的MeshFilter组件列表
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
//按钮事件
saveMeshButton.onClick.AddListener(() =>
{
SaveMesh();
});
//开始默认合并网格
isMergeMesh = mergeMeshToggle.isOn;
//Toggle事件
mergeMeshToggle.onValueChanged.AddListener((bool isMerge) =>
{
SetMergeMesh();
});
}
//保存Mesh
private void SaveMesh()
{
//infoText.text = spatialMeshParent.childCount.ToString();
MeshFilter[] meshFilters = spatialMeshParent.GetComponentsInChildren<MeshFilter>();
spatialMeshes = new List<MeshFilter>(meshFilters);
// 获取所有需要导出的网格
var validMeshes = spatialMeshes.FindAll(m => m != null && m.mesh != null);
// 执行导出
if (isMergeMesh)
{
exportFileName = "MergedSpatialMesh.obj";
//合并Mesh后导出
MergeMeshExporter.ExportMeshes(validMeshes, exportFileName);
}
else
{
exportFileName = "IndividualSpatialMesh.obj";
//单独进行Mesh导出
IndividualMeshExporter.ExportMeshes(validMeshes, exportFileName);
}
}
//设置是否合并导出
public void SetMergeMesh()
{
isMergeMesh = mergeMeshToggle.isOn;
}
}
8、UGUI设计
在Unity编辑器里创建一个Button、Toggle及Text,分别用来保存网格数据、选择是否合并网格及显示保存提示。


四、效果演示及教程
教程\]PICO4 Ultra MR开发 空间网格扫描 模型导出及预览