OpenSceneGraph是一款多平台的3D场景渲染引擎API,以下简称为了OSG,OSG的官网只提供了源码,想使用的话必须自己手动编译。这里以官方的3.6.5版为例讲解如何编译出能在Android平台使用的so包,并成功的运行官方的Demo程序。
官方推荐编译最好在Linux环境下进行,但因为我的Android Studio却是运行在Windows 10下的,所以最好的办法就是给Windows10装了个Linux子系统,进入“程序和功能”>“启用和关闭Windows功能”。然后在拉到底部勾选“适用于Linux的Windows子系统”,等上几分钟后这个功能就装完了。
然后在Windows10的应用市场Microsoft Store里搜索Ubuntu并安装就可以了,这样装出来的Ubuntu是没有图形界面只有字符界面的,但已经能满足编译的需要了。
首次进入Ubuntu时会要求你创建一个用户号,然后对Ubuntu该升级的升级,改安装的安装,主要是把cmake gcc这些程序都要装上。
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install cmake -y
sudo apt install build-essential -y
然后去Github上下载最新的3.6.5的压缩包:https://github.com/openscenegraph/OpenSceneGraph/tree/OpenSceneGraph-3.6.5
然后对压缩包进行解压,为了便于之后将其复制到Ubuntu下使用,我就直接解压到c盘并且把目录命名为了OpenSceneGraph。
由于OSG的编译还需要用到第三方的代码包3rdParty,但可惜的是官网并并不提供下载,需要我们自己到网上去下载,然后将下载的压缩包解压到OpenSceneGraph\3rdParty目录下。
接着我们需要下载Android NDK,可以直接从官网上下载:
https://developer.android.google.cn/ndk/downloads/index.html?hl=zh-cn
下载完毕后依旧是解压到C盘。
OSG和NDK都下载解压完了之后就可以复制到Ubuntu系统上了,这里我推荐用命令方式复制:
sudo cp -r /mnt/c/OpenSceneGraph /home/xrf/
sudo cp -r /mnt/c/android-ndk-r21c /home/xrf/
在OSG365目录下新一个build目录用以存放编译后的文件,并授予全部的权限,如果忘记授权的话可能会因为权限不够而报错。
cd OpenSceneGraph
mkdir build
cd ../..
sudo chmod -R 777 osg365/
接着直接在build目录下开始编译
cmake ../ -DANDROID_NDK=/home/xrf/Android/android-ndk-r21e -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=/home/xrf/Android/android-ndk-r21e/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DCMAKE_CXX_FLAGS="-std=c++11 -frtti -fexceptions -stdlib=libc++ -DUSE_ZLIB" -DANDROID_TOOLCHAIN=clang -DANDROID_PLATFORM=android-19 -DANDROID_ABI=armeabi-v7a -DCMAKE_INSTALL_PREFIX="./armeabi-v7a" -DOPENGL_PROFILE="GLES2" -DDYNAMIC_OPENTHREADS=OFF -DDYNAMIC_OPENSCENEGRAPH=OFF
参数中的DANROID_PLATFORM表示的是Android API最低支持的版本号。
DANDROID_ABI有的是armeabi-v7a,这个是arm的32位版本,如果想要64位的可以换成arm64-v8a。
然后用make命令开始生成静态库文件,这个过程大约要一两个小时,中途会看到一些warning级别的警告,这都不用担心,只要能进行到100%就可以,否则就可能是3rdParty包的某些文件出了问题,建议重新下载出问题的代码文件。
全部完成后记得执行make install命令,这个命令结束后会在build目录下多出一个armeabi-v7a目录,里包含了include、src和obj三个子目录。接着再用系统命令把armeabi-v7a目录复制到Windows的C盘下;
sudo cp -r armeabi-v7a/ /mnt/c/
至此与Ubuntu相关的操作就结束了。概括起来就是我们在Ubuntu下用cmake、make、make install完成了OSG静态库文件的编译。
接着该是Android Studio出场的时候了,首先导入OSG的示例项目osgAndroidExampleG2。这个Demo是以NDK方式创建的,而且配置的路径都是针对Linux环境设置的,所以需要手动修改。
Application.mk内容如下:
#ANDROID APPLICATION MAKEFILE
APP_BUILD_SCRIPT := $(call my-dir)/Android.mk
#APP_PROJECT_PATH := $(call my-dir)
APP_OPTIM := release
APP_PLATFORM := android-19
APP_STL := c++_static
APP_CPPFLAGS := -fexceptions -frtti
APP_ABI := armeabi-v7a
APP_MODULES := osgNativeLib
APP_PLATFORM指定的最低本要和Cmake命令里的DANDROID_PLATFORM一致,然后再修改Android.mk内容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := osgNativeLib
### Main Install dir
OSG_ANDROID_DIR := C:/osg365
NDK_ROOT := C:/Users/你的目录/AppData/Local/Android/Sdk/ndk/21.4.7075529
LIBDIR := $(OSG_ANDROID_DIR)/obj/local/armeabi
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_ARM_NEON := true
LIBDIR := $(OSG_ANDROID_DIR)/obj/local/armeabi-v7a
endif
### Add all source file names to be included in lib separated by a whitespace
LOCAL_C_INCLUDES:= $(OSG_ANDROID_DIR)/include
LOCAL_CFLAGS := -fdata-sections -ffunction-sections -DANDROID
LOCAL_CPPFLAGS := -frtti -fno-exceptions -fdata-sections -ffunction-sections -DANDROID
LOCAL_LDLIBS := -llog -lGLESv2 -lz
LOCAL_SRC_FILES := osgNativeLib.cpp OsgMainApp.cpp OsgAndroidNotifyHandler.cpp
LOCAL_C_INCLUDES += $(NDK_ROOT)/sources/cxx-stl/llvm-libc++/include
LOCAL_C_INCLUDES += $(NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_LDFLAGS := -L $(LIBDIR) \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_dds.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_openflight.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_tga.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_rgb.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_osgterrain.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_osg.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_ive.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgviewer.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgvolume.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgtext.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgterrain.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgsim.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgshadow.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgparticle.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osgfx.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osganimation.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_deprecated_osg.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgvolume.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgtext.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgterrain.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgsim.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgshadow.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgparticle.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgmanipulator.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osgfx.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osganimation.a \
-l$(OSG_ANDROID_DIR)/lib/osgPlugins-3.6.5/libosgdb_serializers_osg.a \
-l$(OSG_ANDROID_DIR)/lib/libosgViewer.a \
-l$(OSG_ANDROID_DIR)/lib/libosgVolume.a \
-l$(OSG_ANDROID_DIR)/lib/libosgTerrain.a \
-l$(OSG_ANDROID_DIR)/lib/libosgText.a \
-l$(OSG_ANDROID_DIR)/lib/libosgShadow.a \
-l$(OSG_ANDROID_DIR)/lib/libosgSim.a \
-l$(OSG_ANDROID_DIR)/lib/libosgParticle.a \
-l$(OSG_ANDROID_DIR)/lib/libosgManipulator.a \
-l$(OSG_ANDROID_DIR)/lib/libosgGA.a \
-l$(OSG_ANDROID_DIR)/lib/libosgFX.a \
-l$(OSG_ANDROID_DIR)/lib/libosgdb.a \
-l$(OSG_ANDROID_DIR)/lib/libosgAnimation.a \
-l$(OSG_ANDROID_DIR)/lib/libosgUtil.a \
-l$(OSG_ANDROID_DIR)/lib/libosg.a \
-l$(OSG_ANDROID_DIR)/lib/libOpenThreads.a
include $(BUILD_SHARED_LIBRARY)
OSG_ANDROID_DIR指的是之前从Ubuntu复制出来的armeabi-v7a目录,为了便于管理而改名成了osg365。
NDK_ROOT指的是Windows版的NDK,注意NDK的版本要和Ubuntu使用的版本一致,不然会出报错。
此外也要注意路径中用的斜杠是“/”。
然后删除AndroidManifest.xml里的uses-sdk节点,因为节点里的内容可以在app模块的build.gradle里配置。
接着就开始配置app的build.gradle文件,并实现Android Studio对C/C++代码的自动提示功能
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.anroid.nativecxx"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
moduleName "osgNativeLib"
abiFilters "armeabi-v7a"
}
}
...
packagingOptions {
pickFirst 'lib/armeabi-v7a/libosgNativeLib.so'
}
sourceSets.main{
jni.srcDirs = []
jniLibs.srcDir "src/main/libs"
}
externalNativeBuild {
ndkBuild {
path file('src/main/jni/Android.mk')
}
}
ndkVersion '21.4.7075529'
}
修改local.properties用于指定ndk的目录,注意把路径改成你的本地路径
ndk.dir=C\:\\Users\\你的目录\\AppData\\Local\\Android\\Sdk\\ndk\\21.4.7075529
sdk.dir=C\:\\Users\\你的目录\\AppData\\Local\\Android\\Sdk
最后记得在Windows的“环境变量”下配置ndk的路径到path下,配完后重启下Android Studio后,选中jni并打开“Terminal”窗口输入ndk-build。一切成功后就可以在src/main/libs下看到生成的so文件了。
so文件被称为动态链接文件,相当于Windows下的dll文件,Java会将so文件作为函数库引入,并将定义为native类型的方法和so内的相关函数链接起来。
为了方便看到编译后的效果,需要从官网下载示例文件,这里有cow.osg为例。先将这个文件用DeviceFileExplorer上传到app的files目录下,再修改代码:
@Override
protected void onResume() {
super.onResume();
mView.onResume();
String address = getFilesDir()+File.separator+"cow.osg";
osgNativeLib.loadObject(address);
}
然后编译一下就可以看到效果了。