Vulkan on Android 4 — Model Rendering Part 1
Our canvas needs some colors on other than just a background. For the purpose, we will dump in a model, draw colors on it with images and lights and finally, make it move around. But in this post, we are going to be done with some prerequisite first.
GLM
OpenGL Mathematics (GLM) is a header only C++ mathematics library for graphics software based on the OpenGL Shading Language (GLSL) specifications.
GLM provides classes and functions designed and implemented with the same naming conventions and functionalities than GLSL so that anyone who knows GLSL, can use GLM as well in C++.
This project isn’t limited to GLSL features. An extension system, based on the GLSL extension conventions, provides extended capabilities: matrix transformations, quaternions, data packing, random numbers, noise, etc…
So, we know what it is used for, but how do we integrate it into our project?
- Download GLM from Github, we need only the whole
glm
sub-directory. Nocmake
, nodoc
, notest
,.vscode
,uitily
,.appveyor.yml
, …etc. - Place
glm
somewhere as long as we specify the path to it later inCMakeLists.txt
in our project. For me, I put it toapp/include
directory. - Adds a search path for header files and some definitions in
app/CMakeLists.txt
.
# glm
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_definitions("-DGLM_FORCE_SIZE_T_LENGTH -DGLM_FORCE_RADIANS -DGLM_FORCE_DEPTH_ZERO_TO_ONE -DGLM_LANG_STL11_FORCED")
add_subdirectory(include/glm)
GLM_FORCE_DEPTH_ZERO_TO_ONE
worths a brief explanation. The viewport transform matrix in Vulkan differs with what we use in OpenGL so it requires some adaptions if we still set the same depth range values as we do in OpenGL(glDepthRange
).
STB
STB is a collection of single-file libraries for C/C++. However, we are only interested in stb_image.h
for image decoding.
We do not add definitions about stb_image.h
in CMakeLists.txt
due to that the document states that we should include this header file in only one C or C++ file, and add definitions before including it.
Assimp
Assimp might be the only comprehensive model loading library I could ever find. It supports various 3D model formats and is with extra useful features that impressed me. I used to deal with lightweight model loading library which supports a single 3D model format and be happy with it. It is fast and easy to use but I realized it is not the best choice in the long run so I switch to Assimp in the end.
Build
Assimp official website does not offer step-by-step instructions about how to build it on Android. The results I’ve googled are not consistent steps to follow and they vary from version to version, tool to tool. Finally, I discovered a simple way to build it with Android studio. Not a single command is required.
- Download Assimp from the official site.
- Create a new module of type Android Library with any name we want, like,
assimp
, and delete anything about testing. - Unzip assimp-4.1.0.zip(in my case) and place the directory
assimp-4.1.0
toassimp/src/main
. - Specify the path of
CMakeLists.txt
and add some definitions inbuild.gradle
of our new module. Here I disabled the support for all the 3D formats and enables the support for FBX, BLEND, and OBJ files. Note it is not mandatory to defineASSIMP_ANDROID_JNIIOSYSTEM
on Android if we are not going to load assets from theassets
folder.
...
android {
defaultConfig {
minSdkVersion 25
targetSdkVersion 28
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared",
"-DASSIMP_ANDROID_JNIIOSYSTEM=ON",
"-DASSIMP_NO_EXPORT=ON",
"-DASSIMP_BUILD_ASSIMP_TOOLS=OFF",
"-DASSIMP_BUILD_TESTS=OFF",
"-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=FALSE",
"-DASSIMP_BUILD_FBX_IMPORTER=TRUE",
"-DASSIMP_BUILD_BLEND_IMPORTER=TRUE",
"-DASSIMP_BUILD_OBJ_IMPORTER=TRUE"
cppFlags "-fexceptions"
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
}
...
externalNativeBuild {
cmake {
path "src/main/assimp-4.1.0/CMakeLists.txt"
}
}
}
...
5. Build the module and we ‘ll get libassimpd.so
and libandroid_jniiosystemd.a
(if ASSIMP_ANDROID_JNIIOSYSTEM
is defined) for debugging build or libassimp.so
and libandroid_jniiosystem.a
for release build. Note we’ll get multiple .so
and .a
files if we specify multiple terms in abiFilters
. Our app runs on armeabi-v7a
and arm64-v8a
so we should build Assimp on the same architectures accordingly.
6. Remove and delete the module since we don’t need it anymore.
Link
That’s all, now we are going to link the libraries for our project.
1. Create folders inside app
directory:
app/libs/armeabi-v7a
app/libs/armeabi-v8a
and place our new fresh libraries to corresponding ones.
2. Link the libraries in app/CMakeLists.txt
...
add_library(assimp-lib SHARED IMPORTED)
set_target_properties(assimp-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libassimp.so)
add_library(android_jniiosystem-lib SHARED IMPORTED)
set_target_properties(android_jniiosystem-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libandroid_jniiosystem.a)
...
target_link_libraries( # Specifies the target library.
main
...
assimp-lib
android_jniiosystem-lib )
3. Copy the extracted assimp-4.1.0/include/assimp
header files to app/include
for later use.