ハイライト
オブジェクト キャプチャ チームの Hao Tang と Risa が、オブジェクト キャプチャ テクノロジーの最新の進歩とベスト プラクティスを紹介します。 Object Capture は、実際のオブジェクトの写真を詳細な 3D モデルに変換する Apple の写真測量 API です。
主要内容
多くの AR 体験で難しいのは、AR 自体ではなく、素材です。本物の木製チェスの駒をゲームに組み込むには、以前は 3D モデラーとマテリアルの専門家が関与していました。形状、質感、プロポーションをすべて手作業で加工する必要があり、非常にコストがかかります。
オブジェクト キャプチャは、このプロセスを 2 つのステップに圧縮します。最初に実際のオブジェクトを複数の角度から撮影し、次にその写真を macOS 上のフォトグラメトリ API に渡して USDZ モデルを生成します。 RealityKit は幾何学的メッシュとマテリアル マップを出力し、モデルは AR またはゲーム プロジェクトに直接取り込むことができます。
このセッションでは、特大の木製チェスの駒の例を使用して、プロセス全体をつなぎ合わせます。まず、チェスの駒を写真に撮り、USDZ に処理します。次にモデルを Reality Converter にインポートしてテクスチャを調整します。そして最後にそれを Xcode の RealityKit プロジェクトに組み込んで、クリック、移動、光り、食べることができる AR チェス盤を作成します。
Apple は WWDC 2022 で重要なリンクも追加しました: ARKit は、ARSession の実行中にネイティブのカメラ解像度で写真を撮影できます。開発者は、オブジェクト キャプチャにより適した高解像度の画像を取得しながら、3D ガイド付き UI を表示し続けることができます。
詳細
ARSession で高解像度の写真を撮影する
(05:15) オブジェクト キャプチャの入力品質は 3D モデルの品質に直接影響します。 Hao 氏は、画像の解像度が高いほど、オブジェクト キャプチャで生成できるモデルの品質が向上することを明らかにしています。
(06:20) ARKit 6 は、高解像度の背景写真 API を提供します。これにより、ARSession の実行を継続しながら、アプリがネイティブのカメラ解像度で写真を撮影できるようになります。 iPhone 13のワイドカメラは1200万画素に対応。
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
// …
}
}
キーポイント:
recommendedVideoFormatForHighResolutionFrameCapturing現在のデバイスに高解像度の写真のキャプチャをサポートするビデオ形式があるかどうかを照会します。 -config.videoFormat = hiResCaptureVideoFormatARWorldTrackingConfiguration をこの形式に切り替えます。 -session.run(config)新しい構成で ARSession を開始します。 -captureHighResolutionFrame高解像度の ARFrame を非同期で返します。 -frame.capturedImageその後保存され、オブジェクト キャプチャ プロセスに送信されるのは画像データです。
この API の価値は、撮影プロセスが中断されないことです。ユーザーには引き続き AR オーバーレイが表示され、アプリは 3D を使用して UI をガイドし、まだキャプチャしていない角度をユーザーに知らせることができます。
オブジェクト キャプチャに適した主題を選択してください
(07:44) オブジェクト キャプチャは、表面に十分なテクスチャがあるオブジェクトに適しています。透明、反射、テクスチャのない領域では、再構築の詳細が貧弱になります。
撮影環境も重要です。 Hao 氏は、均一な拡散光を使用し、背景を安定させ、オブジェクトの周囲に十分なスペースを残すことを推奨しています。部屋が暗い場合は、明るいターンテーブルを使用してください。
(09:24) この例の海賊船は、きれいなテーブルの中央に配置されています。撮影者は被写体の周りをゆっくりと移動し、被写体が常にフレームの中心を占め、隣接する写真間の重なりが高度に維持されるように、さまざまな高さから撮影します。
(10:15) この例では、最初に約 80 枚の写真を撮り、次にボートを横にして約 20 枚の写真を撮って船底を再構築します。 Hao 氏は、この方法が適しているのは、オブジェクトが反転した後も硬いままである場合にのみであることも思い出させました。
PhotogrammetrySession を使用して USDZ モデルを生成する
(11:00) 写真がキャプチャされると、Mac にコピーされ、Object Capture API によって処理されます。出力詳細レベルには、縮小、中、完全、生の 4 つがあります。
[reduced] と [medium] は Web、モバイル、AR Quick Look 向けで、三角形とマテリアル チャネルが少なく、メモリ使用量が低くなります。 Full および Raw は、ゲームやポストプロダクションなどのハイエンドのインタラクティブ シナリオを目的としています。幾何学的詳細が高く、より多くのメモリを必要とします。
(14:17) AR チェス盤の例では、Risa はPhotogrammetrySessionルークの写真を処理し、低減された詳細レベルを選択します。理由は簡単です。AR ゲームは安定して動作する必要があり、モデルが重すぎてはいけないからです。
このセッションでは、PhotogrammetrySession のコード スニペットは提供されません。サポートする入り口は公式リソースに記載されています。Creating a photogrammetry command-line appそしてUsing object capture assets in RealityKit、実装の開始点として適しています。
オブジェクト キャプチャ モデルを RealityKit ゲーム オブジェクトに変える
(15:26) チェスの駒のモデルが Xcode にインポートされた後、Risa は RealityKit を使用してチェス盤を作成しました。チェッカーボードはスケールされたプリミティブ立方体から派生し、色は黒と白が交互になります。
(17:00) アニメーションを開始するには 2 つの手順があります。まず、チェッカーボードを y 軸に沿って 10 cm 上に移動し、次に次を使用します。move(to:relativeTo:duration:)元の変換に戻ります。境界線 USDZ には独自のアニメーションが付属しており、直接呼び出すことができます。playAnimation。
// 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)
}
}
}
キーポイント:
checkers.forEach各チェッカーボード エンティティを走査します。 -currentTransform最終的な着陸地点を保存します。 -translation += SIMD3<Float>(0, 0.1, 0)まずはグリッドを10cm上げます。 -move(to:relativeTo:duration:)指定された時間内にエンティティを保存された変換に戻します。 -border.availableAnimationsUSDZ 内の既存のアニメーションを読み取ります。 -border.playAnimation($0)境界モデルの組み込みアニメーションを再生します。
このスニペットはモデル アセット自体を変更するのではなく、RealityKit シーン内のエンティティの変換を操作するだけです。
レイキャストを使用して実際のチェスの駒モデルを選択する
(18:00) チェス盤をインタラクティブにするための最初のステップは、チェスの駒を選択することです。リサが入れたUITapGestureRecognizerARView に追加します。ユーザーが画面をクリックすると、アプリはカメラの原点からクリックされた位置にレイを放射し、3D シーンでレイキャストを実行します。
// 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
}
}
キーポイント:
sender.location(in: self)ARView でのユーザーのクリックの 2D 座標を取得します。 -ray(through:)2D クリック ポイントをカメラからの 3D レイに変換します。 -scene.raycast3D シーンでヒットしたエンティティを検索します。 -length: 5レイキャストの距離を制限します。 -query: .nearest最新のヒットのみが取得されます。 -mask: .pieceチェスの駒の衝突グループのみを検出します。 -parentChessPieceヒットした子エンティティからチェスの駒オブジェクトを返します。 -boardGame.select(piece)そしてgameManager.selectedPieceゲームのステータスを更新します。
Risa は、レイキャストは次のことを無視することを特に思い出させます。CollisionComponent実在物。オブジェクト キャプチャ モデルをインポートした後、それをクリックする場合は、衝突コンポーネントを見逃すことはできません。
CustomMaterial を使用して、CPU と GPU の間でアニメーションの進行状況を転送します。
(20:38) 食べるアニメーションでは、RealityKit カスタム マテリアルのジオメトリ モディファイアを使用します。これらは RealityKit の頂点シェーダーで頂点ごとに呼び出され、位置、法線、テクスチャ座標などの頂点データを変更できます。
(21:16)capturedProgressキャプチャ中の作品のアニメーションの進行状況を 0 ~ 1 の範囲で示します。CPU 側はこの値をCustomMaterial.custom.value、メタル側はユニフォームのカスタムパラメータを通じてそれを読み取ります。
// 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
}
}
}
}
キーポイント:
capturedProgressこれは、チェスの駒エンティティのステータス属性です。- ゲッターは最初のマテリアルから読み取ります
CustomMaterial.custom.value[0]。 - 読み取りに失敗した場合に返されます
0、アニメーションがまだ開始されていないことを示します。 -modifyMaterials固形物をトラバースして交換します。 -guard var customMaterial = material as? CustomMaterialカスタムマテリアルのみを扱います。 -SIMD4<Float>(newValue, 0, 0, 0)アニメーションの進行状況をカスタム値の最初のチャンネルに入れます。 - 変更したものを返す
customMaterial, RealityKit は新しい値をシェーダーに送信します。
(21:50) Metal 側は、この進行に従って y 方向をスケーリングし、x 方向に波のオフセットを追加します。 Risa さんは、これらの変更は一時的なものであり、エンティティの元の頂点データは変更しないと述べました。
サーフェス シェーダとブルームを使用して移動可能な位置をマークする
(22:30)初心者が駒がどこに移動できるかを理解できるように、この例ではチェッカーボードの潜在的な着地点にパルス効果を追加しています。各チェッカーボードは独立したエンティティであり、独自のモデル コンポーネントがあるため、サーフェス シェーダを個別に適用できます。
(23:00) CPU 側はブール値を渡し、メタル サーフェス シェーダーはカスタム パラメータを読み取ります。現在のグリッドが着地点となる可能性がある場合は、発光色を変更します。
// 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));
}
}
}
キーポイント:
checkerSurfaceRealityKit サーフェス シェーダによって使用される Metal 関数です。 -params.uniforms().custom_parameter()[0]CPU側から渡されたカスタム値を読み取ります。 -isPossibleMove現在のチェッカーボードを強調表示する必要があるかどうかを決定します。 -sin(params.uniforms().time() * M_PI_F)時間をかけてパルス変化を生成します。 -set_emissive_color(half3(a))自己照明の色を変更します。- 黒の市松模様の追加呼び出し
set_base_color、ハイライトをより明確にします。
(23:20) 照明効果をより明確にするために、この例では ARView にブルーム後処理を追加しています。実装エントリはrenderCallbacks.postProcess、特定の画像処理にはメタル パフォーマンス シェーダーが使用されます。
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!)
/// ...
}
}
キーポイント:
import MetalPerformanceShadersメタル パフォーマンス シェーダーの紹介。 -renderCallbacks.postProcess = postEffectBloomカスタム後処理を ARView レンダリング プロセスに接続します。 -ARView.PostProcessContext後処理に必要なデバイス、commandBuffer、テクスチャを提供します。 -MPSImageThresholdToZeroしきい値を使用して明るい領域を除外します。 -thresholdValue: 0.85しきい値を下回る色は抑制されます。 -brightness.encode処理コマンドを現在のコマンド バッファにエンコードします。 -sourceColorTextureARView によってレンダリングされるカラー テクスチャです。 -bloomTexture輝度フィルタリング後の中間結果を受け取ります。
重要ポイント
-
製品 AR プレビュー ツールの作成: オブジェクト キャプチャを使用して製品 USDZ を生成し、RealityKit を使用してそれをユーザー空間に配置します。靴、植物、装飾品などのテクスチャ付きの低反射オブジェクトに適しています。開始点はショットの仕様、PhotogrammetrySession、および RealityKit モデルの読み込みです。
-
撮影ガイダンス付きの 3D スキャン アプリを作成: ARSession でオーバーレイを表示し、ユーザーにさまざまな高さと角度から撮影するように促します。使用
captureHighResolutionFrame写真をネイティブ解像度で保存し、処理のために Mac に転送します。 -
本物のおもちゃを AR キャラクターに変えるゲーム プロトタイプを作成します: まずオブジェクト キャプチャを使用しておもちゃをスキャンし、次に衝突コンポーネント、クリック選択、移動アニメーションを RealityKit のモデルに追加します。例では
scene.raycastそしてmove(to:relativeTo:duration:)インタラクティブなポータルとして直接使用できます。 -
RealityKit カスタム マテリアル エフェクト ライブラリのセットを作成: 選択したグロー、スキッシュ、および潜在的な位置パルスなどのエフェクトを再利用可能なコンポーネントに抽出します。 CPU サイドパス
CustomMaterial.custom.value状態が渡され、GPU 側はサーフェス シェーダーまたはジオメトリ モディファイアを使用してアニメーションを実行します。 -
AR 教育チェス盤の作成: ルールに従って可動グリッドを計算し、その結果をチェス盤マテリアルのカスタム パラメーターに書き込み、発光色とブルームで強調表示します。この方向は、チェス、国際チェス、ボードゲームのルールを教えるのに適しています。
関連セッション
- Discover ARKit 6 - このセッションの高解像度写真キャプチャ機能は ARKit 6 から提供されており、カメラと ARSession のアップデートについて学び続けるのに最適です。
- RoomPlan を使用してパラメトリック 3D ルーム スキャンを作成する — AR スキャンに関しても同様ですが、ターゲットが個々のオブジェクトから部屋構造に拡張される点が異なります。
- MetalFX アップスケーリングによるパフォーマンスの向上 - AR ゲームで後処理と高品質のレンダリングが追加される場合は、MetalFX のパフォーマンスの向上に注意する必要があります。
- Discover Metal 3 - このセッションのカスタム マテリアル、シェーダー、後処理はすべて Metal のグラフィックス機能に隣接しています。
コメント
GitHub Issues · utterances