Unity Native Programming

Unity is great in terms of the ease to create graphics applications, the wide compatibility with different platforms (thanks to Mono), and its pioneering role in the current fast growing AR/VR market. However, most programmers are more comfortable with C++, and Linux, than C# and Windows. As a result, many existing great libraries, especially in the field of computer vision, are C++ projects. Examples include OpenCV, ARToolKit, etc.

In order to reuse native libraries in Unity projects, here are two options:

  • re-implement the algorithm in C# (Javascript)
  • find a way to interface native libraries.

I went for the second option, and here comes HoloLensARToolKit. I hope this wiki page will make your life easier when you are faced with this question.

Managed and Unmanaged Library

Unity builds managed libraries, that is to say, the libraries and applications built by Unity are managed by Common Language Runtime (thanks to Mono again). According to the Wikipedia page:

The CLR provides additional services including memory management, type safety, exception handling, garbage collection, security and thread management.

Great! C++ code can be built with CLR as well, as the name “Common Language Runtime” suggests. Therefore, one good way to go is to build your native code using CLR, put your library in Unity asset path, and use it as if it is written in C#.

However, it is not quite intuitive to migrate those huge and useful native libraries (OpenCV, ARToolKit) to CLR. If you just hit “build” to build them, the library files that appear in your project folder are unmanaged libraries. Some additional work has to be done in order to correctly and safely interface managed and unmanaged libraries: Marshaling and PInvoke.

Native Code

Let us look at the native C++ code first.

You need and only need to answer the following two questions:

  • What is the desired running platform?
  • What are the functions that you want to call in C# managed code?

Desired running platform

If we take Win32 as example, then the native library should be compatible with Win32. Because the built dll file is shipped with your Unity application to the desired platform, all the dependencies of your library should exist on the target platform.

In the case of HoloLensARToolKit, the library ARToolKitUWP.dll should depend only on UWP and WINRT system libraries, instead of general Win32 libraries (e.g. kernel32.dll). A useful tool is called Dependency Walker that can help you to check the dependecies of a dynamic link library.

Let’s take a look at the dependency of our ARToolKitUWP.dll:

Dependency

Basically, in order to successfully link the native library on the target platform, these dependencies must be satisfied on the given device. If your library depends on other third-party libraries, then these third-party libraries should be compatible with the specific platform as well, and make sure they are placed in the searching directory of runtime linker. If you are not sure about the directories, just place them at the same location as the .exe or .dll files.

What functions to use?

Not all functions in a library can be called by the outside, apparently. It is left to the programmer to design an accessible interface exposed to other libraries. The files ARToolKitUWP.h and ARToolKitUWP.cpp define such interface for HoloLensARToolKit project.

The keywords to use that specifies exportable functions are extern "C" and __declspec(dllexport). The minimum example is:

#define EXPORT_API __declspec(dllexport)
extern "C" {
    EXPORT_API void HelloWorld();
}

A good practice is to design a singleton class representing a controller, so that all the public functions of the singleton object could be called externally, and the native library manages one single object. In the case of ARToolKit, the ARController class is designed like this, since there is only need for one controller in general.

ARToolKitUWP.h defines the full list of exportable functions for HoloLensARToolKit project.

Unity Side Scripting

In order to use the exposed function of native libraries, function signatures have to be defined, so that C# finds the function to call inside native libraries. Such function definitions are like this:

using System.Runtime.InteropServices;            // system reference
public static class HelloWorldFunctions {
    [Dllimport("HelloWorldLibrary.dll")]         // provide the name of library
    public static extern void HelloWorld();      // entry of function
}

Once such function definitions are made and the functions are found in the native library, they can be directly called in C# code. This technology is called PInvoke.

In HoloLensARToolKit project, the native function entries are defined in ARToolKitUWP-Unity/Scripts/ARUWPNative.cs, for your reference.

Function Parameters

As you may found out, there are some strange code around parameter definitions, like this:

[DllImport("ARToolKitUWP")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool aruwpGetARToolKitVersion([MarshalAs(UnmanagedType.LPStr)]StringBuilder buffer, int length);

It is called Marshaling. According to Wikipedia,

In computer science, marshalling or marshaling is the process of transforming the memory representation of an object to a data format suitable for storage or transmission, and it is typically used when data must be moved between different parts of a computer program or from one program to another.

In the case of C# interfacing native code, the data exchange between managed environment and unmanaged environment only happens at the time when native functions are called and returned. The processing by native code happens in between, but the computation does not affect the managed memory. Therefore, we only need to perform such memory transformation when native functions are called and returned. Marshaling does the trick.

For instance, for the above function, the native code looks like this:

EXPORT_API bool aruwpGetARToolKitVersion(char *buffer, int length);

The bool type of C++ is marshaled to the bool type of C#, and the char buffer set by native function is returned as StringBuilder object of C#, because of the different representation of data types for both languages. Marshaling is not only about data type conversion, but also creates manageable memory for unmanaged data, so that the data can be later managed by CLR, e.g. garbage collection.

Thanks for reading and happy coding.


ARToolKit on HoloLens

HoloLens is fascinating in terms of holographic display and in-room localization, but the capability of the front-facing camera (locatable camera) is not fully utilized for potential augmented reality applications.

ARToolKit

Since ARToolKit has served AR/VR for more than 10 years, and it is open-source, it would be nice to have it running on HoloLens. The obstacles towards this goal are quite clear as well:

  • Universal Windows has a whole different set of tools and run-time libraries. The dependencies of existing ARToolKit does not exist on UWP, such as pthreads, video libraries, opencv.
  • ARToolKit is written in native C/C++ code, and an additional wrapper is needed for development on Unity, which is recommended for HoloLens. (If you are not good at Direct3D, and Windows App)

Luckily, after spending some time on this, I successfully get some pieces of code written, and actually make ARToolKit runs on HoloLens.

The repository is called HoloLensARToolKit on Github.

Demos

The following videos and screenshots are taken with HoloLensARToolKit v0.1.

Samples of HoloLensARToolKit

There are three samples of HoloLensARToolKit, each representing a certain kind of marker that is supported: single marker, cube marker and multi marker.

Minion on the Cube

This video is taken on HoloLens Device Portal, also known as Mixed Reality Capture. You might have noticed that there is still some lag between the video that is captured and update in the rendering.

More Screenshots

  • Single Marker

  • Cube Marker

  • Multi Marker

Finally

You can access more articles describing the implementation details of HoloLensARToolKit in my blog, simply clicking on the tag: hololens-artoolkit.

With ARToolKit integrated with HoloLens, many more augmented reality applications are possible. If you are AR/VR developer, you must see what I mean here.

Thanks for reading.