将同事的送我的仙人掌转换成 3D 模型
2021 WWDC,Apple 在 RealityKit 框架下引入了新 API:PhotogrammetrySession
,通过这个 API,可以从不同角度拍摄物体,并且基于这些相片,生成一个可以用于 AR/VR 显示的 3D 模型。
最近我也收到一个来自同事的礼物,她家的仙人掌掉落下来的小仙人掌。于是我萌生了这个将仙人掌转换成 3D 模型的想法。
开始,拍照
Apple 对于这个新 API 提供了非常多的相关代码和文章。其中包括用于拍摄的应用的 源代码。
通过 Xcode 将这段源代码编译使其应用运行在 iPhone 上,可以对前期拍摄起到非常大的帮助作用。这个应用的主要功能是每隔一段时间自动拍摄一张相片,并且会记录相片的景深信息(注:必须使用至少拥有两个镜头的 iPhone 才可以使用这个应用,因为至少两个镜头才可以支持记录景深信息)。
在这个应用自动帮助我们拍摄的同时,我们只需要围绕着物体,缓慢移动镜头,完整的记录物体各个角度下的样子。关于拍照还有很多注意事项,比如最好拍摄 20 至 200 张相片,当前拍摄的物体的相片与上一张相片最好有 70% 以上的重合度,尽量在光线均匀的环境下拍摄,不要拍摄透明或者强烈反光的物体之类的。更多详细注意事项可以看《Capturing Photographs for RealityKit Object Capture》。
下图分别是 Apple 官方推荐的拍摄场景和我的拍摄场景。
Apple 官方将物体放在一个会旋转的平台上,并且用上文中提及的应用自动拍照。我将仙人掌放在一个普通的凳子上,然后右手举着相机,尽可能保持不动,左手从底部托着等凳子,缓慢的手动旋转。
拍摄完成之后将相片导入 Mac,然后就开始处理这些相片了。
Show Me the Code
这里需要用到 Apple 提供的另一段相关的 源代码,这段代码将在 Mac 运行,通过调用本文的主角 API PhotogrammetrySession
,在 Mac 上将所拍摄的物体生成为 3D 模型。
在开始使用 PhotogrammetrySession
之前,需要先创建一个 PhotogrammetrySession.Request
,这个 request 需要指定两个参数:URL
和 PhotogrammetrySession.Request.Detail
。他们分别表示最终输出 3D 模型的绝对地址和 3D 模型的精细程度,地址必须以 .usdz
后缀结尾,因为这是 3D 模型的格式名字,而精细程度则会影响 3D 模型的大小。
有了这个 request 之后就可以创建 PhotogrammetrySession
,在创建这个 session
时,也需要一个 URL
参数,用来表示用于生成 3D 模型的图片所在文件夹的绝对地址:
let outputUrl = URL(fileURLWithPath: "/Users/jake/Downloads/Cactus.usdz")
var request = PhotogrammetrySession.Request.modelFile(url: outputUrl, detail: .full)
let inputFolderUrl = URL(fileURLWithPath: "/Users/jake/Downloads/Cactus Images")
guard let session = try PhotogrammetrySession(input: inputFolderUrl) else { return }
在创建 session
时还可以加入 PhotogrammetrySession.Configuration
参数:
let config = Configuration()
config.featureSensitivity = .high
config.sampleOrdering = .sequential
config.isObjectMaskingEnabled = true
guard let session = try PhotogrammetrySession(input: inputFolderUrl, configuration:config) else { return }
其中 featureSensitivity
表示处理模型时的细致程度,sampleOrdering
表示模型的相片是否连续,可以用于提高处理速度,isObjectMaskingEnabled
好像表示是否将模型与模型所在的背景区隔开,应该也可以提高处理速度。但在我实际使用中,我发现这几个参数无论如何调整似乎都没什么差别,也有可能是因为这个 API 还处于测试版的原因。
最后调用 session
的 process(requests: [PhotogrammetrySession.Request])
方法,然后等待制作完成就可以啦。这里可以一次性处理多个 requset,就可以同时生成多个模型,节约时间。
session.process(requests: [request])
async {
do {
for try await output in session.outputs {
switch output {
case .processingComplete:
case .requestError(let request, let error):
case .requestComplete(let request, let result):
case .requestProgress(let request, let fractionComplete):
...
十几分钟之后
最后得到的模型在 Mac 上显示如下:
我用 iPhone 12 mini 一共给这个仙人掌拍了一百多张相片,使用的电脑是 2020 款 M1 芯片最低配金色 MacBook Air,按照 Apple 官方的说法,使用英特尔芯片的 MacBook 处理速度会更慢。我试着生成了好几种不同精度的模型,发现处理速度只跟相片数量有关,相片数量越多,处理时间越长,与模型精细程度等无关。
也许用带激光雷达的 iPhone 或者 iPad 拍摄相片,制作出来的 3D 模型效果会更好。
最后
在得到仙人掌的 3D 模型之后,通过使用 QLPreviewController
就可以很方便的在手机上显示出来:
override func viewDidAppear(_ animated: Bool) {
let previewController = QLPreviewController()
previewController.dataSource = self
present(previewController, animated: true, completion: nil)
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
guard let path = Bundle.main.path(forResource: "Cactus", ofType: "usdz") else {
fatalError("Couldn't find the supported input file.")
}
let url = URL(fileURLWithPath: path)
return url as QLPreviewItem
}
效果如图所示:
看起来还不错,但 Apple 官方的样例才是惊为天人,可以从「AR Quick Look」下载并使用 Apple 官方模型。
2021 年 7 月 24 日