Converting the model file formats

Conducted by Fraser Savage

Overview

As we plan to let the user upload models to a webapp and then download them for use in the hololens application, we need a way to automatically convert models from one of the provided formats stl to a format Unity can use obj. To summarise what was done in this experiment:

  • Used the ASSIMP C++ library to import stl files and export them as obj files
  • Used the Java Native Interface to make this functionality available for a Java application

1. Creating the Java function prototype and corresponding .h file

To be able to run C++ code from the Java application I first had to create the native function declaration in my Java class:

private native boolean convertStlToObj(String filePath, String fileName);

This native function needed to reside within a system library which, on Linux is a so file residing in /usr/lib (my distribution is Arch Linux). These libary's are typically named with the format of lib<name>.so.

The Java class which makes use of the native function requires for the library to be loaded using the System.loadlibrary() call in it's static block. For example to load the library file libconverter.so I would use the following:

static {
  System.loadlibrary("converter");
}

Next I built the application, generating all the necessary class files. To generate the correct header file I then ran the following command in my shell environment from the 'root' of the output folder:

$ javah com.company.Main

This generated the com_company_Main.h header file for JNI usage by the Main class in com.company package.

2. Implementing the C++ function

With the javah generated header file I could then begin to explore the Assimp library. The reason for using JNI and making the codebase polyglot was because of the need to convert models into a format that we can use in Unity, so the requirement for this function is primarily to convert stl files to obj files. As a result additional postprocessing takes a back seat.

To function prototype generated by javah was:

JNIEXPORT jboolean JNICALL Java_com_company_Main_convertStlToObj
  (JNIEnv *, jobject, jstring, jstring);

So implementing the function in the com_company_Main.cpp file I needed to use the same declaration and include the following libaries:

  • <jni.h>
  • "com_company_Main.h"

In addition, I needed to include a couple of assimp header files, namely:

  • <assimp/Importer.hpp>
  • <assimp/Exporter.hpp>
  • <assimp/scene.h>
  • <assimp/postprocess.h>

I will omit the code snippet for the sake of brevity, but the "algorithm" that the function performs is as follows:

  1. Convert the jstring parameters to native C++ strings
  2. Use the Assimp::Importer class to read the stl from file
  3. Store the imported stl as a const aiScene*, processing it at the same time
  4. Check that the scene imported correctly
  5. Use the Assimp::Exporter class to export the scene to an obj file in the same location as the imported stl
  6. Check the obj file generated can be imported correctly

The function will return JNI_FALSE to the calling java program if any of the steps fail, while returning JNI_TRUE if all is well.

3. Preparing it for user

The final step in preparing the native function was to use g++ to compile and link the two files, com_company_Main.cpp and com_company_Main.h with the Assimp library and point it towards the jdk include directories. This would compile the .so file which I then copied into the /usr/lib directory, allowing me to use the function to convert stl files to obj files within a Java application.

4. Conclusion

This experiment proved to be quite useful as it exposed me to interop between different classes of language within the same component of the application, as well as allowing me to explore the possibilities for preprocessing models for the HoloLens application.

It also highlighted that there is a flexibility over what language and framework to use for the server application, as long as it can call C/C++ libraries - conversion of model file types is a relatively important requirement.