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 asobj
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:
- Convert the
jstring
parameters to native C++ strings - Use the
Assimp::Importer
class to read thestl
from file - Store the imported
stl
as aconst aiScene*
, processing it at the same time - Check that the scene imported correctly
- Use the
Assimp::Exporter
class to export the scene to anobj
file in the same location as the importedstl
- 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.