Apple Vision Pro で3Dキャラクターに付いてきてもらう
「Apple Vision Pro」での3Dキャラクターに付いてきてもらう手順をまとめました。
前回
1. VRM を usdz に変換
「VRM」をusdzに変換する手順は、次のとおりです。
(1) モデルの準備。
「ニコニコ立体」から「ニコニコ立体ちゃん」をダウンロードします。
(2) Blenderを起動して「VRM Add-on for Blender」をインストール。
リポジトリからアドオンファイル (VRM_Addon_for_Blender-release.zip) をダウンロードし、Blenderの「プリファレンス→アドオン→インストール」でインストールし、チェックボックスで有効化します。
(3) Blenderのメニュー「ファイル → インポート → VRM」でニコニコ立体ちゃんのVRMファイル (AliciaSolid.vrm) をインポート。
(4) Blenderのメニュー「ファイル → エクスポート → FBX」で「AliciaSolid.fbx」という名前でエクスポート。
(5) 「Mixamo」を開き、「UPLOAD CHARACTER」で「AliceSolid.fbx」をアップロードし、アクション「Walking」を選択し、右下の「In Place」をチェックし、「DOWNLOAD」ボタンを押す。
「Walking.fbx」がダウンロードされます。
(6) 「Reality Converter」をダウンロードしてインストール。
(7) 「Reality Converter」を起動して、「Walking.fbx」をドラッグ&ドロップし、右側の「Material」で各マテリアルにテクスチャを設定。
VRMのマテリアルのテクスチャは、「VRMEditorTools」で取得できます。
(8) 「Reality Converter」のメニュー「ファイル→書き出す」で「Walking.usdz」で保存。
2. プロジェクトの作成
プロジェクトの作成手順は、次のとおりです。
(1) Xcodeの最新版をインストールして起動。
(2) 「Create New Project」で「visionOS」の「App」を選択。
(3) 「Initial Scene」に「Window」、「Immersive Space Render」に「RealityKit」、「Immersive Space」に「Mixed」を指定。
3. 3Dキャラクターについてきてもらう
3Dキャラクターについてきてもらう手順は、次のとおりです。
(1) 「Package.realitycomposerpro」ダブルクリックで「Reality Composer」を起動し、「Walking.usdz」のモデルを中央に配置し、デフォルトの球を削除。
(2)「AppleVisionPro.swift」を追加。
・AppleVisionPro.swift
import SwiftUI
import ARKit
@MainActor
class AppleVisionPro: ObservableObject {
let session = ARKitSession()
let worldTracking = WorldTrackingProvider()
func run() async {
if WorldTrackingProvider.isSupported {
do {
try await session.run([worldTracking])
} catch {
assertionFailure("Failed to run session: (error)")
}
}
}
func getTransform() async -> simd_float4x4? {
if let anchor = worldTracking.queryDeviceAnchor(atTimestamp: CACurrentMediaTime()) {
return anchor.originFromAnchorTransform
}
return nil
}
}
(3)「ImmersiveView.swift」を以下のように編集。
3Dキャラクターに、ユーザーの前方2.0の場所まで移動してもらいます。
・ImmersiveView.swift
import SwiftUI
import RealityKit
import RealityKitContent
import simd
struct ImmersiveView: View {
@ObservedObject var appleVisionPro = AppleVisionPro()
@State var entity: Entity?
private var timer = Timer.publish(every: 0.02, on: .main, in: .common).autoconnect()
var body: some View {
RealityView { content in
if let scene = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(scene)
// アニメーションを再生
if scene.availableAnimations.count > 0 {
scene.playAnimation(scene.availableAnimations[0].repeat())
}
entity = scene
}
}
.task() {
await appleVisionPro.run()
}
.onReceive(timer) { _ in
Task {
let transform = await appleVisionPro.getTransform()
if entity != nil && transform != nil{
let speed: Float = 0.01
// モデル位置
let modelPosition = SIMD3<Float>(entity!.position.x, entity!.position.y, entity!.position.z)
// ユーザー位置
let userPosition = SIMD3<Float>(transform!.columns.3.x, transform!.columns.3.y, transform!.columns.3.z)
// ターゲット位置
var translation = matrix_identity_float4x4
translation.columns.3.z = -2.0; translation.columns.3.y = -1.0
let targetTransform = simd_mul(transform!, translation)
let targetPosition = simd_make_float3(targetTransform.columns.3.x, targetTransform.columns.3.y, targetTransform.columns.3.z)
// 距離
let distance = length(targetPosition - modelPosition)
if distance > 0.5 {
// ターゲット位置に移動
let direction = normalize(modelPosition - targetPosition)
let movement = direction * speed
entity!.position -= movement
// ターゲットの方向を向く
let targetAngle = -atan2(direction.z, direction.x) - .pi / 2
let targetRotation = simd_quatf(angle: targetAngle, axis: [0, 1, 0])
entity!.orientation = simd_slerp(entity!.orientation, targetRotation, 0.5)
} else {
// ユーザー方向を向く
let direction = normalize(modelPosition - userPosition)
let angle = -atan2(direction.z, direction.x) - .pi / 2
entity!.orientation = simd_quatf(angle: angle, axis: [0, 1, 0])
}
}
}
}
}
}
#Preview {
ImmersiveView()
.previewLayout(.sizeThatFits)
}
(4) 実行。
参考
次回
この記事が気に入ったらサポートをしてみませんか?