OpenSceneGraph for Android编译

OpenSceneGraph是一款多平台的3D场景渲染引擎API,以下简称为了OSG,OSG的官网只提供了源码,想使用的话必须自己手动编译。这里以官方的3.6.5版为例讲解如何编译出能在Android平台使用的so包,并成功的运行官方的Demo程序。

官方推荐编译最好在Linux环境下进行,但因为我的Android Studio却是运行在Windows 10下的,所以最好的办法就是给Windows10装了个Linux子系统,进入“程序和功能”>“启用和关闭Windows功能”。然后在拉到底部勾选“适用于Linux的Windows子系统”,等上几分钟后这个功能就装完了。


linux.png

然后在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。


cmake命令完成

然后用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文件了。


ndk_build成功

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);
    }

然后编译一下就可以看到效果了。


运行效果

你可能感兴趣的:(OpenSceneGraph for Android编译)