编译3D渲染引擎Horde3D

Horde3D是Github上一款开源的轻量级3D渲染引擎,同时它还支持多个平台。今天我们准备在Mac平台上交叉编译至Android平台。如果需要同时能编译Sample,那么还需要SDL2库。默认情况下,编译Horde3D时不强制下载SDL2,你可以选择强制下载,版本默认下载的是2.0.9,不过我们打算替换为2.26.5。推荐读者最好先看一下Horde3D根目录下的CMakeLists.txt脚本,可以更好地理解细节。废话不多说,现在开始编译。

在这里插入图片描述

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 makefilesSpecify toolchain file for cross-compiling,cmake文件选择ndk中的Android NDK/build/cmake/android.toolchain.cmake文件。然后将CMAKE_INSTALL_PREFIX
设置为自定义的目录,例如build-android下再自定义一个outputConfigure完成后进行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的模版文件。修改其中的compileSdkVersiontargetSdkVersion,同时删掉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即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值