visionOS Reality Composer Pro の試してみた
visionOS で 3Dコンテンツを作成するときには Reality Composer Pro を使用して作成するのですが、実際にどうやって作成しているのか、実際に試してみました。
RealityComposerProとは
VisionPro で 3D空間に3Dモデルを配置するには RealityComposerProを使用して簡単に配置をすることができます。
UnityやUnrealEngineのようなゲームエンジンのように3D空間上にオブジェクト(Entity)を配置し、オブジェクトに対してコンポーネントをつけることで、機能を付与することができます。
SwiftUI上ではこのRealityComposerProで作成したシーンを読み込むことで3D空間上にオブジェクトを配置することができます。
環境構築
visionOSの開発を行うには Xcodeのベータバージョンをダウンロードして使用する必要があります。
現在は beta5 があるのでそちらをインストールしています。
ダウンロードしたxidを展開して出てきたXcodeを開きvisionOSにチェックをinstallを行ってください。
ダウンロードしたXcodeを開きCreateProject
からvisionOS向けのプロジェクトを作成します。
次にプロジェクトの設定を行います。
空間上にオブジェクトを表示するので Initial Scene は Volume にします。
Immersive Space は バーチャル空間をどのように使用するかなのですが、今回はMixにして現実空間と一緒に表示されるようにします。
作成されたプロジェクトを開くとコードとプレビューの表示が一緒に表示されます。
プレビューの表示は選択しているファイルのView
が表示されている状態です。
試しに、ContentView
からImmersiveView
のファイルを選択すると表示が切り替わるのが確認できると思います。
再生し Enlarge RealityView Content
ボタンを押すと 球体の大きさが変わり、Show Immersive Space
ボタンを押すと空中に2つ球体が表示されるのが確認できます。
RealityComposerPro
表示されている球体は Reality Compooser Pro で設定され表示されています。
ContentView
では Reality Composer Pro で作成した realityKitContentBundle
にある Scene
という名前のシーンを読み込んでいます。
RealityView { content in
// Add the initial RealityKit content
if let scene = try? await Entity(named: "Scene", in: realityKitContentBundle) {
content.add(scene)
}
}
続いてImmersiveView
を見てみましょう。ImmersiveView
ではImmersive
という名前のシーンを読み込んでいます。
RealityView { content in
// Add the initial RealityKit content
if let scene = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(scene)
}
}
ではこの中身をReality Composer Proで確認してみましょう。
Packages/RealityKitContent/Package
を選択してOpen in Reality Composer Pro
を選択して Reality Composer Proを開きます。
Reality Composer Proを開くと球体が表示しているシーンが開きます。
このシーン上にEntityを配置することで空間にオブジェクトを設置していきます。
今は Immersiveのシーンが開いている状態なので球体が2つシーン上に配置されています。
Scene
シーンをダブルクリックして開くと ContentView
で表示している球体が1つのシーンが表示されます。
試しに Scene
にオブジェクトを追加してみましょう。
左下の+マークから Primitive Shape/Cube
を選択して 立方体を追加します。
Root以下に移動させ、球体の上に配置してみましょう。
セーブしてXcodeに戻り、ContentView
を選択すると立方体が追加されているのが確認できると思います。
Reality Composer Proで編集した内容をセーブすると自動的に Xcode 上でも反映されて確認することができます。
Component
次は Scene
にあるSphere
を選択してコンポーネントを確認してみましょう。
Transform
はかならずEntity
につくコンポーネントで位置、回転、大きさを表しています。
MaterialBinding
は使用するマテリアルを設定し、SpherePrimitive
は球体モデルのメッシュを表現しています。
Collision
は当たり判定を設定していおり、InputTarget
をつけることでヒットしたユーザーの入力イベントを検知できるようになります。
入力イベントは ContentView
の Gesture部分で設定しています。
ContentView
ではオブジェクトをクリックしても大きさが変わるようになっています。
.gesture(TapGesture().targetedToAnyEntity().onEnded { _ in
enlarge.toggle()
})
EntityCompoonentSystem
visionOSのコンポーネントはEntityComponentSystem
という仕組みで動作しています。
コンポーネントでEntityに情報を追加し、
システムの方でコンポーネントを元にどう動作するかを実装します。
それではコンポーネントとシステム作成してみましょう。
今回は並行移動させる機能を作っていきたいと思います。
Cube
を選択して 右下の AddComponent
を選択し、New Component
を選択します。
コンポーネントの名前を入力してコンポーネントを作成します。
これで作成したコンポーネントがCube
につきました。
Xcodeに戻り 作成したMoveComponent
を編集していきましょう。
MoveComponent
は Packages/RealityKitContent/Sources/RealityKitContent/MoveComponent
に作成されています。
今回は移動をさせるために velocity
をコンポーネントに追加しましょう。
SIMD
は ベクトルを表現するための型で 今回は3次元ベクトルの SIMD3<Float>
を使用しています。
import RealityKit
// Ensure you register this component in your app’s delegate using:
// MoveComponent.registerComponent()
public struct MoveComponent: Component, Codable {
var velocity : SIMD3<Float> = [0.0,0.0,0.0]
public init() {
}
}
RealityComposerPro
に戻ってMoveComponent
を確認してみると Velocityが追加されています。
奥に動くようにz
に -0.01 を入れておきましょう.
次にこれを動作させるためにMoveComponent
と同じ階層にシステムを作成します。
Xcodeに戻りRealityKitContent
を選択してNewFileを選択し、名前をMoveSystem
とします。
ファイルを作成したらMoveSystem
の中身を実装しましょう。
import RealityKit
public struct MoveSystem: System {
static let query = EntityQuery(where: .has(RealityKitContent.MoveComponent.self))
public init(scene: Scene) {
}
public func update(context: SceneUpdateContext) {
let entities = context.scene.performQuery(Self.query).map({ $0 })
if entities.isEmpty {
return
}
for entity in entities {
let moveComponent = entity.components[RealityKitContent.MoveComponent.self]!;
entity.transform.translation += moveComponent.velocity;
}
}
}
上から見ていくと query
ではシーンからどのコンポーネントを取得するかのクエリを定義しています。
今回は MoveComoponent
を取得して操作するためMoveComopnent
を取得するクエリを定義します。
static let query = EntityQuery(where: .has(RealityKitContent.MoveComponent.self))
シーンに対してクエリを指定して対象のEntityを取得してきます。
let entities = context.scene.performQuery(Self.query).map({ $0 })
取得したEntityからMoveComponent
を取得してtransform.translation
にvelocity
を足してあげます。
update
では毎フレーム処理が呼ばれるためvelocity
方向に位置が移動し続けます。
for entity in entities {
let moveComponent = entity.components[RealityKitContent.MoveComponent.self]!;
entity.transform.translation += moveComponent.velocity;
}
これでMoveSystem
の実装は完了です。
次に作成したコンポーネントとシステムを使用できるように登録しましょう。
まずは RealityComposerProTestApp
にinit
を追加します。
コンポーネントはregisterCompoonent
, システムはregisterSystem
で登録を行います。
import RealityKitContent
struct RealityComposerProTestApp: App {
init(){
RealityKitContent.MoveComponent.registerComponent()
RealityKitContent.MoveSystem.registerSystem()
}
var body: some Scene {
....
}
}
これでシステムとコンポーネントが動作するようになりました!
それでは動作を確認してみましょう。
立方体が奥へ進んでいくようになりました!
コンポーネントにしているため他のオブジェクトにコンポーネントをつけることで同じように動作させることができます。
球にもコンポーネントをつけてみましょう。
今度は手前に移動させるように z
に 0.01 を入れます。
ContentView
に戻って確認すると立方体と球が動いているのが確認できます。
まとめ
RealityComposerProを使用するとGUI上でシーンにオブジェクトを配置することができます。
また、ComponentとSystemを使用することでComponent単位で挙動を実装することが可能です。
これはUnityやUnrealなどのゲームエンジンに近い形でシーンを構築できるため便利でした。
今回は紹介しませんでしたが音の発生源を追加したり、ShaderGraphによってシェーダの作成も可能です。
RealityComposerPro使いこなしていきましょう!
(Unityでできるのであればそちらの方が良さそうですが・・)
書いた人
佐藤 寿樹
株式会社コナミデジタルエンタテインメントに入社し5年間ウイニングイレブンのオンライン実装に携わる。
その後、株式会社コロプラで9年間エンジニアとしてアプリ開発・運用を行い、位置情報やARを使用したARゲーム開発、OculusRiftやPSVRなどのVRゲーム開発を経験しMESONへ入社。
MESON Works
MESONの制作実績一覧もあります。ご興味ある方はぜひ見てみてください。
Discussion