【Apple Vision Pro】端末に保持した3Dモデルを配置する機能を実装する
こんにちは。
アプリ・データソリューショングループのyoshino.kです。
Apple Vision Proの標準機能だけでは、3Dモデルファイルを空間上に3D表示することはできません。
そこで、Apple Vision Pro内に保持した3Dモデルファイルを読み込んで、空間上に配置する機能を実装してみました。
今回はAppleが配布している3Dモデルファイルを使用しています。
目次
実装した機能のデモ動画
アプリを起動すると、「3Dモデルを選択」ボタンを含むビューを表示しています。
ボタンを押すと表示されるファイル選択ビューから、配置したい3Dモデルファイルを選択します。
選択すると、対象の3Dモデルが読み込まれ、空間上に配置されます。
実装内容の解説
空間上にはボタンとRealityViewを配置したシンプルな構成にしています。
3Dモデルファイルの読み込みにはfileImporterを使用し、ボタンタップ時にファイル選択ビューを表示する実装にしています。
(allowsMultipleSelectionをtrueにすると複数ファイルの選択も可能になります。)
選択したファイルの読み込みについては、1点注意があるので触れておきます。
startAccessingSecurityScopedResource()メソッド
fileImporterで取得したファイルはアクセス制限がかかっており、そのままではアクセスできない場合があります。
ファイルの保存場所 | アクセス制限 |
---|---|
実装したアプリ内 | 制限なし |
実装したアプリ外(他のアプリ内、iCloud Drive内など) | 制限あり |
デモ動画ではファイルアプリ(他のアプリ)内のファイルを参照しているため、制限がかかっています。
制限がかかっている場合は、startAccessingSecurityScopedResource()メソッドを使うことで、一時的に対象ファイルへのアクセス権を得ることができます。
ファイル使用後は、stopAccessingSecurityScopedResource()メソッドを呼び出し、ファイルシステムリソースへのアクセスを放棄します。
※放棄しないと、セキュリティリスクを孕んだ状態になる上、メモリリークを引き起こす可能性があります。
import SwiftUI
import RealityKit
import UniformTypeIdentifiers
struct ContentView: View {
@State private var isFileImporterPresented = false
@State private var modelEntity: ModelEntity? = nil
var body: some View {
VStack {
Button("3Dモデルを選択") {
isFileImporterPresented = true
}
RealityView { content in
// 初期描画時には何も表示しない
} update: { content in
// modelEntity が更新されたら追加
if let entity = modelEntity {
content.entities.removeAll()
content.add(entity)
}
}
.frame(width: 600, height: 600)
.padding()
}
.fileImporter(
isPresented: $isFileImporterPresented,
allowedContentTypes: [.usdz],
allowsMultipleSelection: false
) { result in
do {
let selectedURL: URL = try result.get().first!
// セキュリティスコープ付きリソースのアクセス
if selectedURL.startAccessingSecurityScopedResource() {
Task {
do {
// 非同期でModelEntityを読み込み
let entity = try await ModelEntity(contentsOf: selectedURL)
// 読み込んだModelEntityをStateに代入
modelEntity = entity
} catch {
print("ModelEntity読み込み失敗: \(error)")
}
selectedURL.stopAccessingSecurityScopedResource()
}
}
} catch {
print("ファイル選択失敗: \(error)")
}
}
}
}
さいごに
3Dモデルファイルを読み込んで空間上に配置する機能は、特殊な機能ではないですが使う機会は多いかと思います。
私は実装時に、アクセス制限のところでつまづいたので、アプリ外部のファイルを参照する場合にはご注意ください。
