見出し画像

Lesson 3A.3 Finding Flat Surfaces

これまでこのユニットでは、SceneKitが3次元シーンの構築にどのように役立つかについて少し学びました。ARKitを使用してカメラ情報を表示し、オリジンを提供しましたが、飛行機を検出するという最も価値のある機能を利用していません。

このレッスンでは、平面検出を有効にし、新しい平面の検出に対応し、既存の平面を更新する方法を学びます。そこから、作成したSceneKitモデルをスペースに浮かべたままにするのではなく、サーフェスに配置できます。

あなたが学ぶこと

平らな面の検出を可能にする方法

平面検出への対応方法

検出された平面を視覚化する方法

検出された平面にSceneKitアセットを配置する方法

Vocabulary
anchor
extent
feature point
plane detection

p.472 
フィーチャーポイント

ARKitは、iOS開発者にとって非常に複雑なタスクを簡素化します。ARKitがデバイスの動きと向きに自動的に反応することをすでに観察しました。各プロジェクトでは、動き回ると、シーン内のオブジェクトが空間に固定されているように見えます。しかし、フレームワークはまた、カメラからビデオフレームを取り込み、機能ポイントのためにそれらを分析しています。フィーチャーポイントは、シーンを分析するときに発見されたコーヒーカップ、ソファの端、平らな床など、検出可能な物体と考えることができます。

ARKitの機能ポイントのリストを視覚化するには、シーンビューにアタッチされたdebugOptionsのコレクションにARSCNDebugOptions.showFeaturePointsを追加します。

機能ポイントを追跡するための推奨事項

これらのオプションを新しいARプロジェクトに追加し、デバイスでコードをビルドして実行してみてください。どのサーフェスや環境が最も多くの機能ポイントを含んでいるように見えるかに注意してください。予想通り、より多くの機能ポイントにより、拡張現実でのオブジェクトのより正確な配置と追跡が可能になります。

機能ポイントの追跡を改善するための推奨事項をいくつか紹介します。

表面の質感。ソリッドブラウンの卓上やデスクトップと同様に、サーフェスがプレーンすぎると、ARKitはオブジェクトを機能として検出するのに苦労します。特徴検出を改善するには、カーペット敷きの床や布張りの椅子などの質感のある表面にカメラを配置してみてください。

照明。十分な光がなければ、ARKitはカメラ情報を効果的に処理できません。また、光沢のある表面は、ARKitが機能を検出することを困難にします。反射しない表面の明るい部屋でARプロジェクトを実行してみてください。

動き。ARKitは、デバイスの加速度センサーとジャイロスコープから検出されたカメラ情報と動きを追跡します。しかし、動きが速すぎると、ARKitが位置を適切に追跡できず、3Dオブジェクトが元の場所から離れることがあります。シーン内を移動しながら、ゆっくりと安定したペースで移動し、カメラを通して周囲を見るために徐々に回してみてください。

p.473 
平面検出

十分なフィーチャポイントに同じy座標が含まれている場合、ARKitはシーンに水平面が存在することを判断できます。しかし、まず、飛行機を探していることをシステムに伝える必要があります。

シーンビューのセッションの一部として、ARWorldTrackingConfigurationという設定があります。この設定を微調整して水平面を検索するには、planeDetectionプロパティを有効にし、その値を.horizontalを含めるように設定できます。

ARKitがいつ現場で飛行機を発見したか、どうやってわかりますか?拡張現実アプリのテンプレートから次のコード行を思い出してください。

このコードは、sceneViewオブジェクトに情報(つまり、ビューコントローラ)に送信するように指示します。XcodeでOptionキーを押しながらデリゲートをクリックし、ポップアップのARSCNViewDelegateリンクをクリックしてドキュメントを表示します。

p.474 
Xcodeのドキュメントには、コンテンツの更新を処理するための5つの方法が記載されています。関心のある最初の方法はレンダラー(_:, didAdd:, for:)で、ARKitが新しいアンカーを見つけることを報告するたびにトリガーされます。

Xcodeの自動補完機能とコンテキスト認識機能を使用して、ARSCNViewDelegateに準拠したクラス定義内に「renderer」の入力を開始します。リストからレンダラー(_ renderer:, didAdd:, for:)メソッドを選択し、Returnキーを押してメソッドヘッダーと空のボディをクラスに追加します。

p.475 
アンカーは、ARシーンにオブジェクトを配置するための位置と向きの両方です。水平平面検出を有効にすると、ARKitは検出された平面ごとに自動的に新しいアンカーを作成します。Renderer(_:, didAdd:, for:)メソッドが呼び出され、子ノードの追加に使用できるSCNNodeが提供されます。

ビューコントローラが新しいアンカーポイントに関するメッセージを受信していることをテストするには、新しい平面が検出されるたびに簡単なメッセージを印刷させることができます。アンカーには複数のタイプ(ARPlaneAnchor、ARImageAnchor)があるため、guardステートメントを使用して、ARPlaneAnchorが検出されたアンカータイプの場合にのみ印刷関数を実行できます。

アプリをビルドして実行します。次に、床、机、テーブル、またはその他の平らな面を調べて、印刷ステートメントを確認します。

平面の視覚化

しかし、検出された飛行機を見ることができると思いませんか?検出されたアンカー全体をカバーするSCNPlaneオブジェクトを追加できます。シーン内を移動すると複数の平面が検出される可能性があるため、SCNPレーンをジオメトリとする新しいSCNNodeを返すメソッドがあると便利です。

以下は、床を見通すことができる半透明の平面を作るための方法(レッスン2のloadSidewalksメソッドに似ています)の最初のテイクです。

p.476 
Renderer(_:, didAdd:, for:)メソッド内で、発見された平面アンカーごとに新しいフロアを作成し、提供されたSCNNodeにアタッチします。

この新しいコードでアプリを実行すると、2つの問題が見つかります。まず、半透明の平面はシーン内の平面のサイズを正確に反映しません。それは常に1m×1mの正方形です。第二に、2つの平面が互いに重なっているのを見るかもしれませんが、実際には1つの大きな平面にマージする必要があります。

これらの問題に対処する方法を見てみましょう。

p.477 
飛行機のサイズの調整

ARPlaneAnchor内には、検出された平面の推定幅と高さを与えるエクステントプロパティがあります。ARPlaneAnchorをパラメータとしてcreateFloorメソッドに渡すと、そのエクステント値を使用してSCNPlaneのサイズを適切に設定できます。水平平面のy値は0になるので、サイズ変更にはx値とz値を使用する必要があります。

これで、ARKitが水平面を検出すると、半透明の床は最初に検出されたときの平面のサイズと一致します。

p.478 
飛行機の更新とマージ

ARKitはシーンに関する詳細情報を収集し続けているため、2つのARPlaneAnchorオブジェクトが実際には1つの大きな平面であることを発見するかもしれません。この発見により、アンカーの1つが自動的に削除され、もう1つが領域全体にまたがるように拡大します。ノードが削除されたときに通知を受け取るには、レンダラー(_:, didRemove:, for:) メソッドを使用します。検出されたアンカーと一致するようにノードのプロパティが更新されたときに通知を受け取るには、レンダラー(_:, didUpdate:, for:) を使用します。

シーングラフのSCNPlaneのインスタンスはどうですか?ARKitは半透明平面に接続された親ノードを削除しているため、子ノードは自動的に削除されます。ただし、飛行機のアンカーのサイズが大きくなった場合は、SCNPlaneのサイズを更新する必要があります。また、アンカーの範囲が変更されると、その中心も変更されるため、その位置を更新する必要があります。

次のクリップは、その範囲が大きくなるにつれて、平面アンカーの中心プロパティがどのように調整されるかを示しています。

SCNPレーンを更新する方法は1つです。guardステートメント(前のメソッドのguardステートメントに似ています)を使用して、更新されたアンカーがARPlaneAnchorであることを確認し、最初の子ノードのジオメトリがSCNPlaneであることを確認することができます。それが確立されると、ノードの位置とサイズをアンカーのそれぞれのプロパティに一致させることができます。

p.479 
その結果、重複する小さな平面を見るのではなく、シーンに関するより多くの情報が発見されると、既存の平面が増加するのを見ることができます。

資産と飛行機の接続

発見されたアンカーの上に新しいノードを作成する方法がわかったので、作成したシーンを物理的なサーフェスに接続するのは本当に簡単です。アンカーが時間の経過とともにどのように変化するかに関係なく、船を飛行機の中央に保ちながら、発見されたすべての飛行機の上に拡張現実アプリのテンプレートから船を置きたいと想像してみてください。

プロジェクトでship.scnファイルを開き、船の位置を(0,0,0)に戻します。(デフォルトでは、船の初期位置は原点より0.1メートル上、0.8メートル後ろです。)

p.480
新しい飛行機が発見されるたびに床を追加することに加えて、船に一致するジオメトリを持つノードを作成する必要があります。複数の飛行機が見つかる可能性があるため、クローンメソッドは船のコピーを作成します。(コピーを作成しないと、1隻の船が新しく発見された各飛行機にジャンプします。)そして、床と同じように、アンカーの中央のプロパティを使用して船を真ん中に置くことができます。

より多くのデータが収集され、発見された飛行機が大きくなるにつれて、飛行機のアンカーの中心に合わせて船の位置と半透明の平面を更新できます。前のセクションで述べたように、飛行機のサイズも更新する必要があります(ただし、船のサイズは同じままです)。

p.481

演習

学校のキャンパスをプロジェクトにインポートし、最初に発見された飛行機の上にシーンを置きます。

ARKitは垂直面も検出できます。赤い壁紙で壁を覆うアプリを作成します。(ヒント: ARPlaneAnchor には、水平面と垂直面を区別するためのアライメントプロパティがあります。)

水平面と垂直面の両方の検出を有効にするようにアプリを変更します。すべての壁に赤い平面を置き、すべての水平面に緑色のボックスを置き、配置するオブジェクトが表面全体を覆うようにサイズ変更されていることを確認します。(ヒント: ARPlaneAnchor には、水平面と垂直面を区別するためのアライメントプロパティがあります。)

p.482 

この記事が気に入ったらサポートをしてみませんか?