ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
自分の世界を拡張現実に
Object CaptureやRealityKitを使用して、現実世界のオブジェクトを拡張現実ゲームに取り込む方法を紹介します。さらに、Object Captureフレームワークで詳細なアイテムをキャプチャしたり、これらをXcodeのRealityKitプロジェクトに追加したり、定型化されたシェーダやアニメーションを適用したり、ARエクスペリエンスの一部としてこれらを使用したりする方法を紹介します。また、ARKit、RealityKit、Object Captureと連携させる際のベストプラクティスも紹介します。 このセッションを最大限に活用するには、WWDC21の「RealityKit 2の詳細」と「Object Captureによる3Dコンテンツの作成」を最初にご確認ください。
リソース
- Building an Immersive Experience with RealityKit
- Capturing photographs for RealityKit Object Capture
- Creating a Game with Reality Composer
- Creating a Photogrammetry Command-Line App
- RealityKit
- Taking Pictures for 3D Object Capture
- Using object capture assets in RealityKit
関連ビデオ
WWDC22
WWDC21
-
ダウンロード
♪ メロウなインスト曲 ヒップホップ ♪ ♪ こんにちは Haoです Object Captureチームの エンジニアです 今日は同僚のRisaと一緒に Object Capture APIと RealityKitを使用して 現実世界の物体の 3Dモデルを作成し ARに取り込む方法を ご紹介します では 始めましょう まずは Object Captureの おさらいから これは昨年 RealityKit APIとして macOSで公開されました 次に ARKitで強化された いくつかのカメラ機能を ご紹介します これは高解像度の 被写体の写真を撮影して Object Captureを AR Appに 取り込む際に 役立ちます その後は 今後も このテクノロジーを 最大限に活用いただくために Object Captureの ベストプラクティスを ご紹介します 最後のセクションでは Risaが RealityKitの Object Captureを使った エンドツーエンドの ワークフローを紹介し 現実世界の物をAR体験に 取り込む方法を説明します Object Captureの簡単な おさらいから始めましょう Object Captureは コンピュータビジョン技術で 現実の被写体の画像を簡単に 詳細な3Dモデルに 変換することができます まずiPhone iPad DSLR等で 様々な角度から 被写体の写真を撮影する ところから始めます その後でその写真を Object Capture対応の Macにコピーします RealityKitは Photogrammetry APIを 使用して ほんの数分で 写真を3Dモデルに 変換できます 出力モデルには 幾何学的なメッシュと テクスチャを含む様々な マテリアルマップが含まれ 自動的にモデルに 適用されます Object Capture APIの 詳細については 昨年のWWDCの Object Captureの セッションを視聴する事を 強くお勧めします 多くのデベロッパが Object Captureで素晴らしい Appを作成しています: Unity Cinema4D Qlone PolyCam PhotoCatch などがあります さらにこのAPIを使って 作成された 美しい見た目の モデルもあります これはEthan Saadiaが PhotoCatch Appの Object Captureの 力を使って 作成したモデルです そしてShopifyの友人 Mikko HaapojaもこのAPIを使って 素敵な3Dモデルを たくさん作りました Object Captureで出力される 3Dモデルのきめ細やかな 画質は 電子商取引では 非常に効果的です 例えばこのGOAT Appでは 様々な靴を試着することが できます 靴のモデルは全てObject Capture APIで作成したものです 細部をしっかりと捉える こだわりのデザインと なっています これは製品の購入を 決める際にも 自分の空間でぴったりとした フィット感を試す際にも 大いに役立ちます 例えば Plant Story Appでは 自分の空間で 本物そっくりの植物の3D モデルをプレビューできます 全てObject Captureで 作られています 植物にどれぐらいの スペースが 必要かを把握したり 自室でリアルな ディテールを確認できます リアリズムと言えば このビデオで本物の植物を 見つけられましたか? そう この白いプランターの 植物です このテーブルの左端に あるやつですね 2021年の公開以来 Object Capture APIが このように幅広く使われて いることを 嬉しく思っています 次は ARKitで強化された カメラ機能についてです これはObject Captureで行う 再構築の品質を高めるのに 大いに役立つはずです Object Capture体験を 成功させるには まずはあらゆる方向から 物体の写真を撮影します 高解像度のカメラであれば 何を使っても構いません iPhoneでもiPadでも DSLRやミラーレスカメラ でも良いです iPhoneやiPadの カメラAppを使えば 深度や重力情報を含む 高画質の写真が撮影でき Object Capture APIで 物体の実際のスケールや 向きを自動的に 復元することができます さらにiPhoneやiPadを お使いの場合は ARKitのトラッキング機能を 活用して モデルの上に3Dガイダンス UIを重ね あらゆる方向から物体を 満遍なく捉える事ができます もう1つ重要な点は 画像の解像度が高いほど Object Captureで生成できる 3Dモデルの質も上がります そのため 今年のARKitでは 高解像度のバックグラウンド フォトAPIが 新たに導入されています このAPIを使用すると ARSessionを実行しながら カメラのネイティブ解像度で 写真を撮影できます デバイスでカメラの センサーをフル活用しながら 3D UIを重ねて表示する こともできます iPhone 13の場合ですと 1200万画素 ネイティブ解像度の ワイドカメラになります このAPIは非侵入型なものです ARSessionの連続的な ビデオストリームが 中断されないため Appは引き続きスムーズな AR体験をユーザーに 届けることができます さらにARKitではEXIF メタデータが利用可能になり ホワイトバランス 露出 その他の設定など ポストプロセスに役立つ 可能性がある有益な情報を Appから読み取ることが できるようになりました ARKitがあれば新しいAPIの 使い方は非常に簡単です 高解像度のフレーム キャプチャをサポートする ビデオフォーマットを ARWorldTrackingConfgurationで クエリし 成功したら 新しいビデオフォーマットを 設定しARSessionを実行します 高解像度写真の キャプチャについては ARSessionの新しい captureHighResolutionFrame API 関数を呼び出すと コンプリーションハンドラ経由で 非同期で高解像度写真が 返されます それだけでOKです また 手動でカメラ設定を 行う方が 望ましい場合があることも 事実です フォーカス 露出 ホワイトバランスなど そのためAVCaptureDeviceに 直接アクセスし プロパティを変更して きめ細やかなカメラ制御を 行うための便利な方法も 提供しています このコード例からも わかるとおり ARWorldTrackingConfigurationで configurableCaptureDevice ForPrimaryCameraを呼び出し 基盤のAVCaptureDeviceに アクセスします これらの強化機能の 詳細については 今年のWWDCの "ARKit 6について"のセッションを ご確認いただくことを 強くお勧めします では Object Captureの ベストプラクティス ガイドラインを 見ていきましょう 何よりもまず先に Object Captureの 特性に適した被写体を選ぶ 必要があります 表面に適度な質感がある 物体がお勧めです 領域の一部のテクスチャが なかったり 透明だと その領域の細部が上手く 再構築されない事があります 反射や強い光が当たっていない ことも大切です マットな表面がない 被写体の場合は 拡散光を使って 鏡面反射を減らすことが できます 被写体をひっくり返して 底面を撮影する時は 被写体が動かないように 注意して下さい 反転させても形が変わらない ように気を付けます 最後に すぐれた被写体は ある程度細かい構造を 持ち合わせてはいますが 被写体の細部を復元するには 高解像度カメラで アップの写真を 撮る必要があります 次に重要なことは 理想的な撮影環境を 整えることです 撮影環境に均一で良質の 拡散光があることを 確認して下さい 被写体の周囲に十分な 空間があり 背景が安定していることも 重要です 部屋が暗い場合は 明るいターンテーブルを 使います 次に 被写体を上手に 撮影するための ガイドラインを紹介します これに従えば Object Captureから 質の高い3Dモデルを 作成できます 例として同僚のMauneshが iPhoneを使って どのように美しい 海賊船の写真を撮影したかを ご紹介します この船は ARKitエンジニアの Christian Lipskiが 作ってくれたものです Mauneshはまず 海賊船を きれいなテーブルの 中央に置きました これによって船がはっきりと 浮かび上がります 彼はiPhoneを両手で しっかりと持ちます 船の周囲をゆっくりと 回りながら 様々な高さで写真を 撮影します カメラの視野の中心に 十分な大きさで 船が収まるようにし 細部を 最大限に捉えられる ようにします また 隣接した2枚の写真の 重なり具合が 高いことも確認しましょう 十分な数の 写真が撮れたら ここでは80枚ほどですが 船を横向きにして 船底も再構築できる ように撮影します 船を横向きにした状態で さらにもう20枚ほど 写真を撮ります 彼はiPhoneを ランドスケープモードで 持っていますね これは横に長い被写体を 撮影しているからで ランドスケープモードなら 被写体の細部を 最大限に捉える事が できるからです でも 縦に長い被写体を 撮影する場合は ポートレートモードが 必要になるかもしれません
これだけです 最後のステップでは写真を Macにコピーし Object Capture APIを使って 処理します 4つの詳細レベルから 選ぶことができ 様々な用途に合わせて 最適化されています reducedレベルやmediumレベルは AR QuickLookで 3Dコンテンツを閲覧する 場合など Webベースや モバイルでの体験に 最適です この詳細レベルで再構築 されたモデルは 三角形やマテリアル チャンネルが少なく 消費メモリが 少なくて済みます fullやrawの詳細レベルは コンピューターゲームや ポストプロセスのワークフローなど インタラクティブな事例で 使われます 最高レベルの幾何学的詳細が 含まれており ベイク処理と ベイクなしから自由に 選べますが 再構築には より多くのメモリが 必要です 用途に応じて正しい 出力レベルを 選ぶことが大切です この海賊船には“medium”の 詳細レベルを選んだので M1 Macでの処理には数分しか かかりませんでした 出力された3Dモデルが あまりに見事だったので この海賊船が波の高い海を 航海する 動画クリップを作りました Object Captureの威力は こんなにすごいのです! “おーい!” ここからRisaにバトンタッチ RealityKitでObject Captureを使った エンドツーエンドのワーク フローを紹介してもらいます ありがとう Hao Object Capture APIの 説明が終わった所で エンドツーエンドの開発 ワークフローに移り RealityKitで現実の物を ARに取り込みましょう 各ステップはサンプル ワークフローを使って 詳しく説明しますので まずは早速デモを ご覧下さい 同僚のZachは 木工細工が趣味で 先日 6つの巨大な 木製のチェスの駒を 作りました このチェスの駒を見ていたら インタラクティブなARチェス ゲームを作りたくなりました これまで現実世界の物の 高品質な3Dモデルを作るには 3Dモデラ―とマテリアルの 専門家が必要でした でもObject Capture APIが あれば チェスの駒を直接撮影し 拡張現実に取り込むだけで いいのです まずはルークの撮影から 始めましょう ここでは同僚のBryanが 前述のベストプラクティスを 念頭に置いて プロフェッショナルなセットを 使用しています ここでBryanはルークを このターンテーブルに置き プロ仕様の照明を当てて 最終出力に強い影が 出るのを防ぎます iPhoneのカメラを ターンテーブルで使うと 出力したUSDZに自動 スケール推定と重力ベクトル 情報が含められます この件の詳細は2021年の Object Captureの セッションを参照して下さい もちろんBryanのような 凝ったセットがない場合は iOSデバイスを手に持ち 被写体の周りを歩いて 撮影することもできます これでルークの駒の写真が全て 揃ったので これをMacに転送します 写真の処理には2021年に 導入された PhotogrammetrySession APIを 使用します ベストプラクティスに従って 再構築にはreducedの 詳細レベルを使用して AR Appの性能が 落ちないようにします APIの最終出力は USDZ ファイルタイプのモデルです これが再構築したルークの チェスの駒の 最終出力です 時間節約のために 他の5つの駒の写真も 先に撮影しておきました チェスの駒に1つの配色だけを 使ってどうやってゲームを 作るのかしらと思う方も いるかもしれません 6つの駒を複製して Reality Converterに ドラッグしましょう 元のテクスチャの色を 反転させて 複製セットを新たに反転した テクスチャに置き換えました こうすればプレイヤーごとに 明るいバージョンの駒と 暗いバージョンの駒の セットができます “書き出し”メニューで圧縮 テクスチャのオプションを オンにして モデルを書き出します これでテクスチャのメモリの フットプリントを 減らすことができます
チェスの駒のセットが全て 揃ったので モデルをXcodeプロジェクトに 取り込みます 私はRealityKitを使って チェス盤を作りました Y軸のプリミティブ立方体を 縮小し 白と黒を交互に入れ替えました 再構築した全てのチェス駒を チェス盤に置くとこうなります 実物をAppの中で 見るだけでもワクワクですが さらに機能を追加して インタラクティブなゲームを 作りましょう この部分のデモでは 既存のテクノロジーをいくつか ご紹介したいと思います そうすればご希望の出力を 作成するには どのように テクノロジーを組み合わせるべきか 例を示せると思います RealityKitの高度なトピックの 実践的な活用事例を 説明するにあたって APIの知識がまだ少ない方は 2021年のRealityKit セッションを ご確認されることを お勧めします まずはApp起動時の アニメーションを 追加したいと思います チェッカーのタイルが上から ゆっくりと落ちてきて 最終位置に収まると同時に チェスの駒も 一緒に変換される アニメーションを作ります この効果をコードで 再現するのに 必要なのは2つのステップ だけです 最初のステップでは Y軸に沿って 両方の エンティティを上に移動し 同時にチェスの駒を 縮小します 2番目と最後のステップでは 両方のエンティティを元の トランスフォームに アニメ―トします これを行うコードは 極めてシンプルです まずはチェッカータイルを 繰り返し処理していきます 各エンティティに対して チェッカータイルの現在の トランスフォームを保存します これが最終的な着地位置に なるからです 次に 各正方形をY軸沿いに 10 cm上に移動させます このmove関数を使って これをアニメートさせ 元のトランスフォームに 戻します またチェッカー盤の輪郭を 描く このボーダーUSDZIに アニメーションが組込まれて いることもわかっているので playAnimation APIを 使用して 同時にアニメーションを 開始しましょう チェスの駒にも全く同じ アニメーションを追加 ただし駒の変換に伴って スケールを変更しました これで出来上がりです 数行コードを追加するだけで 起動アニメーションが完成しました しかし 実際にチェスの駒を 動かせなければ チェスをすることは できません 次は駒を動かしましょう チェスの駒を 動かし始める前に 駒を選択できるようにする 必要があります そこで UITapGestureRecognizerを ARViewに追加しました ユーザーが特定の場所を タップすると カメラの起点から その2Dポイントを通過する レイを定義します 次にそのレイに対して 3Dシーンへのレイキャストを 実行しエンティティに当たるか 確認します チェスの駒だけを選択できる ようにしたいので チェスの駒のコリジョン グループを マスクとして指定しました raycast関数では CollisionComponentを持たない すべてのエンティティが 無視されることに ご注意下さい これでチェスの駒が 見つかった時に選択できます どの駒を選択するかが わかったので 今度はその駒が 光っているように見える 効果を追加します それを実現するために カスタムマテリアルの サーフェスシェーダを 使用します サーフェスシェーダでは Metalを通じてマテリアル パラメータの計算や指定を 行うことができ それがRealityKitの フラグメントシェーダから 1ピクセルごとに 呼び出されます Metalでこのような 炎の効果を表現する サーフェスシェーダを 作成することができます 次にこのサーフェスシェーダで カスタムマテリアルを 長方形のプリズムに適用し エンティティの外観に シェーダ効果をかけます この効果を作るための コードを書いてみましょう このサーフェスシェーダで 使用するノイズテクスチャを すでにプロジェクトに 追加してあります テクスチャを2回 サンプリングします 1つは全体の形状 もう1つはディテールに 使います さらにRGB値を取り出し 再マッピングして 外観の色を変更します そして先ほど抽出した処理値の y位置を画像の値と比較して サンプルポイントの 不透明度を計算します この効果に動きを 与えるために テクスチャのY軸を 時間の関数として 動かしていきます さらに各サンプルポイントの 対面角度と カメラの視野角を 組み合わせて 側面での効果を フェードアウトさせます これによりエッジが 柔らかくなり 基盤となる モデルの性質が 目立たなくなります 最後にサーフェス パラメータ関数を使用して 先ほど計算した色と 不透明度を設定します こちらが選択シェーダを 適用した チェスの駒となります 本当に内側から 光っているように見えます そしてこれを3つの 変換アニメーションと 組み合わせると このようになります チェスの駒を動かせる 機能を実装したので 相手の駒を捉えることも できるようになりました サーフェスシェーダと同様 ジオメトリモディファイアも カスタムマテリアルを使って 実装できます 位置 法線 テクスチャの 座標など 頂点データを 変更できる 非常に パワフルなツールです これらのMetal関数は RealityKitの頂点シェーダによって 頂点ごとに1回ずつ 呼び出されます これらの変更は一過性の ものであり 実際のエンティティの 頂点情報には 影響を及ぼしません 駒が捉えられた時に 押しつぶされるような 楽しいジオメトリ モディファイアを追加します チェスの駒のプロパティに capturedProgressという ものがあり 捕獲時の アニメーションの0から1への 進行状況を表しています 駒の捕獲はユーザー 主導のアクションなので ジオメトリモディファイアに アニメーションを開始する タイミングを伝える 必要があります そのためcustomMaterialに カスタムプロパティを 設定します こうするとCPUとGPU間の データ共有が可能になります ここではカスタム値の プロパティを使用して アニメーションの進行状況を モディファイアに渡します Metal側からアニメーションの 進行状況を抽出するために ユニフォームにカスタム パラメータを使用します このオブジェクトを縦に スケールし 他の駒に潰されるように したいので スケールの軸をy方向に 設定します アニメーションを少し 複雑化するために x軸のジオメトリも変更して 波のような効果も 加えたいと思います 頂点のオフセットは set_model_position_ offset 関数を使用して設定できます ジオメトリモディファイアの 最終成果はこちらです 潰される前に x軸に沿って縦に伸びてから 少し大きくなっているのが わかるでしょう 自分がチェスの初心者なので 選択した駒をどこに 動かせるか教えてくれる 機能を追加したら ゲームを覚えるのに 役立つと思いました チェッカーの駒は独自の Model Componentを持つ 個別のエンティティなので サーフェスシェーダで 駒の動きの候補に パルス効果をかけて 他の駒と区別します 次に“ブルーム”と言う ポストプロセス効果を追加して この効果をさらに 強化します グロー効果を出す時に サーフェスシェーダで 使用したカスタムパラメータを ここでも使用します この場合はCPU側から Booleanを Metalサーフェスシェーダに 渡します このチェッカーが 可能な動きである場合に 色を変えることでパルス 効果を加えたいと思います ここの光っている色に パルスを追加します 最後にビュー全体に ブルーム効果を追加します ブルームとは明るい部分の 境界から 光の羽を生み出す ポストプロセス効果です これを行うにはARViewで レンダーコールバック プロパティを使用します ブルーム効果の作成には すでに組み込まれている Metalパフォーマンス シェーダ関数を使います 次に renderCallbacks.postProcess クロージャをブルーム関数 として設定します チェッカーにパルスをかけると 白色が強調され これがブルーム効果により さらに強調されます サーフェスシェーダと ブルーム効果の併用により 駒をどこに動かせば良いかが はっきりわかります 最後にこれらをすべて 組み合わせて AR Appで現実の チェスの駒に 命を吹き込みましょう 追加した全ての機能が どのように見えるか ご覧下さい ご参考までに セッションリソースに このサンプルプロジェクトの リンクを貼りました ぜひダウンロードして お使いの環境で 試してみて下さい とてもシンプルです 巨大なチェスの駒を 撮影して再構築し AR Appに取り込むまでを ご説明しました 今日のセッションは 盛り沢山だったので 重要なポイントを まとめたいと思います まず 2021年に発表した Object Capture APIの おさらいから開始しました 続いてARSessionが アクティブな時に カメラのネイティブ解像度で 必要な時に写真が撮れる ARKitの新しいAPIについて 紹介しました Object Captureテクノロジーを 最大限に活用できるように 再構築に適した被写体の タイプや 高画質を 得るための理想的環境 また撮影時に従うべき 推奨フローなども 説明しました セッションの後半では エンドツーエンドの開発 ワークフローの例を紹介 巨大なチェスの駒の 写真を撮影し この画像をPhotogrammetrySession API への入力に使用して 3Dモデルを作成しました 次にそのモデルをReality Converterにインポートし テクスチャを置き換え 最後にチェスゲームを 少しずつ構築し ARでチェスの駒の動きを 確認しました 本日のセッションは 以上です ご視聴ありがとうございました “おーい!” ♪
-
-
6:20 - HighRes capturing
if let hiResCaptureVideoFormat = ARWorldTrackingConfiguration.recommendedVideoFormatForHighResolutionFrameCapturing { // Assign the video format that supports hi-res capturing. config.videoFormat = hiResCaptureVideoFormat } // Run the session. session.run(config) session.captureHighResolutionFrame { (frame, error) in if let frame = frame { // save frame.capturedImage // … } }
-
17:00 - Chessboard animation
// Board Animation class Chessboard: Entity { func playAnimation() { checkers .forEach { entity in let currentTransform = entity.transform // Move checker square 10cm up entity.transform.translation += SIMD3<Float>(0, 0.1, 0) entity.move(to: currentTransform, relativeTo: entity.parent, duration: BoardGame.startupAnimationDuration) } // Play built-in animation for board border border.availableAnimations.forEach { border.playAnimation($0) } } }
-
18:00 - select chess piece
// Select chess piece class ChessViewport: ARView { @objc func handleTap(sender: UITapGestureRecognizer) { guard let ray = ray(through: sender.location(in: self)) else { return } // No piece is selected yet, we want to select one guard let raycastResult = scene.raycast(origin: ray.origin, direction: ray.direction, length: 5, query: .nearest, mask: .piece).first, let piece = raycastResult.entity.parentChessPiece else { return } boardGame.select(piece) gameManager.selectedPiece = piece } }
-
21:16 - capture geometry modifier
// Capture Geometry Modifier class ChessPiece: Entity, HasChessPiece { var capturedProgress: Float get { (pieceEntity?.model?.materials.first as? CustomMaterial)?.custom.value[0] ?? 0 } set { pieceEntity?.modifyMaterials { material in guard var customMaterial = material as? CustomMaterial else { return material } customMaterial.custom.value = SIMD4<Float>(newValue, 0, 0, 0) return customMaterial } } } }
-
23:00 - highlight potential moves using bloom
// Checker animation to show potential moves void checkerSurface(realitykit::surface_parameters params, float amplitude, bool isBlack = false) { // ... bool isPossibleMove = params.uniforms().custom_parameter()[0]; if (isPossibleMove) { const float a = amplitude * sin(params.uniforms().time() * M_PI_F) + amplitude; params.surface().set_emissive_color(half3(a)); if (isBlack) { params.surface().set_base_color(half3(a)); } } }
-
23:20 - Import MetalPerformanceShaders
import MetalPerformanceShaders class ChessViewport: ARView { init(gameManager: GameManager) { /// ... renderCallbacks.postProcess = postEffectBloom } func postEffectBloom(context: ARView.PostProcessContext) { let brightness = MPSImageThresholdToZero(device: context.device, thresholdValue: 0.85, linearGrayColorTransform: nil) brightness.encode(commandBuffer: context.commandBuffer, sourceTexture: context.sourceColorTexture, destinationTexture: bloomTexture!) /// ... } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。