🎥

Reality Composer Pro のカメラの位置と回転を iOS 18 の RealityView に適応させる

2024/12/23に公開

RealityView

visionOS のみで使用可能だった RealityView が iOS 18 で使用可能になり、
基本的には ARKit とともに使用するものだが、ARView の カメラの設定 .nonAR と同様に AR 以外の 3D コンテンツでも扱うことができるようになった。

RealityView はコードで Entity を追加してシーンを作る方法と、Reality Composer Pro でシーンを作成しコードでシーンを追加する方法の 2 種類。

だだ、問題があって RealityView で Apple Vision Pro や AR 以外の 3D コンテンツを作成する場合、シーンを映すカメラを設置する必要があるが、現状 Reality Composer Pro では視覚的に設定することができずコードで書く必要がある。

そのため、Blender などの 3DCG DCC ツールなどで位置や回転の値をコピーし設定することができるが面倒ではある。

Reality Composer Pro からがんばってカメラの位置や回転を取得する

Reality Composer Pro で 3D モデルなどをレイアウトした際に表示しているカメラの位置や回転を取得できたら楽できそう。
ということで、Reality Composer Pro からがんばってカメラ設定を取得してみる。

手順としては以下の 3 点

  • Reality Composer Pro でカメラの位置や回転をカメラプリセットとして保存する
  • Reality Composer Pro の保存データ rkasset からカメラプリセットのデータを取得
  • RealityView でカメラの設定を行う

Reality Composer Pro で表示しているカメラの位置や回転を保存する

Reality Composer Pro では現在表示しているカメラの位置や回転をプリセットとして保存することができる。

Viewport > Camera Presets > Save Presets をクリックしカメラの位置や回転を保存。

Camera Presets

Save Presets

カメラプリセットを保存することによって、ビューポートをクリックやタップからの操作でカメラの設定変更後、先ほど保存したカメラプリセットを Viewport > Camera Presets で呼び出すと保存した位置や回転に戻すことができる。

Preset

Reality Composer Pro の保存データ rkasset からカメラプリセットのデータを取得する

Reality Composer Pro の保存データは rkasset ファイルとして Swift Package Manager 形式として保存され、
rkasset ファイルは、パッケージ設定の Package.swift や USD やテクスチャ、Reality Composer Pro の設定ファイル Package.realitycomposerpro が存在する

rkasset ファイル

Package.realitycomposerpro を「パッケージを展開する」や VSCode などでみると WorkspaceData のフォルダに Settings.rcprojectdata があり、
ここにカメラプリセットの値があるため、transform のパラメータをコピーして Xcode でコードを書く。

Settings.rcprojectdata

{
  "cameraPresets" : {
    "844F0B72-5434-4ED2-99AC-E75DF101CC31" : [
      {
        "date" : 756636274.765971,
        "title" : "Preset",
        "transform" : [
          0.85786504,
          -0.0007317257,
          -0.5138746,
          0,
          -0.1574032,
          0.9515578,
          -0.26412472,
          0,
          0.48917472,
          0.3074689,
          0.81619304,
          0,
          0.63515496,
          0.57381564,
          1.3330741,
          1
        ]
      }
    ]
  },
  "secondaryToolbarData" : {
    "isGridVisible" : true
  },
  "unitDefaults" : {
    "kg" : "g",
    "kg⋅m²" : "kg⋅m²",
    "m" : "cm",
    "m\/s" : "m\/s",
    "m\/s²" : "m\/s²",
    "s" : "s",
    "°" : "°"
  }
}

ちなみにカメラの transform の値は、以下の値が初期値で、-Z軸方向がカメラレンズの向きになる点は注意が必要。
(Settings.rcprojectdata の transform パラメーターを全て 0 にすると表示がおかしくなるので注意)

// 1, 0, 0, 0
// 0, 1, 0, 0
// 0, 0, 1, 0
// 0, 0, 0, 1

"transform" : [
  1,
  0,
  0,
  0,
  0,
  1,
  0,
  0,
  0,
  0,
  1,
  0,
  0,
  0,
  0,
  1
]

RealityView でカメラの設定を行う

  • float4x4 にカメラプリセットの値を設定
  • PerspectiveCamera() を使用しカメラの Entity を設定
  • RealityView へカメラの Entity を設定する(ここでは content の add でカメラを追加している)

以下、コード

struct ContentView : View {
    var body: some View {
        RealityView { content in
            if let scene = try? await Entity(named:"Scene", in: rCPCameraPositionBundle){
                content.camera = .virtual
                
                let cameraPosision = float4x4(
                    [0.85786504, -0.0007317257, -0.5138746, 0],
                    [-0.1574032, 0.9515578, -0.26412472, 0],
                    [0.48917472, 0.3074689, 0.81619304, 0],
                    [0.63515496, 0.57381564, 1.3330741, 1]
                )
                
                let camera = PerspectiveCamera()
                camera.name = "PerspectiveCamera"
                camera.transform = Transform(matrix: cameraPosision)
                // Reality Composer Pro のカメラの fieldOfView は約 90 度ぐらい?
                camera.camera.fieldOfViewInDegrees = 90
                content.add(camera)
                
                content.add(scene)
            }
        }
        .ignoresSafeArea()
        .background(Color.black)
    }
}

RealityView

その他

Settings.rcprojectdata を修正して Reality Composer Pro にカメラプリセットを追加する

Reality Composer Pro から RealityView のカメラを設定したということは、逆に Reality Composer Pro にパラメーターからカメラプリセットを追加することが可能である。
以下、Z軸 -1m にカメラがあるカメラプリセットをコードで追加した例。

注意点として Package.realitycomposerpro は Reality Composer Pro ファイルが閉じられたときに保存されるため、
Reality Composer Pro でファイルを開いている場合は、そのファイルを閉じてからテキスト編集を行う必要がある。

{
  "cameraPresets" : {
    "844F0B72-5434-4ED2-99AC-E75DF101CC31" : [
      {
        "date" : 756636274.765971,
        "title" : "Preset",
        "transform" : [
          0.85786504,
          -0.0007317257,
          -0.5138746,
          0,
          -0.1574032,
          0.9515578,
          -0.26412472,
          0,
          0.48917472,
          0.3074689,
          0.81619304,
          0,
          0.63515496,
          0.57381564,
          1.3330741,
          1
        ]
      },
      {
        "date" : 756636274.765971,
        "title" : "Preset2",
        "transform" : [
          1,
          0,
          0,
          0,
          0,
          1,
          0,
          0,
          0,
          0,
          1,
          0,
          0,
          0,
          -1,
          1
        ]
      }
    ]
  },
  "secondaryToolbarData" : {
    "isGridVisible" : true
  },
  "unitDefaults" : {
    "kg" : "g",
    "kg⋅m²" : "kg⋅m²",
    "m" : "cm",
    "m\/s" : "m\/s",
    "m\/s²" : "m\/s²",
    "s" : "s",
    "°" : "°"
  }
}

カメラの位置と回転をコードから取得する

以下コード。
Transform に行列を設定した float4x4 を設定。
位置は translation、回転は rotation.axis の x, y, z から取得する。

Reality Composer Pro の Translation コンポーネントに適応する場合は、デフォルトの設定が cm と °(度/degree)になっているため、RealityView のデフォルトの単位である m と rad(radian)に変更してペーストする。

    let cameraPosision = float4x4(
            [0.85786504, -0.0007317257, -0.5138746, 0],
            [-0.1574032, 0.9515578, -0.26412472, 0],
            [0.48917472, 0.3074689, 0.81619304, 0],
            [0.63515496, 0.57381564, 1.3330741, 1] // ⚠️
        )

    let t: Transform = Transform(matrix: cameraPosision)

    // 位置 translation
    print("translation x: \(t.translation.x)") // 0.63515496
    print("translation y: \(t.translation.y)") // 0.57381564
    print("translation z: \(t.translation.z)") // 1.3330741

    // 回転 rotation.axis
    print("rotation x: \(t.rotation.axis.x)") // -0.49061152
    print("rotation y: \(t.rotation.axis.y)") // 0.86093944
    print("rotation z: \(t.rotation.axis.z)") // 0.13447462

行列で変更を行うため Transform を使用せずとも、
⚠️ の最初 3 つの値は位置で、回転は以下の方法でも取得できる。

    let q: simd_quatf = simd_quatf(cameraPosision)

    print("q x: \(q.axis.x)") // -0.49061152
    print("q y: \(q.axis.y)") // 0.86093944
    print("q z: \(q.axis.z)") // 0.13447462

注意点

PerspectiveCamera で設定したカメラは、表示時に RealityView のカメラ(_RealityKit_SwiftUI.RealityViewCamera)に設定される。
また、RealityView は現状カメラを複数設定できない。

RealityView の update 内で @Bindig の更新があり、.realityViewCameraControls モディファイアーを設定されている場合、PerspectiveCamera の位置や回転の値が正しく反映されない。

Discussion