您现在的位置是:首页 >学无止境 >编译3D渲染引擎Horde3D网站首页学无止境
编译3D渲染引擎Horde3D
Horde3D是Github上一款开源的轻量级3D渲染引擎,同时它还支持多个平台。今天我们准备在Mac平台上交叉编译至Android平台。如果需要同时能编译Sample,那么还需要SDL2库。默认情况下,编译Horde3D
时不强制下载SDL2
,你可以选择强制下载,版本默认下载的是2.0.9
,不过我们打算替换为2.26.5
。推荐读者最好先看一下Horde3D根目录下的CMakeLists.txt
脚本,可以更好地理解细节。废话不多说,现在开始编译。
文章目录
- 1. 配置编译环境
- 2. 编译Horde3D渲染引擎
- 2.1 预编译SDL2库
- 2.2 修改Horde3D Android Sample中样板代码
- 2.2.1 替换BuildTools/android/app/src/main/java/org/libsdl/app下源码
- 2.2.2 (可选)修改BuildTools/android/app/下build.gradle.in和AndroidManifest.xml
- 2.2.3 (可选)修改BuildTools/android/gradle/wrapper下gradle-wrapper.properties文件
- 2.2.4 (可选)修改BuildTools/android/下build.gradle文件
- 2.2.5 修改Horde3D/Samples/Framework/SDLFramework.cpp
- 2.3 修改Horde工程CMakeLists.txt
- 2.4 (可选)添加BuildTools/android/gradlew的执行权限
- 2.5 编译Horde3D库及Sample
- 3. 吐槽在Windows上的踩坑之路
1. 配置编译环境
交叉编译至Android平台我们需要用到NDK
,为了同时能编译Android App Sample,我们再额外准备一下Android SDK
(如果你很熟悉这些,请跳过这一部分,不然的话,你最好进入Android Studio中的SDK Manager
下载你需要的平台SDK)。至于CMake
工具,在官网上下载即可。在Mac,Linux上编译流程类似,在Windows上稍微麻烦一点,不过是类似的,无非是环境变量的配置麻烦点,笔者都已编译过。
本次编译我们选择Mac机器进行操作示范,同时,我们通过分析Horde3D
的根CMakeLists脚本,先预编译好SDL2
库,然后替换一部分Horde3D
的Sample的预构建样板代码,具体下面操作介绍。
2. 编译Horde3D渲染引擎
2.1 预编译SDL2库
在预编译SDL2
之前,让我们先拉取一下Horde3D
的源码:
git clone https://github.com/horde3d/Horde3D.git
查看Horde3D
的根CMakeLists脚本,我们看到其中逻辑会进入到find_package(SDL2)
,该语句会执行FindSDL2.cmake
脚本。其实这里的脚本有一些逻辑错误,假如既未预编译安装SDL2
库,又未强制要求Download SDL2(HORDE3D_FORCE_DOWNLOAD_SDL默认为OFF
),那么会进入错误的逻辑,虽然问题不大,但是确实很讨厌。因此,出于编译单元分离的目的,我们先进行SDL2
的编译。
在机器上找个合适的目录,将SDL2.26.5.zip下载下来并解压,创建一个用于存放构建内容的目录,例如:
mkdir build-android
我们可以使用CMake-GUI工具,配置以下几个Entry(ANDROID_ABI,ANDROID_PLATFORM,ANDROID_DL_LIBRARY),Entry的值可直接参考Horde的编译指导,同时在Configure
时我们选择Unix makefiles
和Specify toolchain file for cross-compiling
,cmake文件选择ndk中的Android NDK/build/cmake/android.toolchain.cmake
文件。然后将CMAKE_INSTALL_PREFIX
设置为自定义的目录,例如build-android
下再自定义一个output
。Configure
完成后进行Generate
以生成Makefile
文件,然后在build-android
目录下执行:
make && make install
至此,SDL2.26.5
版本已编译成功并安装至build-android/output
下。
当然,如果你不喜欢使用CMake GUI,那么也可以在build-android
目录下启动一个终端,并输入(供参考):
cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-24 -DANDROID_DL_LIBRARY=<path-to-your-Android-SDK>/ndk/<ndk-version>/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/aarch64-linux-android/24/libdl.so -DCMAKE_BUILD_TYPE=Release -DANDROID_SDK_ROOT_PATH=<path-to-your-Android-SDK> -DCMAKE_TOOLCHAIN_FILE=<path-to-your-Android-SDK>/ndk/<ndk-version>/build/cmake/android.toolchain.cmake -DCMAKE_INSTALL_PREFIX=<path-to-current-dir>/output -G "Unix Makefiles" --fresh ..
--fresh
选项是较新的CMake上才有的,例如本文使用的3.26.4
,该选项可以确保刷新CMakeCache变量。至于24
,你也可以改成别的版本,配套即可。
等待构建文件生成后,再执行以下命令用以启动make
:
cmake --build .
最后再make install
一下。至此,与前文用CMake GUI的方式结果一致。
2.2 修改Horde3D Android Sample中样板代码
2.2.1 替换BuildTools/android/app/src/main/java/org/libsdl/app下源码
该目录下默认包含来自SDL2.0.9
的代码,我们可以将SDL2.26.5
解压缩的文件夹中的android-project/app/src/main/java/org/libsdl/app
下的java文件拷贝至BuildTools/android/app/src/main/java/org/libsdl/app
下。
2.2.2 (可选)修改BuildTools/android/app/下build.gradle.in和AndroidManifest.xml
该目录下的build.gradle.in
文件是预构建Sample的app层级的build.gradle
的模版文件。修改其中的compileSdkVersion
,targetSdkVersion
,同时删掉buildToolsVersion = '28.0.3'
这句话。
若使用31及以上的SDK,则需要在AndroidManifest.xml
中的<activity>中添加android:exported="true"
字段。
2.2.3 (可选)修改BuildTools/android/gradle/wrapper下gradle-wrapper.properties文件
默认的Gradle
版本使用的是5.1.1-all
,可以自行修改至已下载的版本,例如笔者改成了6.7.1-all
,缩减后续时间。
2.2.4 (可选)修改BuildTools/android/下build.gradle文件
buildscript {
repositories {
// jcenter()
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
}
}
allprojects {
repositories {
// jcenter()
mavenCentral()
google()
}
}
2.2.5 修改Horde3D/Samples/Framework/SDLFramework.cpp
修改以下代码(修改前):
SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" );
修改后:
// SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
SDL_SetHint( SDL_HINT_MOUSE_TOUCH_EVENTS, "0" );
SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" );
2.3 修改Horde工程CMakeLists.txt
我们不打算通过find_package
的方式去查找SDL2的目录,此处直接写入以下几个值:
# find_package(SDL2)
set(SDL2_FOUND TRUE)
set(SDL_LIB_PATH "<path-to-your-sdl2>/lib")
set(SDL2_INCLUDE_DIR "<path-to-your-sdl2>/include/SDL2")
set(SDL_LIBRARY_PATH <path-to-your-sdl2>/lib/libSDL2.so")
set(SDL2_LIBRARY ${SDL_LIBRARY_PATH})
2.4 (可选)添加BuildTools/android/gradlew的执行权限
最好检查一下该文件的执行权限,否则在构建Sample过程中会出现Permission Denied
错误。使用chmod
命令,此处不赘述。
2.5 编译Horde3D库及Sample
前文所述的操作步骤完成后,即可创建自定义build文件夹来存放构建成果物,例如创建一个build-android
文件夹,在该目录下打开终端,执行以下命令:
cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-24 -DHORDE3D_FORCE_DOWNLOAD_SDL=OFF -DHORDE3D_USE_GL2=OFF -DHORDE3D_USE_GL4=OFF -DHORDE3D_USE_GLES3=ON -DCMAKE_BUILD_TYPE=<Debug-or-Release> -DANDROID_SDK_ROOT_PATH=<path-to-your-Android-SDK> -DCMAKE_TOOLCHAIN_FILE=<path-to-your-Android-SDK>/ndk/<ndk-version>/build/cmake/android.toolchain.cmake -G "Unix Makefiles" --fresh ..
随后开始进行编译构建,同前文:
cmake --build .
最后可以在build-android/Android
下找到多个Android Sample Project。在Android Studio中打开并运行至手机,以Chicago
为例,最后可以看到成功运行,图就不放了,读者自己去构建吧。
3. 吐槽在Windows上的踩坑之路
跟着下面的步骤,让我们一起在Windows上踩坑吧。
现在开始第一次编译,我们还没有单独编译SDL2库,因此就采用直接运行脚本来自动下载SDL2库并进行默认编译链接等动作。按照Horde3D的编译doc指导进行操作。
在Windows平台上使用CMake gui来配置路径地址时,不要使用斜杠,一定要统一使用/斜杠,不然会导致后续的解析失败。
执行Configure
,OK,不出所料,报错了。这里其实确实是一个脚本的问题,原因是我们没有强制要求下载SDL2库,它默认为SDL2已在本地是有的,因此要消除这个bug,我们本质上需要修改一下CMakeLists脚本。找到下面这句话,将OFF
改为ON
,或者也可以直接在CMake GUI中将HORDE3D_FORCE_DOWNLOAD_SDL
这个option打上勾。
option(HORDE3D_FORCE_DOWNLOAD_SDL "Force linking Horde3D to a downloaded version of SDL" OFF)
在CMake gui中重新Configure,再次报错,错误信息如下:
External SDL project done
CMake Error at BuildTools/CMake/Modules/FindSDL2.cmake:255 (get_filename_component):
get_filename_component unknown component -pthread
Call Stack (most recent call first):
CMakeLists.txt:55 (find_package)
Configuring incomplete, errors occurred!
我们找到FindSDL2.cmake
文件的第255行:
IF( ${CMAKE_SYSTEM_NAME} STREQUAL "Android" )
get_filename_component( SDL_LIB_PATH ${SDL2_LIBRARY} DIRECTORY )
ENDIF()
再稍作定位,找到SDL2_LIBRARY这个参数,在第245行:
set(SDL2_LIBRARY ${SDL_LIBRARY_PATH} ${CMAKE_THREAD_LIBS_INIT})
给CMAKE_THREAD_LIBS_INIT加个打印,重新Configrure一下,可以看到,这个值就是-pthread
。
下一个问题,get_filename_component()
函数是干嘛的(读者如果不知道的话,还是看一下CMake官方doc吧 get_filename_component),是不是移除-pthread
就行。我们知道,在NDK的Native APIs这一节里,有提到这么一句话:
The standard C11 library headers such as <stdlib.h> and <stdio.h> are available as usual.
Note that on Android, unlike Linux, there are no separate `libpthread` or `librt` libraries. That functionality is included directly in libc, which does not need to be explicitly linked against.
因此,当我们的构建目标是Android
时,不需要主动去链接pthread
库,因为已经合入到了c
库中,而c
库又是NDK编译时会自动链接的。现在想必你应该已经知道了解决办法。很简单,我们将${CMAKE_THREAD_LIBS_INIT}
这个值删掉。
在CMake GUI中重新configure。可喜可贺,看到了喜闻乐见的Configuring done
。心情瞬间是不是好了很多。其实这后面还有坑等着你,不过到目前为止,我们似乎已经准备好了一切。接下来的工作就不手把手教了。笔者直接在此罗列一下遇到的坑。相信读者也能靠自己的耐心与能力解决它们。
3.1 给工程最好加上CMP0135政策
按照官方的提示,我们在主CMakeLists中插入以下语句:
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif(POLICY CMP0135)
3.2 默认下载的SDL2.0.9版本Clang14编译失败
Clang14在编译2.0.9版本SDL2库时,报了一个C99的错误,查看原因,似乎也很难分析出为什么,看代码似乎一切正常,摆烂,直接与时俱进,替换为SDL最新的发布版本。
查找并替换脚本中预下载的SDL版本至2.26.5
。这需要接下来进行一系列的修改,主要包括将原先2.0.9的预置代码统统删掉,替换为2.26.5的新代码。
3.3 SDL2.26.5中已移除SDL_HINT_MOUSE_TOUCH_EVENTS
修改SDLFramework.cpp
中的代码,替换为以下代码,同前文所述:
// SDL_SetHint( SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, "1" );
SDL_SetHint( SDL_HINT_MOUSE_TOUCH_EVENTS, "0" );
SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" );
完成上述的这些修改后,需要在CMake gui中重新Configure,使其构造出默认的样板工程。然后运行Generate
,创建Makefile
脚本,然后运行使用NDK中Android NDK/prebuilt/windows-x86_64/bin/make.exe
,参考Horde3D的doc即可。