Documentation

Rendering

This example shows and explain how rendering works in combination with the Wikitude SDK Native API. There are two methods of rendering available in the Wikitude Native SDK. We call them internal and external rendering. Internal means the OpenGL view is setup by the Wikitude SDK and the SDK user can define custom rendering, that is executed by the Wikitude SDK. On the other hand external rendering means the SDK user sets up the OpenGL view and integrates the Wikitude SDK into this rendering setup.

  1. Rendering APIs
  2. External Rendering
  3. Internal Rendering

Rendering APIs

The Wikitude Native SDK for iOS currently supports the following RenderingAPIs:

  • OpenGL ES 3
  • OpenGL ES 2

How the Rendering API can be selected can be seen at Rendering API selection for External Rendering or Rendering API selection for Internal Rendering.

External Rendering

Most of the examples in the Wikitude Native SDK example application use external rendering, simply because it might be the preferred usage by developers. The example application comes with a simple OpenGL ES view (ExternalEAGLView) and an also very simple renderer (ExternalRenderer).

To activate external rendering you need to pass WTRenderingMode_External to the WTWikitudeNativeSDK method -initWithRenderingMode:delegate.

self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingMode:WTRenderingMode_External delegate:self];

During the Wikitude Native SDK startup phase, which is initialized with a call to -start:completion:, several methods from the WTWikitudeNativeSDKDelegate protocol are called. They are needed to prepare the Wikitude Native SDK for external rendering. All methods in the WTWikitudeNativeSDKDelegate protocol are marked as optional, but the Wikitude Native SDK will call its -wikitudeNativeSDK:didEncounterInternalError: delegate method if a required method is not implemented or returned an invalid value. The required methods are:

  • -wikitudeNativeSDK:didCreatedExternalUpdateHandler:
  • -wikitudeNativeSDK:didCreatedExternalDrawHandler:
  • -eaglViewSizeForExternalRenderingInWikitudeNativeSDK:
  • -eaglContextForVideoCameraInWikitudeNativeSDK:
 - (void)wikitudeNativeSDK:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK didCreatedExternalUpdateHandler:(WTWikitudeUpdateHandler __nonnull)updateHandler
{
    self.wikitudeUpdateHandler = updateHandler;
}

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

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

- (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;
}

The first two methods provide block objects, that need to be called every frame from the external rendering system. There purpose is to update internal SDK logic and draw the camera stream in OpenGL. The last one is used to get to know the current OpenGL view size in order to draw the camera frame fullscreen and with the correct aspect ratio. External rendering also requires a shared EAGLContext object that is used by the Wikitude Native SDK to issue camera related OpenGL ES calls. This way custom rendering and Wikitude rendering do not influence each other and less conflicts can occur.

An example of how those block objects can be used is the following:

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

Such a snippet is typically found somewhere in the external render loop.

Rendering API selection for External Rendering

For external rendering the SDK needs to know which Rendering API was used by the external rendering system so the correct rendering API calls can be made internally. If this is not explicitly set, the SDK will expect an OpengL ES 2 context.

To set the rendering API, use the WTNativeSDKStartupConfiguration method -targetRenderingAPI:

Make sure that only one rendering API is set, otherwise the SDK does not start and reports an error in the completion handler of -start:completion

An example implementation of this can be found in the external rendering example of the Wikitude SDK (Native API) example application. Here the rendering API is specified with an converted value from the external rendering system.

WTRenderingAPI renderingAPI = [WTExternalRenderingViewController convertToWikitudeRenderingAPI:self.renderer.activeRenderingAPI];
startupConfiguration.targetRenderingAPI = [NSOrderedSet orderedSetWithObjects:renderingAPI, nil];

Internal Rendering

In case no OpenGL ES 2 rendering is already setup in the hosting Wikitude Native SDK application, the Wikitude Native SDK brings its own set of OpenGL ES 2 compatible classes to do so. These classes are WTEAGLView and WTRenderer. Objects of those classes can be retrieved through WTWikitudeNativeSDK methods. To start the Wikitude Native SDK with internal rendering, pass WTRenderingMode_Internal to the -initWithRenderingMode:delegate: method.

self.wikitudeSDK = [[WTWikitudeNativeSDK alloc] initWithRenderingMode:WTRenderingMode_Internal delegate:self];

self.wikitudeRenderer = [self.wikitudeSDK createRenderer];
self.wikitudeEAGLView = [self.wikitudeSDK createEAGLView];

After all required objects are created, view and renderer have to be connected through a call to setRenderer:.

[self.wikitudeEAGLView setRenderer:self.wikitudeRenderer];

After those two objects are connected, the view has to be added to the view hierarchy of your application. This can either be done using Storyboards or programmatically. The Wikitude Native SDK example application does it in code.

[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]];

To do some custom OpenGL ES 2 calls from outside the Wikitude Native SDK, custom update and draw block objects can be passed to the Wikitude Native SDK. The corresponding delegate methods are called during the startup phase.

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

- (WTCustomDrawHandler)wikitudeNativeSDKNeedsExternalDrawHandler:(WTWikitudeNativeSDK * __nonnull)wikitudeNativeSDK
{
    return ^(){
        if ( _isTracking ) {
            [self.renderableRectangle drawInContext:[EAGLContext currentContext]];
        }
    };
}

In this snippet only custom rendering is done and no update logic.

Rendering API selection for Internal Rendering

For internal rendering the SDK needs to know which rendering API context is shall create. If this is not explicitly set the SDK will create and use an Open GL ES 2 context.

To set the rendering API use WTNativeSDKStartupConfiguration's method -targetRenderingAPI:.

The SDK will try to create the given rendering APIs in the following order: OpenGL ES 3 > OpenGL ES 2.

A WTNativeSDKStartupConfiguration object is available in the first block of -start:completion and can be modified like shown below:

/* Try to create an OpenGL ES 3 context. If OpenGL ES 3 is not supported on the current device, an OpenGL ES 2 context is created */

startupConfiguration.targetRenderingAPI = [NSOrderedSet orderedSetWithObjects:WTRenderingAPI_OpenGL_ES_3, WTRenderingAPI_OpenGL_ES_2, nil];
/* Try to create an OpenGL ES 3 context. If the current devcie does not support OpenGL ES 3, the SDK will not start and report an error in the completion handler of `-start:completion:` */

startupConfiguration.targetRenderingAPI = [NSOrderedSet orderedSetWithObjects:WTRenderingAPI_OpenGL_ES_3, nil];

To check which rendering API context was created in case multiple desired rendering APIs were given, implement the WTWikitudeNativeSDKDelegate method -wikitudeNativeSDK:didSetupRendererWithAPI: to know what the SDK did setup internally.

- (void)wikitudeNativeSDK:(WTWikitudeNativeSDK *)wikitudeNativeSDK didSetupRendererWithAPI:(WTRenderingAPI)renderingAPI
{
    NSLog(@"Wikitude SDK did setup rendering with API '%@'", renderingAPI);
}