一覧に戻る

iOS ネイティブAPIのレンダリング

2017.09.22iOSネイティブAPI

レンダリング

このトピックでは、レンダリングがWikitude SDKネイティブAPIと連携してどのように機能するかを示します。

Wikitude SDK ネイティブAPIには、内部レンダリングと外部レンダリングの2種類のレンダリング方法が用意されています。内部レンダリングでは、OpenGLビューはWikitude SDKによってセットアップされ、SDKユーザーはカスタムレンダリングを定義できます。内部レンダリングビュー(OpenGL ES、Metal)は、Wikitude SDKによってセットアップされ、SDKユーザーはWikitude SDKによって実行されるカスタムレンダリングを定義できます。それに対して外部レンダリングは、SDKユーザーが独自にレンダリングビューを設定し、このレンダリング設定にWikitude SDKを統合します。

レンダリングAPI

iOS用のWikitude SDK ネイティブAPIは、次のRenderingAPIをサポートしています。

  • OpenGL ES 3
  • OpenGL ES 2
  • Metal

レンダリングAPIの選択方法については、「外部OpenGL ESレンダリング用のAPIの選択」または「内部レンダリング用のAPIの選択」を参照してください。

外部OpenGL ESレンダリング

開発者は外部レンダリングの方を好むと思われるので、Wikitude SDK ネイティブAPIに含まれるサンプルのほとんどは外部レンダリングを使用しています。このサンプルアプリケーションにはシンプルなOpenGL ES View(ExternalEAGLView)とシンプルなレンダラー(ExternalRenderer)が付属しています。

外部レンダリングを有効にするには、WTOpenGLESRenderingModeと組み合わせてWTOpenGLESRenderingConfigurationを使用する必要があります。この場合、WTExternalOpenGLESRenderingModeはWTRenderingMode_Externalを渡し、WTWikitudeNativeSDKメソッドの-initWithRenderingConfiguration:delegateに渡します。最も便利な方法は、WTWikitudeSDKで+createExternalOpenGLESRenderingConfigurationを呼び出すことで、事前設定されたWTOpenGLESRenderingConfigurationを作成することです。

WTOpenGLESRenderingConfiguration *selectedConfiguration = [WTWikitudeNativeSDK createExternalOpenGLESRenderingConfiguration:self];
self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingConfiguration:selectedConfiguration delegate:self];

この事前設定済みのレンダリング設定では、デバイスの仕様に応じて、OpenGL ES 3.0またはOpenGL ES 2.0を使用します。
レンダリングモードとレンダリング設定を手動で作成することもできますが、まずは渡す前にWTWikitudeSDKで+selectRenderingConfigurationを呼び出す必要があります。それ以外の場合は受け入れられません。これは、現在のデバイスで必要なレンダリング設定がサポートされていることを確認するためです。

WTExternalOpenGLESRenderingMode *externalRenderingMode = [[WTExternalOpenGLESRenderingMode alloc] initWithDelegate:self andVersion:kEAGLRenderingAPIOpenGLES2];
WTOpenGLESRenderingConfiguration *openGLESRenderingConfiguration = [[WTOpenGLESRenderingConfiguration alloc] initWithOpenGLESRenderingMode:externalRenderingMode];
WTRenderingConfiguration *selectedConfiguration = [WTWikitudeNativeSDK selectRenderingConfiguration::[NSOrderedSet orderedSetWithObjects:openGLESRenderingConfiguration, nil]];
self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingConfiguration:selectedConfiguration delegate:self];

この方法は冗長のため、モードと構成の作成方法をさらに制御する必要がある場合にのみ推奨されます。
Wikitude SDK ネイティブAPIの起動フェーズ中に(これは-start:completion:の呼び出しによって初期化されます)、WTExternalOpenGLESRenderingProtocolプロトコルのメソッドがいくつか呼び出されます。これらのメソッドは、Wikitude SDK ネイティブAPIで外部レンダリングが行えるよう準備するために必要となります。

- (void)wikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK didCreateExternalOpenGLESUpdateHandler:(WTWikitudeOpenGLESUpdateHandler __nonnull)updateHandler
{
    self.wikitudeUpdateHandler = updateHandler;
}

- (void)wikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK didCreateExternalOpenGLESDrawHandler:(WTWikitudeOpenGLESDrawHandler __nonnull)drawHandler
{
    self.wikitudeDrawHandler = drawHandler;
}

- (EAGLContext *)eaglContextForVideoCameraInWikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    if (!_sharedWikitudeEAGLCameraContext )
    {
        EAGLContext *rendererContext = [self.renderer internalContext];
        self.sharedWikitudeEAGLCameraContext = [[EAGLContext alloc] initWithAPI:[rendererContext API] sharegroup:[rendererContext sharegroup]];
    }
    return self.sharedWikitudeEAGLCameraContext;
}

- (CGRect)eaglViewSizeForExternalRenderingInWikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    return self.eaglView.bounds;
}

最初の2つのメソッドはブロックオブジェクトを備えており、外部レンダリングシステムのフレームごとに呼び出す必要があります。これらのメソッドの目的は、内部SDKロジックを更新し、カメラストリームをOpenGLで描画することです。 3番目のメソッドは、カメラフレームを全画面に正しいアスペクト比で描画するために現在のOpenGLビューのサイズを取得する場合に使用されます。 外部レンダリングには共有のEAGLContextオブジェクトも必要であり、Wikitude SDK ネイティブAPIはこのオブジェクトを使用してカメラ関連のOpenGL ES呼び出しを発行します。こうすることで、カスタムレンダリングとWikitudeレンダリングが互いに影響しなくなり、競合の発生が抑えられます。
これらのブロックオブジェクトは以下のように使用できます。

if ( self.wikitudeUpdateHandler
    &&
     self.wikitudeDrawHandler )
{
    self.wikitudeUpdateHandler();
    self.wikitudeDrawHandler();
}
// ...external rendering code...

このようなコードは主に外部レンダリングのループ処理で使用されます。

外部OpenGL ESレンダリング用のAPIの選択

外部レンダリングの場合、SDKは外部レンダリングシステムによって使用されるレンダリングAPIを把握することで、正しいレンダリングAPIの呼び出しを内部的に行うことができます。
WTWikitudeSDKの+createExternalOpenGLESRenderingConfigurationの呼び出しでレンダリング設定が作成される場合、サポートされている中で最も高いOpenGL ESバージョンが自動的に選択されます。
手動でレンダリング設定を作成する場合、レンダリングの初期化機能の最後のパラメータに任意のバージョンを指定できます。

WTExternalOpenGLESRenderingMode *externalRenderingMode = [[WTExternalOpenGLESRenderingMode alloc] initWithDelegate:self andVersion:kEAGLRenderingAPIOpenGLES3];

内部OpenGL ESレンダリング

ホストするWikitude SDK ネイティブAPIを使用するアプリケーションでOpenGL ESレンダリングが設定されていない場合、Wikitude SDKネイティブAPIはWTWikitudeNativeSDKメソッドを通して取得できる独自のWTEAGLViewクラスを提供します。内部レンダリングでWikitude SDKネイティブAPIを起動するには、外部レンダリングの設定方法と同様にWTInternalOpenGLESRenderingModeでレンダリング設定を作成する必要があります。

WTRenderingConfiguration *renderingConfiguration = [WTWikitudeNativeSDK createInternalOpenGLESRenderingConfiguration:self];
self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingConfiguration:renderingConfiguration delegate:self];

self.wikitudeEAGLView = [renderingConfiguration view];

必要なオブジェクトがすべて作成されたら、アプリケーションのビュー階層にビューを追加する必要があります。これは、ストーリーボードを使用することも、プログラムすることもできます。Wikitude SDKネイティブAPIのサンプルアプリケーションでは、これをコードで実行します。

[self.view addSubview:self.wikitudeEAGLView];
[self.wikitudeEAGLView setTranslatesAutoresizingMaskIntoConstraints:NO];

NSDictionary *views = NSDictionaryOfVariableBindings(_wikitudeEAGLView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_wikitudeEAGLView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_wikitudeEAGLView]|" options:0 metrics:nil views:views]];

Wikitude SDKネイティブAPIの外部からカスタムのOpenGL ESを呼び出すために、カスタム更新および描画ブロックオブジェクトをWikitude SDKネイティブAPIに渡すことができます。対応するデリゲートメソッドは、起動フェーズ中に呼び出されます。

- (WTCustomOpenGLESUpdateHandler)wikitudeNativeSDKNeedsExternalOpenGLESUpdateHandler:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    /* Intentionally returning a nil handler here */
    return ^(){};
}

- (WTCustomOpenGLESDrawHandler)wikitudeNativeSDKNeedsExternalOpenGLESDrawHandler:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    __weak typeof(self) weakSelf = self;

    return ^(){
        if ( weakSelf.isTracking ) {
            [weakSelf.renderableRectangle drawInContext:[EAGLContext currentContext]];
        }
    };
}

このスニペットはカスタムレンダリングのみで更新ロジックはありません。

内部レンダリング用のAPIの選択

内部レンダリング用のAPIの選択は、外部レンダリングと同じ方法で動作します。

Metalレンダリング

以前のレンダリングの例にはOpenGL ESが搭載されていましたが、現在のほとんどのiOSデバイスでは、2014年にAppleによって導入されたレンダリングAPIであるMetalでレンダリングできる可能性があり、OpenGL ESよりもGPUをより詳細に制御できます。
前述のOpenGL ESの例に類似したMetalの外部レンダリングおよび内部レンダリングの例を示します。

外部Metalレンダリング

外部Metalレンダリングのサンプルアプリケーションには、シンプルなMetalビュー(ExternalMetalView)とMetalレンダラー(ExternalMetalRenderer)が含まれます。
外部レンダリングを有効にするには、WTMetalRenderingConfigurationをWTWikitudeNativeSDKの-createExternalMetalRenderingConfiguration:メソッドを呼び出すことで取得できるWTWikitudeNativeSDKメソッドの-initWithRenderingConfiguration:delegateに渡す必要があります。

WTMetalRenderingConfiguration* configuration = [WTWikitudeNativeSDK createExternalMetalRenderingConfiguration:self];
self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingConfiguration:configuration delegate:self];

-start:completion:の呼び出しで初期化されるWikitude SDKネイティブAPIの起動フェーズでは、WTExternalMetalRenderingProtocolプロトコルのいくつかのメソッドが呼び出されます。外部レンダリングのためにWikitude SDKネイティブAPIを準備する必要があります。

- (void)wikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK didCreateExternalMetalUpdateHandler:(WTWikitudeMetalUpdateHandler __nonnull)updateHandler
{
    self.wikitudeUpdateHandler = updateHandler;
}

- (void)wikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK didCreateExternalMetalDrawHandler:(WTWikitudeMetalDrawHandler __nonnull)drawHandler
{
    self.wikitudeDrawHandler = drawHandler;
}

- (id<MTLDevice>)metalDeviceForVideoCameraInWikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    if (!self.mtlDevice)
    {
        self.mtlDevice = [self.renderer device];
    }
    return self.mtlDevice;
}

- (id<MTLCommandQueue>)metalCommandQueueForVideoCameraInWikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    if (!self.mtlCommandQueue)
    {
        self.mtlCommandQueue = [self.renderer commandQueue];
    }
    return self.mtlCommandQueue;
}

- (CGRect)viewSizeForExternalRenderingInWikitudeNativeSDK:(WTWikitudeNativeSDK *)wikitudeNativeSDK;
{
    return self.metalView.bounds;
}

最初の2つのメソッドは、外部レンダリングシステムからフレームごとに呼び出す必要があるブロックオブジェクトを提供します。その目的は、内部SDKロジックを更新し、カメラストリームをMetalで描画することです。3つ目のメソッドは、カメラのフレーム全体を適切なアスペクト比で描画するために、現在のMetalビューのサイズを取得します。外部レンダリングには、Wikitude SDKネイティブAPIがカメラに関連するMetal呼び出しを発行するために使用するMTLDeviceオブジェクトとMTLCommandQueueオブジェクトも必要です。この方法では、カスタムレンダリングとWikitudeレンダリングは互いに影響を及ぼさず、競合が少なくなります。
これらのブロックオブジェクトの使用例を次に示します。

if ( self.wikitudeUpdateHandler && self.wikitudeDrawHandler )
{
    self.wikitudeUpdateHandler();
    self.wikitudeDrawHandler([_renderer renderCommandEncoder]);
}

// ...external rendering code...

Metalでは、OpenGL ESとは対照的に、レンダラーのMTLRenderCommandEncoderをすべてのフレームでwikitudeDrawMetalHandlerに渡す必要があります。このコマンド・エンコーダーはレンダー呼び出しのすべてのコマンドを保持するので、レンダリングする必要があるすべてのオブジェクトはレンダリングするためにアクセスする必要があります。

内部Metalレンダリング

ホストするWikitude SDK ネイティブAPIを使用するアプリケーションでMetalレンダリングが設定されていない場合、Wikitude SDKネイティブAPIは独自のMetal互換クラスを提供します。このクラスはWTMetalViewです。このクラスのオブジェクトは、WTMetalRenderingConfigurationオブジェクトから取得できます。内部レンダリングを使用してWikitude SDKネイティブAPIを起動するには、WTWikitudeNativeSDKのcreateInternalMetalRenderingConfiguration:メソッドによって作成された構成を、-initWithRenderingConfiguration:delegate:に渡します。

WTMetalRenderingConfiguration *configuration = [WTWikitudeNativeSDK createInternalMetalRenderingConfiguration:self];

self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingConfiguration:configuration delegate:self];

self.wikitudeMetalView = [configuration metalView];

その後、アプリケーションのビュー階層にビューを追加する必要があります。これは、ストーリーボードを使用することも、プログラムすることもできます。Wikitude SDKネイティブAPIのサンプルアプリケーションでは、これをコードで実行します。

[self.view addSubview:self.wikitudeMetalView];
[self.wikitudeMetalView setTranslatesAutoresizingMaskIntoConstraints:NO];

NSDictionary *views = NSDictionaryOfVariableBindings(_wikitudeMetalView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_wikitudeMetalView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_wikitudeMetalView]|" options:0 metrics:nil views:views]];

Wikitude SDKネイティブAPIの外部からカスタムのMetalを呼び出すために、カスタム更新および描画ブロックオブジェクトをWikitude SDKネイティブAPIに渡すことができます。対応するデリゲートメソッドは、起動フェーズ中に呼び出されます。

- (WTCustomMetalUpdateHandler)wikitudeNativeSDKNeedsExternalMetalUpdateHandler:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    /* Intentionally returning a nil handler here */
    return ^(){};
}

- (WTCustomMetalDrawHandler)wikitudeNativeSDKNeedsExternalMetalDrawHandler:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    return ^(id<MTLRenderCommandEncoder> renderCommandEncoder) {
        if (_isTracking)
        {
            [self.renderableRectangle drawWithCommandEncoder:renderCommandEncoder];
        }
    };
}

このスニペットでは、更新ロジックは実装されておらず、カスタムレンダリングのみが実装されています。wikitudeNativeSDKNeedsExternalDrawMetalHandler:メソッドは内部的に使用されるMTLRenderCommandEncoderを提供します。このコマンド・エンコーダーは、レンダラーによってレンダリングされるすべてのオブジェクトに渡される必要があります。