将同事的送我的仙人掌转换成 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 官方推荐的拍摄场景和我的拍摄场景。

1

Apple 官方将物体放在一个会旋转的平台上,并且用上文中提及的应用自动拍照。我将仙人掌放在一个普通的凳子上,然后右手举着相机,尽可能保持不动,左手从底部托着等凳子,缓慢的手动旋转。

拍摄完成之后将照片导入 Mac,然后就开始处理这些照片了。

Show Me the Code

这里需要用到 Apple 提供的另一段相关的源代码,这段代码将在 Mac 运行,通过调用本文的主角 APIPhotogrammetrySession,在 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 上显示如下:

2

我用 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
    }

...

效果如图所示:

3

看起来还不错,但 Apple 官方的样例才是惊为天人,可以从「AR Quick Look」下载并使用 Apple 官方模型。

© 杜金珂。保留所有权利。未经杜金珂书面许可,严禁复制、转发并向公众展示。