これちのPost-it

技術ネタをペラペラと

HoloLens の Spatial Understanding について調べてみた

参考URL

github.com

Spatial Understanding

Spatial mapping のメッシュ上にオブジェクトを置くとき、床・天井・壁の認識が必要となる。加えて、ホログラフィックオブジェクトの最も望ましい物理的な位置を決定するために、配置制約をもとに最適化することも必要となる。
- これち:この配置制約というのはおそらくSpatialMappingで取得したメッシュ内で、という制約
この課題を解決するため room solver を開発した。これらのコア技術は HoloToolkit.SpatialUnderstanding ライブラリ内に存在しこれを使うことで以下のことが可能となる。
1. 壁の空いたスペースを探す 2. 天井にオブジェクトを配置 3. キャラクターが座ることのできる場所の特定 4. その他の空間クエリ
これらのコードはソースコード内にあるためカスタマイズが可能である。また、C++コードは UWP の dll や Unity 内のプレハブにラップされている。

Ray Casting

部屋のスキャンが進むと床・天井・壁のラベルが生成される。PlayspaceRaycast関数はRayを飛ばし何かの表面にあたったら、RaycastResultクラスにそのあたった場所の情報をのせて知らせてくれる。

struct RaycastResult
{
    enum SurfaceTypes
    {
        Invalid,    // No intersection
        Other,
        Floor,
        FloorLike,  // Not part of the floor topology, 
                    //  but close to the floor and looks like the floor
        Platform,   // Horizontal platform between the ground and 
                    //  the ceiling
        Ceiling,
        WallExternal,
        WallLike,   // Not part of the external wall surface, 
                    //  but vertical surface that looks like a 
                    //  wall structure
    };https://camo.githubusercontent.com/badbca8d962fe99d35fc861aade93fbb8dcc9072/68747470733a2f2f617a3833353932372e766f2e6d7365636e642e6e65742f73697465732f6d697865642d7265616c6974792f5265736f75726365732f696d616765732f726179636173742d726573756c742e6a7067
    SurfaceTypes SurfaceType;
    float SurfaceArea;  // Zero if unknown 
                        //  (i.e. if not part of the topology analysis)
    DirectX::XMFLOAT3 IntersectPoint;
    DirectX::XMFLOAT3 IntersectNormal;
};

Unityサンプルでは、カーソルがRayを飛ばし、Unityコライダーに衝突後、understandingモジュールを介し、UIエレメントに表示される。
f:id:korechi:20171118081440j:plain
SpaceVisualizer.csに使っているクエリなどが書かれているため、参考にするとよい。

Shape Queries

dll内のShapeAnalyzer_Wにてユーザが定義したカスタムshapeとのマッチが行われる。Unityサンプルではサンプルのshapeを定義し、結果をアプリ内のクエリメニューで表示している。このカスタムshapeは水平面でしか機能しないことに注意すべき。
例えばソファーは、平らな座面と平らな頂部によって決定される。以下はUnityで使われるクエリ例である。

shapeComponents = new List<ShapeComponent>()
{
    new ShapeComponent(
        new List<ShapeComponentConstraint>()
        {
            ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
            ShapeComponentConstraint.Create_SurfaceCount_Min(1),
            ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
        }
    ),
};
AddShape("Sittable", shapeComponents);
shapeConstraints = new List<ShapeConstraint>()
{
    ShapeConstraint.Create_RectanglesSameLength(0, 1, 0.6f),
    ShapeConstraint.Create_RectanglesParallel(0, 1),
    ShapeConstraint.Create_RectanglesAligned(0, 1, 0.3f),
    ShapeConstraint.Create_AtBackOf(1, 0),
};

f:id:korechi:20171118083035p:plain
SpatialUnderstandingDll.csを読めばより詳しいことがわかる。

Object Placement Solver

object placement solver はオブジェクトルールと制約をもとに、オブジェクトを配置する理想的な位置を探すことができる。オブジェクトのクエリはSolver_RemoveObjectで削除されるまで持続する。
オブジェクト配置クエリは3つのパートからなる。
1. placement type 2. ルールのリスト 3. 制約のリスト これらのクエリを回すためのAPIは以下のようになる。

public static int Solver_PlaceObject(
            [In] string objectName,
            [In] IntPtr placementDefinition,        // ObjectPlacementDefinition
            [In] int placementRuleCount,
            [In] IntPtr placementRules,             // ObjectPlacementRule
            [In] int constraintCount,
            [In] IntPtr placementConstraints,       // ObjectPlacementConstraint
            [Out] IntPtr placementResult)

placement typeは以下のenumで定義される。

public enum PlacementType
            {
                Place_OnFloor,
                Place_OnWall,
                Place_OnCeiling,
                Place_OnShape,
                Place_OnEdge,
                Place_OnFloorAndCeiling,
                Place_RandomInAir,
                Place_InMidAir,
                Place_UnderFurnitureEdge,
            };

ObjectPlacementDefinition構造体はこれらの定義を作成するのを手助けする関数を持っており、以下のように使用することが可能である。

 public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims)

また、ルール、制約のリスト作成にもヘルパークラスが存在し以下のように使用することが可能である。

public static ObjectPlacementRule Create_AwayFromPosition(
    Vector3 position, float minDistance)
public static ObjectPlacementConstraint Create_NearPoint(
    Vector3 position, float minDistance = 0.0f, float maxDistance = 0.0f)

f:id:korechi:20171118103804p:plain
上画像のように床の上にオブジェクトを置きたい場合のサンプルコードは以下のように書くことができる。

List<ObjectPlacementRule> rules = 
    new List<ObjectPlacementRule>() {
        ObjectPlacementRule.Create_AwayFromOtherObjects(1.0f),
    };

List<ObjectPlacementConstraint> constraints = 
    new List<ObjectPlacementConstraint> {
        ObjectPlacementConstraint.Create_NearCenter(),
    };

Solver_PlaceObject(
    “MyCustomObject”,
    new ObjectPlacementDefinition.Create_OnEdge(
        new Vector3(0.25f, 0.25f, 0.25f), 
        new Vector3(0.25f, 0.25f, 0.25f)),
    rules.Count,
    UnderstandingDLL.PinObject(rules.ToArray()),
    constraints.Count,
    UnderstandingDLL.PinObject(constraints.ToArray()),
    UnderstandingDLL.GetStaticObjectPlacementResultPtr());

成功したら、ObjectPlacementResult構造体に、置く場所・次元・角度が返却される。
LevelSolver.csファイルを読めば様々なクエリを確認することができる。

Mac で HoloLens 用 UWP アプリをビルドする【Boot Camp】

はじめに

HoloLens アプリ開発は基本的に WindowsPC を使って行います。
しかし今回 MacBoot Camp を使って HoloLens 用アプリを開発してみました。
(探したところ Boot Camp での開発環境構築のサイトが見当たらなかったため)
結論から言えば、問題なくビルドできました!
一応手順を紹介したいと思います。自分へのメモも含めて。

動作環境

  • MacBookPro 13-inch, 2017, Four Thunderbolt 3 Ports

使用するソフトウェア

手順

BootCamp を使って Windows をインストール

  1. Windows 10インストール用の iso ファイルをダウンロード ただし iso が入った USB メディアを買ってある人はこの手順は必要ありません。
  2. Boot Camp を使って Windows10 をインストール
    ちなみに自分はWindows起動後にbootcampコントローラのインストールが失敗し wifi やら右クリックが使えなくなっていたため、以下のリンクから Windows サポートソフトウェアをインストールしなおしました。
    support.apple.com
    Windows サポートソフトウェアをインストールしたら無事に wifi が繋がりました。
    また、Windowsパーティション最低 60GB は必要です。
    ここを節約してしまうと後々困りますので注意してください。
    Windows そのものに数十GB、Visual Studio にも約 20GB 使います。
    自分は、Mac に 150GB、Windows に 100GB パーティションを区切りました。

開発者モードにしておく

Windows側、HoloLens側どちらも開発者モードにしましょう。

HoloLens のサンプルアプリをビルド

  1. HoloToolKit をダウンロードし Unity のプロジェクトに配置
    DLはこちら
  2. 適当なサンプルシーンを開き、UWP 向けにビルド Windows10 SDK がインストールされていないとビルドが通りませんので注意。
    しかし、以下のようなエラーが出ました。
Exception: Failed to locate env variables VS140COMNTOOLS or VS120COMNTOOLS.
Utility.GetVSVersion () (at C:/buildslave/unity/build/PlatformDependent/WinRT/SharedSources/CSharp/Utility.cs:623)
MetroCSharpVisualStudioSolutionCreator.WriteSolutionFile (System.String solutionFileName, UnityEditor.Scripting.ScriptCompilation.ScriptAssembly[] csharpAssemblies) (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/MetroCSharpVisualStudioSolutionCreator.cs:196)
MetroCSharpVisualStudioSolutionCreator.CreateSolutionFileFrom () (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/MetroCSharpVisualStudioSolutionCreator.cs:724)
PostProcessWSA.CreateVisualStudioSolution () (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/PostProcessWSA.cs:320)
PostProcessWinRT.Process () (at C:/buildslave/unity/build/PlatformDependent/WinRT/SharedSources/CSharp/PostProcessWinRT.cs:237)
UnityEditor.WSA.BuildPostprocessor.DoPostProcess (BuildPostProcessArgs args) (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/ExtensionModule.cs:142)
UnityEditor.WSA.BuildPostprocessor.PostProcess (BuildPostProcessArgs args) (at C:/buildslave/unity/build/PlatformDependent/MetroPlayer/Extensions/Managed/ExtensionModule.cs:149)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

これはVisual Studio 側の環境が整っていないのが問題らしいので次のステップに進みます。

Visual Studio 側の設定

  1. Visual Studio を起動
  2. ツール -> ツールと機能を取得 f:id:korechi:20171106074156p:plain
  3. ユニバーサル Windows プラットフォーム開発をインストール
    f:id:korechi:20171106074300p:plain

再度ビルド

無事 Unity でビルドが通り、Visual Studio 用ソリューションファイルが生成されました!
あとは Visual Studioコンパイルすれば HoloLens 上でアプリが動作します!

その他

リモートデスクトップ

HoloLens から リモートデスクトップアプリを使って BootCamp で起動した Windows10 に普通にリモートデスクトップ繋がりました。
f:id:korechi:20171105161143j:plain

Unity で作った ARKit 向けアプリをリリースする時に気をつけること【審査まで】

はじめに

今回 ARKit の機能を利用するアプリを Unity を使って作成し、ストアに申請しました。(まだ承認されていないのでストアには並んでいませんが)
そこで、Unity を使って ARKit の機能を利用するアプリをストアに申請する際に出たいろいろなエラーなどを紹介し、回避法やおすすめ設定をメモしておきます。
審査結果が届き次第、またフィードバックを記事にまとめたいと思います。

Unity 側

minimum iOS のバージョンを 11 に

ARKit は iOS 11.0 以降でかつ、iPhone6s 以降に発売された iPhone および iPad でしか動作しません。
そのため、File -> Build Setting -> Other Settings の Target minimum iOS Version を 11.0 にしましょう。
f:id:korechi:20171031200051p:plain:h600

必要ならターゲットデバイスiPhone のみに

もし必要ならですが、上と同じく File -> Build Setting -> Other Settings の Target Device を iPhone Only にしておきましょう。
ただ、iPad でも機種によっては ARKit が動作するため、iPad にも対応させている場合は Target Device を iPhone & iPad にしましょう。

画面回転をしない設定にしておく

これはもちろん作るアプリケーションにもよりますが、自分が今回作ったアプリでは画面回転をしない方が良かったため、このような設定にしました。
File -> Build Setting -> Other Settings の Default Orientation を Portrait にすることで、画面を縦固定にすることができます。
f:id:korechi:20171031201120p:plain:h300

XCode

こちらが意外とネック。
Unity で Xcode 用ソリューションにできたとしても安心できません。
自分は結構ビルドが通らなかったです。

Architectures を arm64 のみに(重要)

Build Setting の Architectures で対象とするデバイスアーキテクチャが選択できます。
これがデフォルトですとおそらく、arm64 armv7 が選択されているのですが、これだとビルドが通りません。以下のようなエラーが出ます。

clang: error: invalid iOS deployment version '-miphoneos-version-min=11.0', iOS 10 is the maximum deployment target for 32-bit targets [-Winvalid-ios-deployment-target]

これは、ターゲットとする iOS のバージョンを 11 以上に設定しているのに、32-bit アーキテクチャは最大で iOS10 ですよーとのエラーです。
こちらの iOSバイス一覧から armv7 は iOS11 に出来ないことがわかります。
qiita.com
そのため、arm64 armv7 の部分を選択し、Othersを選択。
f:id:korechi:20171031202120p:plain
その後、armv7 を削除しましょう。 f:id:korechi:20171031202152p:plain

1024×1024pt のアイコンを設定しておく

ARKit には関係しませんが、App Store にアプリが並ぶ時に表示される 1024*1024pt のアイコンを XCode 上で予め登録しておかないと、iTunes Connect でアプリを審査に出す時にエラーとなってしまいます。
あとでエラーになると面倒なので、予め設定しておきましょう。
1. General -> App Icons Source の右側にある矢印をクリックし、一番下にある欄にアイコンを設定しましょう。
f:id:korechi:20171031202910p:plain:w600

アイコンは非透過の png を用意

これも ARKit には関係しませんが、アイコンは非透過のものを用意しておかないと iTunes Connect でアイコンを設定することができません。
自分は、png(透過)→jpg(非透過)→png(非透過)にして非透過画像の png を用意しました。(もっとスマートなやり方は絶対ある)

とりあえずはざっとこんなところです。
アプリの申請の流れは以下のサイトが参考になりました。
i-app-tec.com

剣を自在に振ってスライムを倒すHoloQuestを作ってみた【HoloLens+ARKit】

今回作ったもの

今回HoloQuestという、HoloLensとiPhoneを使った簡単なアクションゲームを作成しました。
HoloLensを通してiPhoneの位置にARの武器が表示され、その剣を使って敵モンスターを倒すゲームです。
youtu.be

動機

  1. 現実空間でスライムと戦ってみたかった(重要)
  2. HoloLens と ARKit を組み合わせればこんなものが作れるよというのを見せたかった・試したかった

使用した機材

  • HoloLens
    • HoloQuestが動作
      • iPhoneの位置に剣を表示
      • スライムの表示なども行う
  • iPhone6s(iOS11)
    • HoloControllerアプリが動作
      • ARKitを使い自身のpositionとrotationを取得
      • 自身のpositionとrotationをHoloLensに送信
    • コントローラーとして使用

開発環境

  • Unity 2017.1.1f1
    • HoloQuestとHoloClientの実装
  • Visual Studio 2017
    • HoloQuestアプリのビルドに使用

お借りした素材

実装

剣をiPhoneの位置に表示

どうやって剣をiPhoneの位置に追従させて表示させるかのイメージ図がこちら。
f:id:korechi:20171004104458p:plain
それではiPhone側で動作するHoloClientアプリと、HoloLens側で動作するHoloQuestの実装それぞれについて説明します。

HoloClient(iPhone側)の実装

iPhone側で動作するアプリは非常に単純で、必要とした機能は以下の2つです。
1. AR Kitを動作させ常に自身のpositionとrotationを取得
2. 自身のpositionとrotationをHoloLensに毎フレーム送信
この際には凹みさんのuOSCを使用させていただきました。
github.com
3. マーカーを画面に表示
自身の位置をHoloLensに知ってもらうために表示しています。マーカーは何でも良いです。
HoloLens側ではvuforiaというマーカー認識ソフトを使用します。

HoloQuest(HoloLens側)の実装

HoloLensとiPhoneはそれぞれが別のアプリが動作しており、どちらのアプリもアプリが起動した瞬間の自分(カメラ)の位置を(0, 0, 0)としてスタートします。
そのため、HoloLensから見てiPhoneがどこに存在するかの相対位置は分かりません。
そこで2通りの位置合わせ方法を今回使用しました。

①HoloControllerアプリをHoloLensの指定された位置で起動

手順は以下の通りです。
1. HoloQuestが起動した時にHoloLensの前に剣を表示
- 今回は(2,0,2)に表示
2. iPhoneをその剣に重ねた状態でHoloClientアプリを起動
- HoloLensからした(2,0,2)の位置がiPhoneにとっては(0,0,0)だと認識される
3. iPhoneから受信したpositionである(x,y,z)に(2,0,2)を足した場所に剣を表示し続ける
f:id:korechi:20171004113533p:plain

②vuforiaを使い、iPhone上に表示されたマーカーを認識して剣の位置を再調整

しかし、iPhoneを振り続けていると剣とiPhoneの位置がだんだんとずれていってしまいます。(原因はまだわかっていません)
そこでゲームのプレイ中に位置がずれたなーと思った時にiPhoneの位置を再調整するためにvuforiaというマーカー認識ソフトを使いました。
vuforiaの参考記事はこちら
vuforiaではマーカーを認識している間、マーカーのpositionとrotationを取得することができます。
その機能を利用し、剣がずれたなーと思った時にHoloLensの前にiPhoneを持ち上げマーカーを認識させるとiPhoneの位置が再度取得できます。
f:id:korechi:20171004114542p:plain

スライムとの戦闘

これは単純にスライムオブジェクトと剣オブジェクトにcolliderを設定し、OnCollisionEnter()で衝突を検知します。
f:id:korechi:20171004114902p:plain

OnCollisionEnter (Collider collider) {
    if (collider.gameObject.tag == “Army”) {
         this.hitPoint -= 1;
    }
}

気をつけたUI

プレイヤーは敵モンスターをどこから見るか分かりません。
後ろから見た時にモンスターの後ろ姿が見えるのは問題ないのですが、HPは常にプレイヤーの方向を向くように設定しました。

今回やらなかったこと

床・壁・天井に別テクスチャを貼る

床を芝生にしたり天井を空っぽく見せることでゲーム空間っぽい演出をしようかなーと思ったのですが今回はしませんでした。
参考記事
http://www.naturalsoftware.jp/entry/2016/06/14/110111www.naturalsoftware.jp
理由は2つあり、1つは処理が重くなる。もう1つは視野角が狭いため敵モンスターを見ていると周りの風景があまり見えないから。 ここらへんは改善の余地ありかもしれません。

最後に

HoloLens + ARKitでゲームを作ってみましたがとても相性が良かったように思えます。
両者ともセンサーを必要としないため、どんなに歩いても問題ありません。(非常にでかい) しかし、どうしても両者の相対位置はずれてきてしまいます。
実用面で考えるならば、新しいコードレスコントローラが発売されるか、vuforia以外のもっと良い位置合わせ方法が求められると思います。
HoloQuestを実際にリリースすることはありませんが、HoloLens + ARKitは面白い組み合わせですし、可能性があると思うので、みなさまも是非お試し下さい!

Hololensとスマートフォン間で通信を行う方法【uOSC】

はじめに

Hololensとスマートフォン(iPhoneAndroid)間でデータをやりとりする方法をまとめました。
具体的には、凹みさんの記事で紹介されていますUnity向けのOSC実装を使っています。
tips.hecomi.com
これがとても使いやすかったので、自分で使い方を忘れないためにも、記事に使い方をまとめておこうと思います。

前提

UnityでHololensアプリを作成し、Hololens実機でのビルドができること。

必要なもの

実装

今回、Hololensとスマートフォン間で通信を行うために、Hololens側とスマートフォン側の2つアプリを作る必要があります。

Hololens側

  1. 新規プロジェクトを作成しuOSC-v0.0.1.unitypackageHoloToolkit-Unity-v1.2017.1.0.unitypackageをインポート
    f:id:korechi:20170908164637p:plain:h200
  2. HoloToolKitタブにあるConfigureのApply*を全て行う
    f:id:korechi:20170909002517p:plain:h100
  3. uOSC Serverオブジェクトを作成し(名前は何でも良い)、uOscServer.csServerTest.csをuOSC Serverオブジェクトに追加
    場所は以下にあります。
    uOSC/Scripts/uOscServer.cs
    uOSC/Examples/Scripts/ServerTest.cs
    f:id:korechi:20170908165603p:plain
  4. File->BuildSettingでPlatformにてUniversalWindowsPlatformを選択
    今回はSDKを10.0.14393.0を選択します。
    f:id:korechi:20170908170907p:plain:h300
  5. Player Settingsから、Publishing SettingsのCapabilitiesのInternetClientとInternetClientServerにチェック
    環境認識も行いたい場合はSpatial Perceptionにチェックを入れます。忘れがちなので要注意です。
    f:id:korechi:20170908171154p:plain:h300
    また、開発マシンのセキュリティソフトやファイアーウォールを無効化しておかないと、データがHololensに届かない場合があります。
  6. Build
  7. 出力されたソリューションファイルをVisual Studio 2017で開き、Hololensを接続し以下の設定でビルド
    f:id:korechi:20170909000158p:plain
  8. おそらく、初回ビルドは失敗するので、project.lockファイルを開き、UAP,Version=v10.0.***の部分を全てUAP,Version=v10.0に書き換えます
  9. もう1度Visual Studioでビルドするとビルドが通ります
    f:id:korechi:20170909002955p:plain
    ログは右下の出力タブに出力されますので、そこを確認しましょう。

スマートフォン

こちらはずっと簡単です。
1. 新規プロジェクトを立ち上げ、uOSC-v0.0.1.unitypackageをインポート
2. uOSC Clientオブジェクトを作成し(名前は何でも良い)、uOscClient.csClientTest.csをuOSC Clientオブジェクトに追加
f:id:korechi:20170909004015p:plain:h200
場所は以下の場所にあります。
uOSC/Scripts/uOscClient.cs
uOSC/Examples/Scripts/ClientTest.cs
IPAddressや送信する内容は固定となっていますので、そこらへんを変えたい場合は上記2ファイルを修正(主にClientTest.cs)を変更しましょう。
3. AndroidもしくはiOS用にビルド

最後に

Hololensでのアプリ開発はまだ不安定な部分もあり、SDKのバージョンによっては動かなかったりします。そのため、今回ご紹介したバージョンでの開発をおすすめします。

追記

UnityのバージョンをUnity 2017.1.1f1にし、MixedRealityToolkit-Unity for Unity 2017.1.1f1を使用したところ、Hololens側の手順8,9が必要なくなりました。
1度目のビルドで無事Hololens上でアプリが起動したのを確認しました。

ARKit用サンプルアプリを作る2つの方法

はじめに

ARKit用サンプルアプリの作成する以下の2つの手順を紹介します。
1. Xcodeのみを使ってアプリを作成
2. Unityでアプリを作成し、Xcodeを使ってビルド

1はiOSのネイティブコードでARKitを直接利用する方法、2はUnity ARKit Pluginを使用してUnityでアプリを作成し、最後にXcodeを使ってビルドする方法です。
ARKitについては前回の記事で紹介したため、そちらも読んでください。
korechipostit.hatenablog.com
どちらを使うかは作りたいアプリによって使い分けると良いと思います。この記事では両方の方法でサンプルアプリを作る方法を紹介します。

Xcodeのみを使ってアプリを作成

まずはAppleの公式ドキュメントでも紹介されている、Xcodeのみを使ったサンプルアプリの作成方法について説明します。

アプリの実行結果

f:id:korechi:20170817233833g:plain
宙に飛行機オブジェクトが浮かんでいるのが確認できるアプリとなっています。

必要なもの

  • Xcode 9 beta ← ここからDL
  • iOS11がインストールされたデバイス(A9プロセッサ以降のもの)

アプリの作成

  1. Xcode-betaを起動し、Create a new Xcode projectを選択します。
    f:id:korechi:20170817000321p:plain:h300
  2. Augmented Reality Appを選択→Nextをクリック
    f:id:korechi:20170817000851p:plain:h250
  3. アプリの初期設定を行う
    f:id:korechi:20170817001251p:plain:h250
    • 任意の値を入れてください。
    • 「Product Name」と「Organization Identifier」から成る「Bundle Identifier」は、世界中のアプリの中から自身のアプリを識別するIDとなります。主に、ドメインを逆さまから並べたものをOrganization Identifierに設定することが推奨されています。
    • Content Technologyは、「Scene Kit」「Sprite Kit」「Metal」の3つから選べますが、今回はとりあえず「Scene Kit」を選択しました。

アプリのビルド

  1. ビルド対象のデバイスを自身のデバイスに設定
    f:id:korechi:20170817003200p:plain
    ここにある「Generic iOS Device」という箇所をクリックし、自身のデバイスを選択してください。
  2. ビルド

無事、宙に飛行機が浮かぶサンプルアプリがiPhone上で実行されるはずです。 コードの中身が気になる方は各自Xcodeを確認してください。

②Unityでアプリを作成し、Xcodeを使ってビルドする方法

こちらはUnityを使ってARKit用アプリを作成する方法を紹介します。
何となくこっちの方がTangoでの開発に近い気もします。

アプリの実行結果

f:id:korechi:20170817233250g:plain

必要なもの

Unityでの操作

  1. 新規Unityプロジェクトの作成
  2. unity-arkit-plugin.unitypackageをインポート
    f:id:korechi:20170817101140p:plain:h300
    Projectビューは以下のようになっています。
    f:id:korechi:20170817101252p:plain:h200
  3. Build Settings -> PlatformをiOSに切り替える
  4. No iOS module loadedとなっている方は、横にある「open download page」ボタンをクリックしてください(DLが終わるまで1時間弱かかる場合があります)
    f:id:korechi:20170817010324p:plain:h300
  5. Build Settings -> Platform -> iOSを選択し、PlayerSettingsからIdentificationを設定
  6. Camera Usage Descriptionに何らかしらの文字を入れる(これをやらないとアプリがカメラ利用許可を得られず、起動時に落ちるらしい)
    f:id:korechi:20170817101656p:plain:h300
  7. Assetsフォルダ直下にある、UnityARKitScene.unityをダブルクリックしてシーンを開く
    シーンを開くと以下のような画面になります。
    f:id:korechi:20170817102111p:plain:h300
  8. Build Settings -> Add Open Scenes をクリック 注)これをしないと現在のシーンがビルド対象となりませんので注意してください
    f:id:korechi:20170817102346p:plain:h300
  9. UnityParticlePainter.unityのシーンも同様にビルド対象とし、ビルドします
    ただし、Unityのパッチが古いと以下のようなエラーが出ます。
Assets/Plugins/iOS/UnityARKit/UnityARVideo.cs(59,31): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `R8'
Assets/Plugins/iOS/UnityARKit/UnityARVideo.cs(66,31): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `RG16'

エラーが出なかった場合は、Xcode向けにビルドされたプロジェクトが生成されます。

Xcodeでの操作

  1. Unityから生成されたXcodeプロジェクトを開きます
    f:id:korechi:20170817104622p:plain:h250
  2. 実機で実行(やり方は①Xcodeのみを使ってアプリを作成、と同じ)
    ただし以下のようなエラーが出てしまいました。
ARKitUnitySample[3217:1623803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ARFrame displayTransformWithViewportSize:orientation:]: unrecognized selector sent to instance 0x1c42eff80'

調べたところこれは、unitypackageが少し古いために発生した問題みたいです。
もしそのようなエラーが出てアプリが強制終了してしまった方は、unitypackageを使わずにUnity-ARKit-pluginをbitbucketからダウンロードして、それをそのままUnityで開いてください
それ以外の手順は大体同じです!

最後に

Xcodeのみを使ってアプリを作成する方法と、Unityを使ってアプリを作成する方法を紹介しました。
どちらを選択するかは皆さんに判断をお任せしますが、やはり3Dオブジェクトをごりごり動かしたい場合はUnityの方が良いのではないかとも思います。
反対に、そうでないものを作るのならばXcodeのみで開発した方が良さそうにも思えます。
自分はもう少し両方のパターンで慣れて見てから判断しようと思います!

AppleのARKitについて調べてみた

はじめに

AppleのARKitに最近興味がわいたので、今回調べてみました。
Appleの公式ドキュメントを読んでまとめつつ、補足をつけたりしています。
アプリの制作方法は次の記事でまとめたいと思います。

ARKit とは

OSデバイスのカメラとモーション機能を統合することで、iアプリやゲーム内で拡張現実体験を提供するフレームワークです。
具体的には、デバイスのモーション機能、カメラによるシーンのキャプチャ、高度なシーン処理、便利さの表示を組み合わせて、AR体験の構築を単純化しています。

ARKitを使ったデモ例

こちらはARKitとUnityを使ってロボットが部屋の中で踊るデモです。
床の上を綺麗に動き回っているのが特徴的です。他にも様々なサンプルアプリが世に出回っているみたいです。

ARKitを利用するには(デバイス側)

A9以降のプロセッサを搭載した、iOS11以降のOSがインストールされたデバイスが必要です。

  • A9: iPhone6s, 6sPlus, SE, iPad(第5世代)
  • A9X: iPad Pro
  • A10: iPhone7, 7Plus

ARKitを利用するためには(アプリ側)

ARKitをサポートしたデバイスのみでアプリを動作させるには、アプリのInfo.plistUIReauiredDeviceCapabilitiesセクションの中でarkitキーを使用してください。
もし、AR機能がアプリにとって二次的な機能ならisSupportedプロパティを使用してください。

ワールドトラッキングの仕組み

現実世界と仮想空間の間の対応関係を構築するために、visual-inertial odometryという技術を使用しています。

visual-inertial odometryとは

iOSバイスのモーションセンサーとカメラから見えた映像の分析結果を結合するプロセス。
ARKitはシーン画像内の特徴点を認識し、その特徴点からのずれを追跡し、モーションセンサーからのデータと比較することで、高い精度でデバイスの位置と動きを得ることができます。

ARKitができること

  • 平面検知
    • ARHitTestResultクラスを使えば、カメラ画像内にある平面(現実世界における)を検知
    • planeDetectionをenableにすることで、ARKitはカメラ内の平面を検知し、その位置とサイズを知らせてくれる
  • それ以外はできないのかな?(まだよく分かっていませんが)
    • Tangoは平面だけでなく壁や特徴点の3次元座標を取得可能だったがARKitは平面検知しか行えないっぽい
    • Tangoは学習した現実空間の座標情報をADFファイルとして保存し、アプリ起動時に読み込むことで以前に学習した空間とのマッチングを行うことができたが、ARKitにその機能はついていないみたいです

ARKitを使用するコツ

  • 明るい環境での使用を促す
    • ワールドトラッキングはカメラ画像をもとに行われるため、暗い場所や細部が見えない環境では精度が落ちてしまいます。
  • ラッキングがうまくいっているかユーザにその都度知らせる
    • ARKitはデバイスが動いているほどシーンを理解できる。しかし、あまりに早く動かしたり、遠くからトラッキングをしてしまうと検知がうまくいかない場合があります。そこで、ARCameraクラスを使うことで、ユーザにトラッキングの情報を教え、トラッキングがうまくできていない時にもどうすれば良いかユーザに伝えるUIを作ることができます。
  • 時間をかけて平面検知を行い、必要とする平面が検知されたらそれ以降は平面検知をしないようにする
    • 平面検知の結果は時間とともに変化する。なぜなら、ARKitはシーン内の情報を常に更新し、その情報をもとに平面の情報を上書きし続けるからです。(これはつまり、一番最初に検知した平面は不正確な場合があるということです)

様々なクラス

ARKitのAR機能を使うためにいくつかのクラスが用意されています。

ARSessionクラス

  • 拡張現実体験に必要なデバイスカメラとモーション処理を管理する共有オブジェクト
  • ARKitが拡張現実感を作成するために実行する主要なプロセスを調整
    • このプロセスにはデバイスのモーションセンシングハードウェアからのデータの読み取り、デバイスの内蔵カメラの制御、キャプチャされたカメライメージのイメージ分析の実行が含まれる
  • AR機能を使うためには、このARSessionオブジェクトが必要
    • ARSCNViewやARSKViewオブジェクトを使用する場合はARSessionオブジェクトが生成されているが、自分でARコンテンツを自作する場合は、ARSessionオブジェクトを生成し、扱う必要がある

ARWorldTrackingConfigurationクラス

  • バイスの動きを6軸自由度(6DOF)を使ってトラッキングする設定
    • 3つの回転軸(roll, pitch, yaw)
    • 3つの平行移動軸(x, y, zの移動)
    • これらの情報とカメラ画像を組み合わせることで、仮想の物体を現実空間に配置することができる f:id:korechi:20170815194141p:plain:h300

AROrientationTrackingConfigurationクラス

  • バイスの向き(3軸)のみを使ってトラッキングする設定
  • ARWorldTrackingConfigurationクラスを使うことが推奨されているっぽい(当然か)

ARConfigurationクラス

  • 抽象クラス
  • 具象クラスとしてARWorldTrackingConfigurationクラスとAROrientationTrackingConfigurationクラスが存在

まとめ

  • ARKitは現実空間にARオブジェクトを配置する技術
  • カメラ画像とモーションセンサーのデータを使ってそれを実現
  • 現在、カメラ画像内の平面検知が行えるため、平面の上に物を置いたりすることができるみたい
  • iPhone6s以降に発売された端末で利用できる