-
XcodeによるReality Composer Pro 3の機能の拡張
Reality Composer Pro 3を活用して、より大規模で先進的な空間プロジェクトを構築しましょう。カスタムコンポーネントの編集、カスタムシステムの実行、独自のScriptGraphノードの構築を可能にするプロジェクト固有のプラグインを作成して、空間オーサリングワークフローを高度にコントロールする方法について解説します。
関連する章
- 0:00 - Introduction
- 2:00 - Extending the editor
- 4:51 - Custom components and systems
- 10:32 - Controlling the water surface
- 13:19 - Custom animation actions
- 17:12 - Custom Script Graph nodes
- 21:16 - Next steps
リソース
関連ビデオ
WWDC26
-
このビデオを検索
こんにちは Niklasです。 このセッションでは プラグインを使って Reality Composer Proを拡張する方法を紹介します アーティストや コンテンツ制作者が エディタで直接アセットを操作できるよう 素早くイテレーションして 多彩な3Dアプリや ゲームを構築する方法を紹介します この機能は 今年後半に利用可能になる予定です。
こちらはReality Composer Pro 3です。 RealityKit向けAppleのゲーム・ 3Dコンテンツエディタの最新版です。 このアップデート版では より大規模なシーンに対応し コンテンツを素早くイテレーションするための アーティスト向けワークフローや ヘッドセットでシーンをプレビューする 機能も備えています。
Reality Composer Pro 3の使い方については セッションをご覧ください 「Iterate your spatial scenes faster with Reality Composer Pro 3」 ぜひ確認してほしい もう1つのセッションが 「Design no-code games with Reality Composer Pro 3」です このセッションではコードを書かずに ゲームを構築する方法を紹介します Reality Composer Proのビジュアルスクリプト ツール Script Graphを使います このプレゼンテーションでは コードでできることを紹介します。 Xcodeでプラグインを構築して プロジェクト固有のコンテンツを Reality Composer Pro 3に公開する方法を説明します カスタムコンポーネントが エディタ内に表示され アーティストやデザイナーが 調整できるようになります。 例えばアーティストは 水位を変更したり 回転速度を変えて 大釜がリアルタイムに 反応するのを確認したりできます アプリのビルドやデプロイなしに 行えます。
まずエディタを拡張する 一般的な仕組みを説明します。 次にその仕組みを使って カスタムコンポーネントと カスタムシステムをエディタで動かす方法を紹介します また シーケンサーのタイムラインに 独自カスタムアニメーションを追加する方法も ご紹介します。 さらに Script Graph用の 独自カスタムノードを作成する方法も 説明します。
まず一般的な仕組みを確認しましょう Reality Composer Proの拡張と チームでの作業時の 仕組みについてです。 Chaparral Villageゲームで 進めていきます。 このゲームは デベロッパ、アーティスト、 デザイナーのチームが制作しました。 このゲームにはReality Composer Proの プロジェクトと Xcodeプロジェクトの両方があります。 エディタプロジェクトは主に アーティストやデザイナーが使って エクスペリエンスの コンテンツを作成します Xcodeプロジェクトはエンジニアが 最終アプリのビルドと アーティストがエディタでカスタムデータを 作成できるプラグインの開発に使います。
Reality Composer Proのプロジェクトと Xcodeプロジェクトはリンクされており エディタから直接アプリを 起動できます。
このリンクは自分のプロジェクトでも 設定できます ウィンドウ上部の シミュレーションバーを使います。 エディタプロジェクトとXcodeプロジェクトは 同じgitリポジトリに格納されています。 アーティストとエンジニアはローカルで 変更を加えてコミット・プッシュし チームの他のメンバーと共有します。
Reality Composer Pro 3に ファイルをインポートすると 内部データ形式に変換されて JSONファイルとして ディスクに保存されます。 gitの組み込みツールで 変更をマージできますが エディタにはカスタムマージツールも 付属しており 標準のgitマージよりも 競合を減らしてファイルをマージできます。 Reality Composer Pro 3から アプリにデータを取り込むには RealityKitのシリアライズ形式である Reality Fileとしてエクスポートします。
これらがどのように連携するかを 図で説明します。 Xcodeプロジェクトは 最終ゲームアプリをビルドし Reality Composer Pro 3向けの プラグインフレームワークも作成します。 Reality Composer Pro 3は ゲームのさまざまな3Dシーンを設定し オブジェクトを配置します。 RCPCustomComponents.frameworkは デベロッパが作成した コンポーネントとシステムを エディタで利用できるようにして
アーティストやレベルデザイナーが 編集できるようにし 動作を確認して コンテンツをインタラクティブに改善できます。
最終的にReality Composer Pro 3で 作成されたシーンは Reality Fileにエクスポートされ アプリにリンクされて ロードされます。
コードが更新されたら デベロッパは 新しいプラグインフレームワークをビルドして チーム全員が使えるようにするとともに 新しいアプリも作成します。 コンテンツが変更されたら 最終アプリでテストするために 新しいReality Fileをエクスポートします。 Xcodeプロジェクトには 2つのスキームが設定されています。 ChaparralVillageは 実際のアプリをビルドし RCPCustomComponentsは Reality Composer Pro 3の プラグインをビルドします。 プロジェクト内のすべての カスタムコンポーネントと カスタムシステムは この2つのスキームで共有されています。 どのように機能するか見てみましょう。
プラグインシステムを使って カスタムコンポーネントを作成し Reality Composer Proに公開します。 この大釜のエフェクトを アーティストと一緒に作りたいと思います。 ゲームでこの大釜は ポーションを混ぜるために使われ 水位をコントロールできるようにして 材料が追加されると 上下するようにします。 渦巻くエフェクトも追加したいので ポーションを混ぜる際に 水が回転するのが見えるようにしますが まずは水位の設定だけから 始めましょう。
これはScript Graphでも実現できます。 このようになります。 アップデートイベントで 水面エンティティを取得して 特定の位置に移動させます。 より高度なことをしたい場合は Script Graphではなく カスタムコンポーネントを使う方が 適切かもしれません。 Script GraphとカスタムSwiftコードは 同様のことができます どちらを使うかは 個人の好みによることが多いです。 ただし非常に大きなScript Graphは メンテナンスが難しくなるため コードに切り替える 良い理由になるかもしれません。 コードを使えば他のApple APIと 連携することもできます Script Graphでは利用できない SwiftUIなどです。 この大釜については 最終的には水位を他のシステムと 連携させたいと思っていて 表面に浮かぶ材料などと 連携させたいので コードで実装するのが適切です。 これを実現するために まず簡単なコンポーネントを作成します 大釜の水位を保持するためのものです。 水位を格納する単一のプロパティを 持ちます。
Component プロトコルに加えて CauldronはCodableも実装します。 これはこのコンポーネントを Reality Composer Pro 3で表現し Reality Fileにシリアライズするために 必要です。 より高度なコンポーネントで エディタに表示すべきでない 実行時プロパティがある場合は CodingKeysを実装するのが 適切かもしれませんが このシンプルなコンポーネントでは すべてのプロパティをシリアライズしたいので それは必要ありません。 次に水位を設定するカスタムシステムを 作成します。 システムのアップデートで Cauldronコンポーネントを 持つエンティティを検索します。 次に水のメッシュの子エンティティを検索し 水のメッシュの位置を調整します Cauldronコンポーネントで設定された 水位に基づいて調整します。 その後Reality Composer Pro 3が カスタムコンポーネントと対応するシステムを 使えるようにする必要があります。 そのためにプラグインクラスを 作成する必要があります RealityComposerProPluginプロトコルを 実装するものです。 このプロトコルはRealityComposerPro Swiftパッケージから提供されます。 このパッケージはXcodeプロジェクトに 自動的に追加されます エディタでリンクすると シミュレーションツールバーの オプションを使います。 このクラスのsetupメソッドで Reality Composer Proから受け取る コンテキストを使って コンポーネントとシステムを登録します。 これにより これらのコンポーネントと システムをエディタで使用できるようになります。
また Reality Composer Pro 3が プラグインを作成できるようにする 必要もあります。 createRealityComposerProPlugin()関数を 実装することでこれを実現します プラグインを作成して返します。 この関数がクラスをrawポインタとして 返すことに気づくでしょう この関数をDLLインターフェースで エクスポートする必要があるためです。 またこれをC関数としてマークし エクスポート名を付ける必要があります プラグインローダーが 見つけられるようにするためです。 実際にこれがどのように機能するか 見てみましょう。 まずwaterLevelプロパティを持つ Cauldronコンポーネントを作成します。
次に水面を配置するシステムを追加します プロパティの値に基づいて配置します。
最後にコンポーネントとシステムを登録します Reality Composer Proに登録します。
これでプラグインスキームをビルドして ダイナミックライブラリを作成できます。
エディタでプロジェクトを 開けるようになりました。 このプロジェクトにはプラグインがあるため Reality Composer Proに 信頼するか確認されます。 を選択して プラグインを読み込みます。
プラグインの読み込みを承認すると インポートされたコンポーネントが エディタに表示されます。
プロジェクトのビルド設定に移動すると インポートされたコンポーネントと システムもそこに表示されます。 この設定パネルを使ってカスタムプラグインの ディレクトリを指定することもできます。
インポートされたコンポーネントは プロジェクトのCustom Componentsフォルダに あります。 コンポーネントをインポートして Reality Composer Pro 3が認識したので Cauldronエンティティに追加できます。
エディタで水位プロパティを変更すると 水面が反応するのが確認できます。 カスタムシステムがエディタ内で動作しており プラグインの仕組みを通じて プロパティの値に基づいて 水位を変更しています。 アーティストやデザイナーはこれを使って エディタでプロパティを微調整できます アプリを再ビルドして 再起動する必要がありません。
システムをデバッグしたい場合は コードにブレークポイントを設定して エディタアプリケーションに アタッチできます。
コードが実行されると Xcodeデバッガで停止し ロジックを確認できます。
基本的な水面が機能するようになったので 渦巻くエフェクトを追加して さらに発展させたいと思います。 プレイヤーが大釜をかき混ぜて ポーションを混ぜる際に 水面が渦巻きの形に 変形するようにしたいです。 水面の形を変えるために テクニカルアーティストが この渦巻きシェーダを構築しました Reality Composer Pro 3の Shader Graphシステムを使って構築しました。 Shader Graphには回転速度などの パラメータがあり それらのパラメータに基づいて 渦巻きの形を生成します。 これらのパラメータを 制御できるようにしたいので カスタムコンポーネントから制御します。 そのためにまずいくつかのプロパティを 追加します 渦巻きの形をガイドするためのものです。 次に以前作成した大釜のシステムを修正して これらのパラメータを Shader Graphに伝播させます。 まずShader Graphマテリアルを取得します。 次にヘルパー関数を使って 水面の形状を計算します Cauldronのプロパティに基づいて計算します。 計算された形状を使って Shader Graphパラメータを設定します。 最後にこのマテリアルを モデルに再度割り当てます。 実際にどのように機能するか見てみましょう。 まずCauldronに新しいプロパティを追加します。
次に水面を計算する関数を記述します。
最後にシステムを更新して シェーダパラメータを設定し プラグインを再ビルドします。
プラグインを再ビルドするたびに 変更を反映させるために Reality Composer Proを再起動する必要があります。 Reality Composer Proから再びプロジェクトを 信頼するか確認されます。 このダイアログを表示しないようにするには チェックボックスを オンにします。
次にカスタムコンポーネントへの変更が 表示されるダイアログが現れます。 変更はすべて問題ないので 承認します。
Cauldronコンポーネントに戻ると 新しいプロパティが表示されています。
水位のデフォルト値をいくつか設定しましょう 渦係数を設定しましょう
では 回転速度に別の値を 試してみましょう。 回転速度を上げると 渦がより深くなるのが分かります。
次にアニメーションシステムでプラグインを 使う方法について説明します。 アニメーションシーケンサーは カスタムアニメーションアクションに対応しており プラグインで定義できます その後シーケンサーのタイムラインに 追加できます。 大釜の水位を設定する カスタムアクションを作成します。 これには EntityActionプロトコルを 実装する必要があります。 またReality Fileに保存するには Codableを実装する必要があります。
このアクションは2つのパラメータを取ります: 水面の開始レベルと終了レベルです これにより2つの値の間で アニメーションできます。
EntityActionプロトコルのために アニメーション値の型をTransformとして 返す必要もあります。 アニメーションエグゼキュータでエンティティに アクセスするために必要です。 アクションを実行するコードも 記述する必要があります アニメーション実行時に 水位を更新するためです。
そのためエンティティアクションに 静的なsubscribe()関数を作成します プラグイン読み込みコードから呼び出します。
この関数では EntityActionのsubscribeメソッドを使って .updatedイベントをサブスクライブします RealityKitがアニメーションを実行する際に 呼び出されます。 これを使ってカスタムアニメーションアクションを 実行します。 経過アニメーション時間を0から1の 正規化された数値として取得します。
次に現在の水位を計算します 正規化された時間を使って 開始と終了の水位の間で補間します。 エンティティからCauldronコンポーネントを取得して 水位を更新します。 最後に変更したCauldronコンポーネントを エンティティに再設定します。 最後のピースはこのカスタムアニメーションを 登録することです Reality Composer Pro 3に登録します。
カスタムコンポーネントや カスタムシステムと同様に アクションをコンテキストに登録して エディタが認識できるようにします。
また先ほど作成したsubscribe関数も 呼び出す必要があります アニメーションのアップデート時に アクションが実行されるようにするためです。 実際にどのように機能するか 見てみましょう。 まずカスタムエンティティアクションを定義します。
次にこのアクションを実装する コードを追加します。
最後にこのアクションをエディタに登録して プラグインを再ビルドします。
エディタを再起動して プロジェクトを開くと 新しいアクションがインポートされたことが 表示されます。
このアクションを使うアニメーションを 作成しましょう。 まずエディタで 新しいシーケンスを作成します。
次にシーケンスを開いて アニメーションのルートエンティティを設定します 大釜を含むシーンに設定します。 そのためにCauldronWorldという シーンを準備しています。
次にシーケンスに アニメーショントラックを追加します 大釜をこのトラックに使う エンティティとして選択します。
左パネルからSetWaterLevelActionを ドラッグして トラックのタイムラインにドロップして 大釜で実行されるアクションを作成できます。 インスペクタでこのアクションを展開して パラメータを設定できるようにします: 大釜の水位の開始値と停止値です。 開始値を0.3 停止値を0.5に設定します。 これでアニメーションを再生できます カスタムアクションに基づいて 水位が変化するのが確認できます。
アーティストやデザイナーは Script Graphを使って ゲームプレイとインタラクティビティを 作成できます Reality Composer Pro 3のプロジェクトで コードを書くことなく実現できます。 組み込みのスクリプトノードで 多くのことができますが さらに高度なことをしたい場合は プラグインを使ってカスタムノードを 追加できます デザイナーがScript Graphで 活用できます。 カスタムコンポーネントをScript Graphに 公開する最も簡単な方法は @Scriptableマクロを使うことです。 そのためにまずRealityKitScriptingを RealityKitScriptingMacrosモジュールと ともにインポートします。 このマクロはここで定義されています。 RealityComposerProのSwiftパッケージと 同様に このパッケージはXcodeプロジェクトを 作成すると自動的にセットアップされます Reality Composer Pro内から 作成した場合です。 次にコンポーネントのstructに @Scriptableマクロを付けます。 これはschema変数に展開されます コンポーネントを記述するものです スクリプトシステムに登録するために 使います。 他のすべての登録と同様に これはプラグインの setup関数で行います。 スクリプトモジュールはメインスレッドで 登録する必要があります。
まずプロジェクトのスクリプト設定を 作成します。 設定のイニシャライザで すべてのスクリプトモジュールのリストを 返す必要があります。
Cauldronのschemaを保持する 単一のモジュールを作成します。 このschemaは@Scriptableマクロによって 生成されます。 次に設定を RealityKitScriptingに追加します。 実際にどのように機能するか 見てみましょう。 まずスクリプトモジュールをインポートし @ScriptableマクロをCauldronコンポーネントに 追加します。
次にスクリプトモジュールをエディタに 登録するコードを追加して プラグインを再ビルドします。
Script Graphを作成して Cauldronコンポーネントの 新しいカスタムノードを活用します。 まずCauldronエンティティに Scriptingコンポーネントを追加します。
新しいコンポーネントをダブルクリックして Script Graphエディタを開きます。 ユーザーがキーボードのキーを押すと 水位が変化するようにします。 まずアップデートノードを追加します。 このノードはシーンがアップデートされるたびに 実行されます。
次にIfノードを追加して キー入力と接続します キーが押されるたびに ノードが実行されるようにします。
Ifノードのtrueコネクタをつないで 大釜の水位を設定します。
これで「a」キーが押されると 大釜の水位が0.25に設定されます。 別のキーを接続して 異なる水位を設定します。 そのためにグラフ全体を コピーして貼り付けます。
コピーしたものでキーを「z」に変更し 水位を0.5に設定します。
シミュレーションビューを開いて テストできます。 「a」と「z」キーを押すと 水位が上下します。
このセッションでは 多くの内容をカバーしました。 Xcodeを使ってシンプルなプラグインを 作成する方法をご紹介しました エディタの機能を拡張して アプリのデータを扱い エディタ内でコードを 実行できるようにする方法です。 詳しくはぜひご覧ください 「Explore advances in RealityKit」セッション RealityKitの最新の追加機能を ご覧いただけます。 また次のセッションもおすすめです 「Supercharge your spatial workflows with Reality Composer Pro 3」 エディタで生産性を向上させる 方法をカバーしています。 新しいReality Composer Pro 3で 皆さんがどんな素晴らしいエクスペリエンスを 作るか楽しみにしています。 ご視聴ありがとうございました
-
-
6:08 - Cauldron component
// Add a component to represent the water level import RealityKit public struct Cauldron: Component, Codable { public var waterLevel: Float enum CodingKeys: CodingKey { case waterLevel } } -
6:42 - CauldronSystem
// Add a system to control the water level import RealityKit public struct CauldronSystem: System { let query = EntityComponentQuery(Cauldron.self) public init(scene: Scene) {} public func update(context: SceneUpdateContext) { for (entity, cauldron) in context.entities(matching: query) { guard let water = entity.findEntity(named: "Cauldron_Water_mesh") else { continue } water.setPosition(SIMD3<Float>(0, 1, 0) * cauldron.waterLevel, relativeTo: entity) } } } -
7:00 - RCPCustomComponentsPlugin
// Make sure that Reality Composer Pro 3 knows about the Cauldron and CauldronSystem import RealityComposerPro final class RCPCustomComponentsPlugin: RealityComposerProPlugin { public func setup(context: any RealityComposerProContext) { context.registerComponent(Cauldron.self) context.registerSystem(CauldronSystem.self) } } @_cdecl("createRealityComposerProPlugin") public func createRealityComposerProPlugin() -> UnsafeMutableRawPointer { return RCPCustomComponentsPlugin().passRetained() } -
10:49 - Cauldron component with vortex properties
// Properties to control water surface import RealityKit public struct Cauldron: Component, Codable { public var waterLevel: Float public var rotationSpeed: Float public var minWaterLevel: Float public var maxWaterLevel: Float public var vortexCoeff: Float } -
11:05 - CauldronSystem update with ShaderGraph
public func update(context: SceneUpdateContext) { for (entity, cauldron) in context.entities(matching: query) { guard let water = entity.findEntity(named: "Cauldron_Water_mesh") else { continue } water.setPosition(SIMD3<Float>(0, 1, 0) * cauldron.waterLevel, relativeTo: entity) guard var model = water.components[ModelComponent.self] else { continue } guard var mat = model.materials.first as? ShaderGraphMaterial else { continue } let surface = computeSurface(cauldron: cauldron) try? mat.setParameter(name: "Level Radius", value: .float(surface.levelRadius)) try? mat.setParameter(name: "Lowest Point", value: .float(cauldron.waterLevel - surface.lowestPoint)) try? mat.setParameter(name: "Height Change", value: .float(surface.heightChange)) try? mat.setParameter(name: "Level Coeff", value: .float(surface.levelCoeff)) try? mat.setParameter(name: "Is Level", value: .bool(surface.isLevel)) model.materials[0] = mat water.components.set(model) } } -
13:25 - SetWaterLevelAction
// Custom action for setting the water level of the Cauldron import RealityKit public struct SetWaterLevelAction: EntityAction, Codable { // Parameters for the action public let startWaterLevel: Float public let endWaterLevel: Float // Required by EntityAction protocol public var animatedValueType: (any AnimatableData.Type)? { Transform.self } } -
14:05 - SetWaterLevelAction subscribe
extension SetWaterLevelAction { static func subscribe() { Task { @MainActor in SetWaterLevelAction.subscribe(to: .updated) { event in let normalizedTime = (event.playbackController.time - event.startTime) / event.duration let action = event.action let currentLevel = action.startWaterLevel + Float(normalizedTime) * (action.endWaterLevel - action.startWaterLevel) guard let entity = event.targetEntity else { return } guard var cauldron = entity.components[Cauldron.self] else { return } cauldron.waterLevel = currentLevel entity.components.set(cauldron) } } } } -
14:56 - RCPCustomComponentsPlugin with action
// Make sure that Reality Composer Pro 3 knows about the SetWaterLevelAction import RealityComposerPro final class RCPCustomComponentsPlugin: RealityComposerProPlugin { public func setup(context: any RealityComposerProContext) { context.registerComponent(Cauldron.self) context.registerSystem(CauldronSystem.self) context.registerAction(SetWaterLevelAction.self) SetWaterLevelAction.subscribe() } } @_cdecl("createRealityComposerProPlugin") public func createRealityComposerProPlugin() -> UnsafeMutableRawPointer { return RCPCustomComponentsPlugin().passRetained() } -
17:32 - Cauldron with @Scriptable macro
// Expose Cauldron to Script Graphs import RealityKit import RealityKitScripting import RealityKitScriptingMacros @Scriptable public struct Cauldron: Component, Codable { public var waterLevel: Float public var rotationSpeed: Float public var minWaterLevel: Float public var maxWaterLevel: Float public var vortexCoeff: Float } -
18:08 - Register scripting module
// Register scripting module public func setup(context: any RealityComposerProContext) { context.registerComponent(Cauldron.self) context.registerSystem(CauldronSystem.self) context.registerAction(SetWaterLevelAction.self) SetWaterLevelAction.subscribe() Task { @MainActor in let config = RKS.Configuration(id: "ChaparralVillage") .onInitialize { _ in [ Module("ChaparralVillage") { Cauldron.SchemaProvider.schema } ] } try! RKS.addConfiguration(config) } }
-
-
- 0:00 - Introduction
An overview of the Reality Composer Pro 3 plugin system, showing how Xcode and the editor share a project to let engineers and artists collaborate — with custom components, systems, animation actions, and Script Graph nodes all running live inside the editor.
- 2:00 - Extending the editor
Learn how the Reality Composer Pro 3 plugin system works: how the editor and Xcode share a single git repository, how custom Swift code is compiled into a dynamic library, and how the editor loads and trusts plugins at runtime.
- 4:51 - Custom components and systems
Build a Cauldron component and CauldronSystem using RealityKit, expose them to the editor via a RealityComposerProPlugin, and see the water level property update in real time as artists adjust values in the inspector.
- 10:32 - Controlling the water surface
Extend the Cauldron component with vortex shader properties and update the system to drive a ShaderGraphMaterial at runtime, enabling artists to control vortex depth and rotation speed directly from the Reality Composer Pro 3 inspector.
- 13:19 - Custom animation actions
Implement the EntityAction protocol to create a SetWaterLevelAction that animates the cauldron water level on the sequencer timeline, subscribe to animation update events to interpolate the level, and register the action with the editor plugin.
- 17:12 - Custom Script Graph nodes
Use the @Scriptable macro to expose a custom component to Reality Composer Pro 3 Script Graphs, register a scripting module in the plugin setup, and see the generated nodes appear in the Script Graph editor for no-code artist workflows.
- 21:16 - Next steps
Recap of the plugin capabilities covered — custom components, systems, animation actions, and Script Graph nodes — with recommendations to explore the Explore Advances in RealityKit and Supercharge Your Spatial Workflows sessions.