一覧に戻る

iOS ネイティブAPIのインスタントトラッキング

2017.09.22iOSネイティブAPI

インスタントトラッキング

以下のセクションでは、Wikitude SDKネイティブAPIのインスタントトラッキング機能について詳しく説明します。最小の実装を紹介し、Wikitude SDKネイティブAPIが提供するシンプルさを紹介します。

概要

インスタントトラッキングは、以前にWikitude SDKで導入されたものとは異なり、あらかじめ定義されたターゲットを認識し、トラッキングを開始するのではなく、ただちに任意の環境でトラッキングを開始するアルゴリズムです。これにより、非常に具体的なユースケースを実装することができます。

アルゴリズムは2つの異なる状態で動作します。最初のものは初期状態です。この状態では、ユーザはデバイスに指示を出してインジケータを整列させることで、トラッキングの起点を定義します。ユーザが満足できる起点が定義できたと判明すると、トラッキング状態への移行が実行されます。この状態では、環境は継続的にトラッキングされているため、シーン内に拡張を配置することができます。

インスタントトラッキングのアルゴリズムは、初期化状態で別の入力値を提供することを要求します。具体的には、トラッキングしているデバイスの高さは、シーンの範囲内で正確に増加したスケールを調整するために必要となります。この目的のために、この例ではメートル単位で高さを設定できる範囲入力要素を備えています。

初期化中にインスタントトラッキングの平面を整列するための別のパラメータを設定できます。この平面を初期化インジケータにして表示させ、床の代わりに壁をターゲットとしてトラッキングするために回転させることができます。詳細については、Android ネイティブAPIリファレンスのWTInstantTrackerConfigurationを参照してください。

基本的なインスタントトラッキング

インスタントトラッキングの例は、インスタントトラッキングアルゴリズムの最小限の実装を提供します。まず、UIViewControllerにいくつかの追加が必要になります。インスタントトラッキングを使用するには、UIViewControllerがWTInstantTrackerDelegateプロトコルに準拠している必要があり、WTInstantTrackerとWTInstantTrackingStateがメンバーとして必要になります。

@interface WTInstantTrackerViewController () <WTWikitudeNativeSDKDelegate, WTInstantTrackerDelegate>
@property (nonatomic, strong) WTInstantTracker                      *instantTracker;

@property (nonatomic, assign) WTInstantTrackingState                trackingState;

WTWikitudeNativeSDKがviewDidAppearで実行されているかどうかを確認した後、WTInstantTrackerとWTInstantTrackingStateの両方を初期化します。

self.instantTracker = [self.wikitudeSDK.trackerManager createInstantTracker:self configuration:nil];
self.trackingState = WTInstantTrackerInitializing;

WTInstantTrackerは、以前に生成されたトラッカーインスタンスだけで最小限にインスタンス化することはできますが、実用的なユースケースでは、初期化状態とトラッキング状態の両方で描画されるドロアブルを提供することが推奨されます。したがって、StrokedRectangleインスタンスが生成されます。

self.renderableRectangle = [[StrokedRectangle alloc] init];
self.renderableRectangle.scale = 0.45;

StrokedRectangleをWTInstantTrackerの初期化に使用するには、WTInstantTrackerDelegateのinstantTracker:didChangeInitializationPose:コールバック関数を実装します。

- (void)instantTracker:(nonnull WTInstantTracker *)instantTracker didChangeInitializationPose:(nonnull WTInitializationPose *)pose
{
    [self.renderableRectangle setProjectionMatrix:pose.projection];
    [self.renderableRectangle setModelViewMatrix:pose.modelView];
}

このコールバック関数は、WTInstantTrackerと現在のWTInitializationPoseを提供します。このWitnitializationPoseは、StrokedRectangleの投影マトリックスとモデルビュー行列を設定するために使用され、初期化状態で正しく表示されます。

次に、ある状態から別の状態に移行する手段が必要です。このタスクでは、ボタンクリックで呼び出すことができるtoggleInstantTrackingState関数を提供します。self.trackingStateは、現在の状態の値を保持します。

- (IBAction)toggleInstantTrackingState:(id)sender
{
    if ( [[self.instantTrackingButton currentTitle] isEqualToString:@"Start Tracking"] )
    {
        if ( WTInstantTrackerInitializing == self.trackingState )
        {
            [self.instantTrackingButton setTitle:@"Start Initialization" forState:UIControlStateNormal];
            [self.instantTracker setActiveInstantTrackingState:WTInstantTrackerTracking];
        }
    }
    else
    {
        if ( WTInstantTrackerTracking == self.trackingState )
        {
            [self.instantTrackingButton setTitle:@"Start Tracking" forState:UIControlStateNormal];
            [self.instantTracker setActiveInstantTrackingState:WTInstantTrackerInitializing];
        }
    }
}

インスタントトラッカーが初期化されている間はオレンジ色の矩形を描画しますが、トラッキング状態になると矩形が青色になります。

- (void)instantTracker:(nonnull WTInstantTracker *)instantTracker didChangeState:(WTInstantTrackingState)newState
{
    _trackingState = newState;

    if (_trackingState == WTInstantTrackerInitializing) {
        [self.renderableRectangle setColor:[UIColor colorWithRed:1.00f green:0.58f blue:0.16f alpha:1.0f]];
    } else {
        [self.renderableRectangle setColor:[UIColor colorWithRed:0.41f green:0.60f blue:0.76f alpha:1.0f]];
    }
}

WTInstantTrackerのコールバック関数のinstantTracker:didChangeState:では、StrokedRectangleの色を制御して視覚的な表現をしています。しかしこれは矩形の色を変更するだけで、位置は変更しないため、矩形の投影行列とモデルビュー行列を更新するにはinstantTracker:didTrack:コールバック関数が必要です。

- (void)instantTracker:(nonnull WTInstantTracker *)instantTracker didTrack:(nonnull WTInstantTarget *)target
{
    [self.renderableRectangle setProjectionMatrix:target.projection];
    [self.renderableRectangle setModelViewMatrix:target.modelView];
}

次に、WTInstantTrackerのdeviceHeightプロパティを設定し、それをUISliderに接続するためにupdateDeviceHeightAboveGround:関数を用意しています。この変更は厳密に言えば必須ではありませんが、この方法で正確にデバイスの高さを指定することを推奨します。

- (IBAction)updateDeviceHeightAboveGround:(UISlider *)sender
{
    [self.instantTracker setDeviceHeightAboveGround:@(sender.value)];
}

最後に、状態が初期化からトラッキング状態に変更するときに高さのスライダを非表示にする必要があります。そのため、instantTracker:didChangeState:に適切なalpha値を設定してください。

dispatch_async(dispatch_get_main_queue(), ^{
    if ( WTInstantTrackerTracking == newState )
    {
        self.deviceHeightAboveGroundSlider.alpha = 0.0;
    }
    else
    {
        self.deviceHeightAboveGroundSlider.alpha = 1.0;
    }
});

このセクションで概説した例では、インジケータとして初期化状態のときはオレンジ色の矩形拡大をレンダリングし、トラッキング状態のときは青色の矩形拡大をレンダリングしています。この例はとても単純なものですが、インスタントトラッキングの基本概念を理解するのに適しています。

インスタントシーンのピッキング

インスタントトラッキング機能は、さらに、3Dポイントを基礎としたポイントクラウド構造から照会されることが可能になります。このセクションは、サンプルアプリケーションの対応するサンプルに基づいてこの機能を紹介します。
この機能を利用するには、画面上の2D入力位置が必要です。UITapGestureRecognizerは、その目的のためにView Controllerに追加されます。

@interface WTInstantScenePickingViewController () <WTWikitudeNativeSDKDelegate, WTInstantTrackerDelegate, WTExternalOpenGLESRenderingProtocol, UIGestureRecognizerDelegate>
@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer;
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapFrom:)];
[self.view addGestureRecognizer:_tapGestureRecognizer];
_tapGestureRecognizer.delegate = self;

handleTapFrom:recognizer関数はタップ位置を照会し、メインスクリーンスケールを使用してポイントからピクセルに変換し、結果の座標をconvertScreenCoordinate:toPointCloudCoordinateOnQueue:completion関数に渡すように実装されています。これらの入力座標は、画面の左上隅に原点を持ち、[0、screen_width_in_pixels]と[0、screen_height_in_pixels]の間隔内にあります。完了ハンドラ関数内では、ブール値と3Dポイントが受信します。前者は、操作が正常に完了したかどうかを通知します。後者は成功の場合に結果が含まれ、失敗の場合はゼロが含まれます。特定の間隔内の入力座標に対してポイントクラウドの位置が見つからないときはクエリが失敗することに注意してください。成功したクエリでは、StrokedCubeインスタンスが生成され、その結果の位置に拡張として表示されます。

CGPoint tapPosition = [recognizer locationInView:self.view];

CGFloat screenScale = [[UIScreen mainScreen] scale];
CGPoint tapPositionScaled = tapPosition;
tapPositionScaled.x *= screenScale;
tapPositionScaled.y *= screenScale;

[_instantTracker convertScreenCoordinate:tapPositionScaled toPointCloudCoordinateOnQueue:[NSOperationQueue currentQueue] completion:^(BOOL success, WTPoint3D* _Nullable pointCloudCoordinate) {
    if (pointCloudCoordinate) {
        StrokedCube *targetAugmentation = [[StrokedCube alloc] init];
        targetAugmentation.uniformScale = 0.05f;
        targetAugmentation.xTranslation = pointCloudCoordinate->x;
        targetAugmentation.yTranslation = pointCloudCoordinate->y;
        targetAugmentation.zTranslation = pointCloudCoordinate->z;
        [self.renderableCubes addObject:targetAugmentation];
    }
}];

最後に、サンプルを実行することで、トラッキング状態のときにキューブ拡張をスクリーンタッチに置くことができます。