View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC25に戻る

  • 概要
  • トランスクリプト
  • コード
  • RealityKitの新機能

    iOS、iPadOS、macOS、tvOS、visionOS向けの優れた3Dコンテンツの構築を支援するRealityKitの新機能を活用して、クリエイティブな可能性を解き放ちましょう。ARKitのデータに、RealityKitを介して直接アクセスする方法を学びます。オブジェクト操作機能を使用して、3Dコンテンツをより自然に操作する方法を解説します。シーン理解、環境の融合、インスタンス化などのための新しいAPIについての、インタラクティブなサンプルを用いたデモも行います。

    関連する章

    • 0:00 - イントロダクション
    • 3:19 - アンカーの新機能
    • 6:52 - ManipulationComponent
    • 10:01 - シーン理解
    • 11:18 - EnvironmentBlendingComponent
    • 12:26 - MeshInstancesComponent
    • 16:28 - イマーシブメディア
    • 21:43 - アクセサリとその他の新機能

    リソース

    • Playing immersive media with RealityKit
    • Presenting images in RealityKit
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC25

    • SwiftUIとRealityKitの連係
    • visionOSでの空間アクセサリ入力の詳細
    • visionOSアプリでのイマーシブなビデオ再生のサポート
  • このビデオを検索

    こんにちは RealityKitチームの ソフトウェアエンジニアのLaurenceです 「What's new in RealityKit」 セッションへようこそ このセッションでは 今年リリース されたRealityKitの新機能の いくつかを紹介します

    Appleは2019年に RealityKitを導入しました その目的は 3Dコンテンツを アプリに統合することにより リアルなレンダリングを実現し イマーシブ体験を向上させることです それ以来 皆様から多くのフィードバックを いただき それを参考に このフレームワークを 年々改良してきました RealityKitは 3Dコンテンツを 現実世界の環境とシームレスに 融合させるための多彩な機能を 提供しており visionOS上でイマーシブな アプリやゲームを作成できます visionOSに加えて RealityKitは その主要な機能の多くを iOS、iPadOS、macOSにも 提供しています RealityKitのクロスプラットフォーム機能を 活用すると アプリを一度記述するだけで 最小限のコード変更で様々な プラットフォームに展開できます 今年 RealityKitが最新のtvOSに 対応したことを発表できるのを うれしく思います これにより 既存のアプリや体験をAppleTV に展開したり 大画面向けの新しいアプリを 作成したりできるようになりました RealityKitはすべての世代の AppleTV 4Kに対応しています 今年のRealityKitアップデートでは 仮想世界と現実世界を融合させた 3D体験をこれまでになく簡単に 作成できる多彩な新機能が 追加されました このセッションでは これらの機能の いくつかを紹介します 例えば ManipulationComponentや EnvironmentBlendingComponentや MeshInstancesComponentなどです これらの機能のいくつかを利用して 空間パズルゲームを作成してみます ゲームは目の前の平面に固定された 鍵のかかったチェストから始まります このチェストの周りには 操作できる 複数のオブジェクトが配置されています そのオブジェクトの1つの底面に チェストを開ける鍵が 取り付けられています オブジェクトをつかんで調べることで 隠された鍵を見つけることができます 鍵を手に入れたら チェストを開けて 賞品を確認しましょう

    小さな花火が表示されます

    まず RealityKitの新しいネイティブ ARKitサポートを使って プレイヤーの前のスペースにモデルを固定し アンカーのライフサイクルの変化を処理します 次に ManipulationComponentを使用して シーン内の3Dエンティティに インタラクションを追加します また PhysicsBodyComponentを使って オブジェクトから手を放すと リアルに落下するようにします 次に 新しいSceneUnderstanding APIを 使用して ゲームエンティティが シーン認識メッシュと 衝突できるようにします

    その後 EnvironmentBlendingComponentを使って アプリを現実世界に より自然に溶け込ませます

    次に 新しい MeshInstancesComponentを使って 3Dモデルの複数のインスタンスを 効率的に描画し シーンを装飾する方法を紹介します 次に 新しいイマーシブメディアの アップデートについて説明します また 空間アクセサリやエンティティの アップデートなど その他の新しい 発表内容についても取り上げます まず 新しいAPIを使用して 3Dモデルを現実世界の環境に固定します このAPIによって RealityKitから ARKitデータに直接アクセスできます RealityKit AnchorEntityを使用して ゲームをテーブルに配置します AnchorEntityは バーチャルコンテンツを 現実世界の表面に固定するために使用されます 今年は ARKitのアンカーデータに直接 アクセスできるようにすることで AnchorEntityをさらに強化しています では その方法を説明します RealityKitを通じてARKitデータに直接 アクセスするには まず SpatialTrackingSessionを作成する 必要があります セッションの構成によって AnchorEntityの状態が変化したときに RealityKitは新しい AnchorStateEventsをアプリに送信します 次に AnchorEntityを設定して 目的のアンカーのプロパティを フィルタリングできます このアプリでは 特定の寸法のテーブルを 探したいと思います RealityKitが AnchorEntityに設定した プロパティに合致する 最適なアンカーを見つけると AnchorStateEventを発生させます このAnchorStateEventインスタンスには アンカーの変形や範囲などの ARKitのデータが含まれており ゲームを配置するために使用できます では これをコードで見ていきましょう まず SpatialTrackingSessionを作成して RealityKitのAnchorEntityを 現実世界の環境に トラッキングできるようにします 私のゲームでは チェストを生成する 平面をトラッキングする必要があります そのため SpatialTrackingSessionの構成で 平面のトラッキングを有効にします

    これで 作成した構成を実行することで トラッキングセッションを開始できます 次に ゲームをテーブル上に配置するために AnchorEntityを生成します このAnchorEntityは 水平面である テーブルとして分類し 15cm四方の最小サイズが 関連付けられています このAnchorEntityはアンカーされていない 状態で開始されますが 指定した分類と サイズに一致する テーブル平面が検出されると アンカーされます アンカー状態が変化したときに 更新情報を受け取るには 新しいAnchorStateEvents APIを 使用する必要があります

    AnchorStateEvents APIを使用すると エンティティがアンカーされたとき アンカーが解除されそうなとき またはアンカーに失敗したときの イベントをサブスクライブできます アプリではDidAnchorイベントを 使用して ゲームエンティティを テーブル面の範囲内に配置します

    コードでは DidAnchorイベントを サブスクライブすることで アンカーエンティティが環境に正常に アンカーされた時点を検知しています イベント構造体からは 新しいARKitAnchorComponentを格納する 更新されたアンカーエンティティを 取得できます このコンポーネントは 使用できる範囲や 変換などのARKitデータを保持しており それによってゲームエンティティを アンカーされた面に配置できます このデータにアクセスするには ARKitAnchorComponentの anchorプロパティを使用します

    anchorプロパティを使用するには ARKitの anchor型にキャストする必要があります この場合は AnchorEntityが平面を 対象にしているためPlaneAnchorに キャストしてみます

    これで ARKitのアンカーのextentや transformの生データにアクセスできます ARKitのtransformデータ 具体的には originFromAnchorTransformと anchorFromExtentTransformを使用して ゲームをアンカーされた平面の 中央に正しく配置します これで イマーシブ空間を開くと 適切な平面が見つかったときに ゲームオブジェクトが生成されます

    次に RealityKitの新しい ManipulationComponentを使用してシーンに インタラクションを追加します ManipulationComponentを使うと シーン内の3Dエンティティを つかむ 回転させるなどの 操作が簡単にできるようになります 手を持ち替えるなどの高度な ジェスチャーもサポートしています

    ManipulationComponentを使用して プレイヤーがゲームオブジェクトを つかんだり回転させたりして その下にある鍵を探せるようにします ここでは この機能をゲームに追加する 方法を紹介しますが ManipulationComponentの仕組みや 活用方法について 詳しく知りたい場合は 「Better together: SwiftUI and RealityKit」セッションをご覧ください エンティティをつかんで 操作できるようにするには ManipulationComponentの configureEntity関数を呼び出すだけです この関数によって 必要なコンポーネントの InputTarget、Collision HoverEffect、Manipulationなどが 自動的にエンティティに追加されます 以上です これで エンティティを手で持ち上げて 回転させることができるようになります ただし 手を放すと オブジェクトは スムーズなアニメーションを描画しながら 元の位置に戻ります

    コードに戻り ManipulationComponentの 「releaseBehavior」プロパティを stayに設定します

    次に このmanipulationComponent インスタンスをエンティティに 割り当てます これにより オブジェクトを 手放したときに自動的に 元の位置に戻るアニメーションが 無効になり その場に静止したままになります 次に オブジェクトを床に 落とす必要があります そのために エンティティに PhysicsBodyComponentを追加します ただし PhysicsBodyComponentで 重力を有効にするのは オブジェクトがつままれて 持ち上げられていないときだけにします 新しいManipulationEvents APIを 使えば これを簡単に実現できます

    ManipulationEventsは RealityKitがエンティティの 操作中に発行する 様々なインタラクション 状態を表すイベントです

    例えば WillReleaseイベントは プレイヤーがエンティティを 手放したときに発生します 同様に WillBegin、WillEnd DidUpdateTransform、DidHandOffなど 他のイベントも用意されています 詳しくは developer.apple.com/jpの ドキュメントをご参照ください

    WillBeginとWillEndイベントを使用して ゲームのエンティティが 操作されていないときだけ重力の影響を 受けるように設定します

    まず WillBeginイベントを サブスクライブし physicsBodyComponentのmodeをkinematicに 変更して オブジェクトの移動中に 物理システムが干渉しないようにします この設定により エンティティへの 重力の影響をも防ぐことができます

    次に WillEndイベントを サブスクライブし physicsBodyComponentのmodeを dynamicに戻します エンティティが操作されなくなった タイミングでこれを行います これにより エンティティはシーン内の他の 物理オブジェクトに反応できるようになり 重力の影響も受けるようになります ゲームオブジェクトが物理に 反応するようになったので プレイヤーの周囲の環境と 衝突できるようにする必要があります これを行うには 新しい SceneUnderstanding APIを使用して 部屋のメッシュをアプリの 物理シミュレーションに追加します RealityKitのSpatialTrackingSession APIを使うと 周囲の環境の メッシュを生成できます このメッシュは シーン認識メッシュと呼ばれ 部屋にある現実世界のオブジェクトとの 衝突や物理演算を処理できます

    現実世界の環境からシーン認識 メッシュを利用するには SpatialTrackingSessionの構成で SceneUnderstandingFlagsを 設定します

    visionOSは現在 collision(衝突)フラグと physics(物理)フラグに対応しています この2つを使って ゲームオブジェクトが シーン認識メッシュと 衝突できるようにします これらのフラグは SpatialTrackingSessionの構成で 設定してから実行します

    これを行うには 前に設定した SpatialTrackingSessionを更新します 衝突と物理のシーン認識フラグを SpatialTrackingSessionの構成に 追加するだけで セッションを開始する準備は完了です これで シーン認識メッシュが ゲームの物理シミュレーションに追加され ゲームオブジェクトをテーブルや 床に落とすと 環境と衝突するようになります ゲームが環境とインタラクションできる ようになったので 視覚的にも環境に 反応させたいと思います これに使用するのは EnvironmentBlendingComponentです EnvironmentBlendingComponentは イマーシブ空間アプリ向けの新しい コンポーネントで 今年の RealityKitアップデートで導入されました

    これにより エンティティを現実世界の 静的オブジェクトで隠すことができます このコンポーネントを持つエンティティは 現実世界の静的オブジェクトに 覆われている量に応じて 部分的または完全に隠されます 人やペットなど動的に動く オブジェクトでは このコンポーネントを含む オブジェクトは隠されません

    この機能を追加する場合 必要な作業は EnvironmentBlendingComponentを 追加して 周囲の環境に隠れるように 優先するブレンドモードを設定するだけです これで EnvironmentBlendingComponentを 持つエンティティを現実世界のオブジェクトの 背後に配置すると エンティティが それによって隠されていることがわかります EnvironmentBlendingComponentを 使用するエンティティは 背景環境の一部として扱われ 常にシーン内の 他のバーチャルオブジェクトの 背後に描画されます EnvironmentBlendingComponentの 動作を確認できたので 周囲のゲーム領域に 新しいMeshInstancesComponentを 使用して装飾を追加します 昨年 RealityKitにLowLevelMesh APIと LowLevelTexture APIが追加され レンダリングデータをさらに細かく 制御できるようになりました 今年のRealityKitアップデートでは この低レベルアクセスが 別のレンダリング機能である インスタンス化にも拡張されました このアプリでは 周囲の空間を 装飾する一方で プレイ可能な領域も定義します

    空間を装飾するために 数多くの複製 エンティティを生成することもできますが これを行うには エンティティの クローンを何度も作成する必要があり これによりModelComponentの コピーも多数作成されます この方法ではメモリ使用量と処理の 負荷が大きくなる可能性があります より効率的で便利な方法として 新しいMeshInstancesComponentを 使用する方法があります

    MeshInstancesComponentを 使用すると 1つのエンティティで 同じメッシュを複数回 描画できます 指定する必要があるのは メッシュの 描画に使用する変換のリストだけです iOS、iPadOS、macOS、tvOSでは LowLevelBufferを使用してレンダリング データをCustomMaterialに渡すことで 各インスタンスを固有の見た目にできます MeshInstancesComponentは 利便性が高いことに加え GPUに送信するデータの量を減らすことで パフォーマンスも向上させます 重複したメッシュを描画する際に モデルやマテリアルの複数のコピーを GPUに送信する代わりに MeshInstancesComponentは データは一度だけ送信します

    1つのMeshInstancesComponentで 描画されるモデルは 1つのエンティティの 一部とみなされます このコンポーネントを使用して広い領域を カバーする場合は 複数の小さな エンティティに分割して カリングを 可能にするのが合理的です MeshInstancesComponentを コードで使用する方法を紹介します まず インスタンス化するメッシュが必要です これは アプリのコンテンツバンドルから エンティティを読み込むことで取得します これで MeshInstancesComponentと LowLevelInstanceDataオブジェクトを 初期化できます LowLevelInstanceData オブジェクトは 個々のメッシュインスタンスの データを保持します LowLevelInstanceDataオブジェクトを 作成するときは アプリで必要な インスタンス数を指定する必要があります ここでは プレイ領域を大まかに 表示するために20を指定して 過密にならないようにします 次に LowLevelInstanceData オブジェクトを MeshInstancesComponentに割り当てます その際 インスタンス化するメッシュ パーツのインデックスを指定します 今回インスタンス化するメッシュは単純で メッシュパーツの1つだけであるため LowLevelDataObjectを partIndex: 0に割り当てます

    これで LowLevelInstanceData オブジェクトに 各メッシュインスタンスの 変換を設定します

    装飾に変化を持たせるために 各インスタンスのスケール 角度、位置をランダムにします これらの値を使用して変換行列を作成し それを各インスタンスに割り当てます

    これで meshInstancesComponentを エンティティに追加すると MeshInstancesComponentのデータを 使用してエンティティが描画されます

    これで... ゲームが完成しました

    ゲームを開始して 目の前の平面に固定します プレイ領域内のオブジェクトは 持ち上げたり回転させたりできるので チェストを開ける鍵を探してみましょう このアプリの作成に使用した 新しいAPIを簡単にまとめます 新しいAnchorStateEvent APIを使用して コンテンツを固定しました 次に オブジェクトとのインタラクションに ManipulationComponentを使用しました また シーン認識フラグを使用して ゲームのエンティティがシーン認識 メッシュと衝突できるようにしました 最後に EnvironmentBlendingComponentと MeshInstancesComponentを使用して ゲームを現実世界に溶け込ませます 次に 今年 RealityKit追加される 他の ワクワクする機能をいくつか紹介します 例えば 新しいイマーシブメディアの サポートなどです 今年は RealityKitで画像を提示するための まったく新しいコンポーネント ImagePresentationComponentが 導入されます これは3種類の画像に対応しています まず 従来の2D画像や写真 iPhoneやVision Proで 作成した立体写真である 空間写真 新しい種類の3D画像である空間シーン これは既存の2D画像や 写真から作成されます

    空間シーンは 2D画像から生成される リアルな奥行きを持つ3D画像です 写真をジオラマにしたようなもので ユーザーがシーンに対して頭を動かすことで 発生する視差効果によって 空間シーンの奥行きが強調されます 空間シーンは 既存の2D写真に命を 吹き込むすばらしい方法です visionOSのPhotosアプリや RealityKitを 使用した独自のアプリで使用できます それでは この3種類の画像をアプリに 追加するコードを説明していきます まず RealityKitで2D画像や写真を 表示する方法を紹介します

    最初に2D写真のURLを取得し そのURLを使用して 新しいImagePresentationComponentを 作成します このコンポーネントのイニシャライザは 非同期です 画像をメモリに読み込むのに 少し時間がかかる場合があるためです コンポーネントが初期化されたら エンティティに割り当てて RealityKitのシーンで表示できます

    空間写真を表示するには もう1つステップが必要です エンティティで設定する前に コンポーネントに希望する表示モードを 割り当てる必要があります また 最初に画像が対応している ことを確認することで 適切な表示モードを指定できます 希望する表示モードを指定しない場合や 画像がモードに対応していない場合は ImagePresentationComponentは 画像が空間写真であっても2D (モノスコピック)モードで 表示します イマーシブな空間写真の表示を有効にするには 希望する表示モードとして spatialStereoImmersiveを使用します 空間写真から画像表示 コンポーネントを作成する場合 常に両方の空間ステレオモードが 利用可能になります 2D画像と空間写真はどちらも ディスク上のファイルから読み込まれます この画像を空間シーンとして表示するには いくつかの追加手順が必要になります なぜなら 空間シーンを表示する前に 空間シーンを生成する必要があるためです ここでは 空間シーンをコードで生成して 表示する方法を紹介します

    空間シーンは 2D画像または 空間写真を使用して 生成できます 空間写真から空間シーンを生成する場合 空間写真の1つのチャンネルのみが 変換用の2D画像として使用されます 空間シーンを作成する場合 ImagePresentationComponentを画像の URLから直接初期化するのではありません 代わりに URLからSpatial3DImageを作成し Spatial3DImageを使用して ImagePresentationComponentを初期化します ただし このコンポーネントはまだ空間シーン として表示する準備ができていません そのためには 最初にシーンを 生成する必要があります

    そのために Spatial3DImageの generateメソッドを呼び出します 数秒で空間シーンが生成されます 生成に成功すると ImagePresentationComponentの availableViewingModesが更新され spatial3D モードと spatial3DImmersiveモードが追加されます 次に そのいずれかを希望する表示モード として設定して ウィンドウ表示や イマーシブ表示で空間シーンを 表示できるようになります 空間シーンを事前に生成しておく 必要はありません Photosアプリのように アプリを 使用しているユーザーがボタンを押すまで 待つこともできます generateを呼び出す前に コンポーネントの 表示モードを.spatial3Dに設定すると 空間シーンの準備ができ次第 すぐに表示するよう コンポーネントに指示できます これにより コンポーネントは 生成中に進行状況のアニメーションを表示し 生成が完了すると同時に 空間シーンを表示します こちらは Vision Proでの表示例です ImagePresentationComponentは visionOSのPhotosアプリと 同じ生成アニメーションを表示し 最終的な 結果は3Dでもすばらしい見栄えです

    ここでは ImagePresentationComponentを 使って 2D画像、空間写真、空間シーンを 表示する様々な方法を 簡単にまとめてみましょう このコンポーネントについて詳しくは 「Presenting images in RealityKit」の サンプルコードを developer.apple.com/jpでご確認ください

    今年のもう1つのイマーシブメディアの 更新として VideoPlayerComponentが 幅広いイマーシブビデオフォーマットの再生に 対応できるように更新されました ポータルとイマーシブの両方のモードで 空間スタイリングによる空間ビデオ再生に 対応するようになりました

    Apple Projected Media Profile対応の 180度、360度 広視野角ビデオの再生も可能です Apple Projected Media Profile対応の ビデオではユーザーが快適さの設定を構成でき RealityKitはそれに応じて自動的に 再生を調整します

    Apple Immersive Videoに加え これらのビデオ形式も様々な表示モードで 再生されるよう構成できます これらのアップデートについて詳しくは 「Support immersive video playback in visionOS apps」 セッションをご覧ください

    次に 今年発表されたその他の アップデートについて説明します まずはトラッキング対応 空間アクセサリを紹介します 次に SwiftUIとRealityKitの統合に関する 最新のアップデートを見ていきます その後 新しいエンティティの アップデートについて紹介します RealityKitのAVIFテクスチャサポートの 概要を説明します 次に 新しいホバー効果の groupID機能について説明します 最後に RealityViewsへの 後処理効果の追加について お話しします では始めましょう RealityKitでは トラッキング対応の 空間アクセサリのサポートが追加され 共有スペースとフルスペースの両方で アプリを操作できます 空間アクセサリは6自由度でトラッキングでき アプリやゲーム内での インタラクションを強化する 触覚フィードバックにも対応しています 空間アクセサリによる入力をアプリに 追加する方法の詳細については 「Explore Spatial Accessory Input on visionOS」のセッションをご覧ください 今年 RealityKitではSwiftUIとの統合を 強化するために いくつかの新しい コンポーネントも導入されました ViewAttachmentComponentを 使用すると 非常に簡単に SwiftUIビューをエンティティに 直接追加できます さらに PresentationComponentによって ポップオーバーなどのモーダル表示を エンティティに追加できます また 新しいGestureComponentによって SwiftUIのジェスチャーをエンティティに 追加するプロセスが簡素化されます 詳しくは「Better Together: SwiftUI and RealityKit」セッションで 今年のSwiftUIとRealityKitの統合に 関する最新情報をご確認ください

    新しいエンティティのアタッチメソッドも 導入され エンティティを別のエンティティの ピンにアタッチできます このAPIにより メッシュをアニメーション スケルトンのジョイントにアタッチする作業が 大幅に簡素化されます この方法でメッシュをアタッチすることで メッシュを手動で整列させる必要がなくなり また コストのかかる階層的な 変換の更新も回避できます さらに 新しいEntityのイニシャライザを 使えば メモリ上のDataオブジェクトから エンティティを読み込むこともできます この新しいイニシャライザを使用すると RealityKitのシーン全体やUSDファイルを オンラインソースから読み込んだり ネットワークでストリーミングしたりできます このイニシャライザは 既存のEntityの イニシャライザと同じファイル フォーマットをサポートします

    さらに RealityKitはAVIF形式で エンコードされたテクスチャの サポートを追加しています これはJPEGと同様の品質を提供しながら 10ビットカラーに対応し サイズは大幅に小さくなります MacのPreviewアプリやターミナルのusdcrush を使用して この圧縮を有効にした状態で USDをエクスポートできます また HoverEffectComponentに 新機能のGroupIDが追加されています GroupIDは ホバー効果間の 関連付けをする方法です GroupIDを共有するホバー効果は アクティベーションも共有します ホバー効果にGroupIDを割り当てると 相対的な階層に依存せずにホバー効果を 有効化する方法を自由に 制御できるようになります 通常 ホバー効果は左側の例のように 階層的に適用され 子エンティティは親エンティティの 効果を継承します ただし 右側の例のように エンティティに Entity AやBなどのGroupIDがある場合 それらのホバー効果は子エンティティに 伝播しません

    今年のもう1つの注目の機能は RealityViewでの 後処理効果のサポートです customPostProcessing APIを使用すると bloomなどのカスタムエフェクトをアプリに 追加できます その際 Metal Performance ShadersやCIFilters 独自のシェーダを使用できます このAPIは iOS、iPadOS、macOS tvOSでサポートされています

    今年のRealityKitアップデートでは 3D体験の創造をこれまでになく 容易にすることに注力しています 今回は RealityKit APIを利用して ゲームをユーザーの環境に固定し ゲームのピースを直観的に操作できる 空間パズルゲームの作成方法を 紹介しました また アプリがRealityKiで空間コンテンツを 直接表示できるようにする新しいイマーシブ メディアのアップデートについても 説明しました

    それから 空間アクセサリのトラッキング エンティティの更新、ホバー効果の GroupIDなどの追加アップデートに ついても紹介しました これらの新機能により RealityKitを使った 3Dアプリの構築は非常に簡単になりました 皆さんがどんな体験を生み出すのか とても楽しみにしています ありがとうございました

    • 4:33 - Set up SpatialTrackingSession

      // Set up SpatialTrackingSession
      @State var spatialTrackingSession = SpatialTrackingSession()
      
      RealityView { content in
                   
          let configuration = SpatialTrackingSession.Configuration(
              tracking: [.plane]
          )
      		// Run the configuration
          if let unavailableCapabilities = await spatialTrackingSession.run(configuration) {
              // Handle errors
          }
      }
    • 4:34 - Set up PlaneAnchor

      // Set up PlaneAnchor
      RealityView { content in
      
      		// Set up the SpatialTrackingSession
      
          // Add a PlaneAnchor
          let planeAnchor = AnchorEntity(.plane(.horizontal,
                                                classification: .table,
                                                minimumBounds: [0.15, 0.15]))
          content.add(planeAnchor)
      }
    • 5:48 - Handle DidAnchor event

      // Handle DidAnchor event
      
      		didAnchor = content.subscribe(to: AnchorStateEvents.DidAnchor.self) { event in
      
      		guard let anchorComponent =
                 event.entity.components[ARKitAnchorComponent.self] else { return }
      
      
      		guard let planeAnchor = anchorComponent.anchor as? PlaneAnchor else { return }
      
      		let worldSpaceFromExtent =
          planeAnchor.originFromAnchorTransform *
          planeAnchor.geometry.extent.anchorFromExtentTransform
      
          gameRoot.transform = Transform(matrix: worldSpaceFromExtent)
      
          // Add game objects to gameRoot 
      }
    • 7:38 - Set up ManipulationComponent

      // Set up ManipulationComponent
      extension Entity {
          static func loadModelAndSetUp(modelName: String,
                                        in bundle: Bundle) async throws -> Entity {
      
              let entity = // Load model and assign PhysicsBodyComponent
              let shapes = // Generate convex shape that fits the entity model
      
              // Initialize manipulation
              ManipulationComponent.configureEntity(entity, collisionShapes: [shapes])
              var manipulationComponent = ManipulationComponent()
              manipulationComponent.releaseBehavior = .stay
              entity.components.set(manipulationComponent)
      
              // Continue entity set up
          }
      }
    • 9:28 - Subscribe to willBegin ManipulationEvent

      // Subscribe to ManipulationEvents
      
      // Update the PhysicsBodyComponent to support movement
      willBegin = content.subscribe(to: ManipulationEvents.WillBegin.self) { event in
          if var physicsBody = event.entity.components[PhysicsBodyComponent.self] {
              physicsBody.mode = .kinematic
              event.entity.components.set(physicsBody)
          }
      }
    • 9:29 - Subscribe to willEnd ManipulationEvent

      // Subscribe to ManipulationEvents
                      
      // Update the PhysicsBodyComponent to be a dynamic object
      willEnd = content.subscribe(to: ManipulationEvents.WillEnd.self) { event in
          if var physicsBody = event.entity.components[PhysicsBodyComponent.self] {
              physicsBody.mode = .dynamic
              event.entity.components.set(physicsBody)
          }
      }
    • 10:52 - Set up Scene understanding mesh collision and physics​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      // Set up Scene understanding mesh collision/physics
      
      let configuration = SpatialTrackingSession.Configuration(
          tracking: [.plane],
          sceneUnderstanding: [.collision, .physics]
      )
    • 11:56 - Set up EnvironmentBlendingComponent

      // Set up EnvironmentBlendingComponent
      
      entity.components.set(
          EnvironmentBlendingComponent(preferredBlendingMode: .occluded(by: .surroundings))​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
      )
    • 14:20 - Set up MeshInstancesComponent

      // Set up MeshInstancesComponent entity
      
      let entity = try await ModelEntity(named:"PebbleStriped.usdz")
      var meshInstancesComponent = MeshInstancesComponent()
      let instances = try LowLevelInstanceData(instanceCount: 20)
      meshInstancesComponent[partIndex: 0] = instances
          
      instances.withMutableTransforms { transforms in
          for i in 0..<20 { 
              let scale: Float = .random(in:0.018...0.025)
              let angle: Float = .random(in:0..<2) * .pi
              let position = randomPoint(in: inArea, with: scene)
              let transform = Transform(scale: .init(repeating: scale),
                                        rotation: .init(angle: angle,axis: [0, 1, 0]),
                                        translation: position)
              transforms[i] = transform.matrix
          }
      }
              
      entity.components.set(meshInstancesComponent)
    • 17:36 - Load and display a 2D photo

      // Load and display a 2D photo
          
      guard let url = Bundle.main.url(forResource: "my2DPhoto", withExtension: "heic") else {a​​​​​​​​​​​​​​​​​​​​​​​​​​
          return
      }
      
      let component = try await ImagePresentationComponent(contentsOf: url)
      
      let entity = Entity()
      entity.components.set(component)
    • 17:57 - Load and display a spatial photo with windowed presentation

      // Load and display a spatial photo with windowed presentation
          
      guard let url = Bundle.main.url(forResource: "mySpatialPhoto", withExtension: "heic") else {
          return
      }
      
      var component = try await ImagePresentationComponent(contentsOf: url)
      
      // Discover if the component supports windowed spatial photo presentation.
      if component.availableViewingModes.contains(.spatialStereo) {
          component.desiredViewingMode = .spatialStereo
      }
      
      entity.components.set(component)
    • 18:22 - Load and display a spatial photo with immserive presentation

      // Load and display a spatial photo with immersive presentation
          
      guard let url = Bundle.main.url(forResource: "mySpatialPhoto", withExtension: "heic") else {
          return
      }
      
      var component = try await ImagePresentationComponent(contentsOf: url)
      
      // Discover if the component supports immersive spatial photo presentation.
      if component.availableViewingModes.contains(.spatialStereoImmersive) {
          component.desiredViewingMode = .spatialStereoImmersive
      }
      
      entity.components.set(component)
    • 18:56 - Load a spatial photo and use it to generate and present a spatial scene

      // Load a spatial photo and use it to generate and present a spatial scene
          
      guard let url = Bundle.main.url(forResource: "mySpatialPhoto", withExtension: "heic") else {
          return
      }
      
      let spatial3DImage = try await ImagePresentationComponent.Spatial3DImage(contentsOf: url)
      var component = ImagePresentationComponent(spatial3DImage: spatial3DImage)
      
      try await spatial3DImage.generate()
      
      // Discover if the component supports windowed spatial scene presentation.
      if component.availableViewingModes.contains(.spatial3D) {
          component.desiredViewingMode = .spatial3D
      }
      
      entity.components.set(component)
    • 20:06 - Generating a spatial scene as needed

      // Load a spatial photo and use it to generate and present a spatial scene
          
      guard let url = Bundle.main.url(forResource: "mySpatialPhoto", withExtension: "heic") else {
          return
      }
      
      let spatial3DImage = try await ImagePresentationComponent.Spatial3DImage(contentsOf: url)
      var component = ImagePresentationComponent(spatial3DImage: spatial3DImage)
      
      component.desiredViewingMode = .spatial3D // (or .spatial3DImmersive)
      
      entity.components.set(component)
      
      try await spatial3DImage.generate()
    • 23:35 - Load entity from Data object​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      // Load entity from Data object
          
      if let (data, response) = try? await URLSession.shared.data(from: url) {
          if let entity = try? await Entity(from: data) {
              content.add(entity)
          }
      }

Developer Footer

  • ビデオ
  • WWDC25
  • RealityKitの新機能
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習とAI
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン