在上一篇教程中,主要介绍了如何把OSG源代码编译成为能够在Android项目下使用的函数库。在这一篇教程中,我将针对如何在自己的Android项目中配置OSG函数库进行详细讲解。

  现阶段网上关于OSGfor Android的配置方式教程有很多,但是大部分在实际使用起来都会或多或少的出现一些问题,无法完全照搬,需要一定的修改。而且,对于配置中的那些变量的具体含义,也很少有人能够进行仔细的讲解。这非常不利于新手的学习和理解,往往会造成出现bug后面对满屏幕的错误log完全一脸茫然的情况。

  所以我将在这篇教程中详细介绍系统的介绍如何在Android项目中配置OSG函数库,并对各个配置变量的含义进行详细讲解。

-------------------------------------------------------------------------------------------------

  在一个项目中配置函数库,是我们在进行项目开发时几乎都要做的第一件事情。可以说,各种第三方函数库帮助我们完成了很多通用的常用的功能,使我们从繁杂的基本算法、基本功能中脱离出来,能够更专心的完成我们需要实现的业务功能。OSG就是一个非常好的开源三维引擎,提供了一套成熟的API用于实现三维场景功能的开发。


一、工具准备

  OSG是基于C++平台的API,在开发时使用的都是标准的C++。众所周知,开发Android项目,我们平常使用的都是Java,那么,如何才能在Java语言中调用OSG的这些C++函数呢?Java中提供了Java本地接口,即JNI(Java Native Interface)。JNI是一个协议,用于沟通Java代码和本地的C/C++代码。而Google公司为Android开发了一套用于快速创建native工程的工具集合,即NDK(Native Development Kit)。在本文中,将使用Eclipese+NDK的方式进行配置开发。网上有许多的经验教程用到了Cygwin。但是,从NDK的r7版本以上就包含了Cygwin,所以本文在配置项目时,并没有单独使用Cygwin。

  这里使用的NDK版本是r10d,可以在官方网站上下载,链接为:

  http://developer.android.com/tools/sdk/ndk/index.html

  当然,由于一些原因,现在很多情况下是连接不上这个网站的,比如我就是。不过现在很多网盘上有共享的可以下载,大家可以自行搜一下。OSG函数库可以根据我前一篇教程里讲的那样自己进行编译,不过时间花费比较大,当然也可以从网上下载别人已经编译好的OSG函数库,这样省时省力。这里我使用的是3.0.1版本的OSG。需要注意的是,上一篇教程讲过,在编译时根据参数不同,会有两个版本的OSG库,分别是GLES1和GLES2,这两个版本在使用时,配置的参数会有所不同,甚至会对新手来说产生一些莫名其妙的错误。具体的区别,我会详细的说明一下。


二、具体配置

  首先,为了在项目中使用C/C++,在项目结构上会有一点不同,需要增加一个jni文件夹,其位置在项目的根目录下,与src等文件夹在同一层。这个文件夹用于存放所有的C/C++文件,以及项目配置文件(.mk后缀)。下面进行详细讲解。


  1. 配置文件

  在OSG for Android项目中,配置文件有两个,一个是Android.mk,另一个是Application.mk。这两个文件都是存放在jni文件夹内的,用于在编译项目时提供配置信息。

  首先,我们来看Android.mk文件的配置方式。

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := osgNativeLib#OSG_ANDROID_DIR := D:/MyTools/osggles2_3_0_1OSG_ANDROID_DIR := D:/MyTools/osggles1_3_0_1LIBDIR := $(OSG_ANDROID_DIR)/obj/local/armeabiifeq ($(TARGET_ARCH_ABI),armeabi-v7a)    LOCAL_ARM_NEON  := true    LIBDIR          := $(OSG_ANDROID_DIR)/obj/local/armeabi-v7aendif### Add all source file names to be included in lib separated by a whitespaceLOCAL_C_INCLUDES:= $(OSG_ANDROID_DIR)/includeLOCAL_CFLAGS    := -fno-short-enumsLOCAL_CPPFLAGS  := -DOSG_LIBRARY_STATICLOCAL_LDLIBS := -L $(SYSROOT)/usr/lib -llog#LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv2LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv1_CMLOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lzLOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -gnustl_staticLOCAL_LDLIBS += -landroidLOCAL_SRC_FILES :=osgMain.cpp osgNativeLib.cpp modelUtil.cpp AnimationUtil.cpp ExternVariables.cppLOCAL_LDFLAGS   := -L $(LIBDIR) -losgdb_dds\-losgdb_openflight\-losgdb_tga\-losgdb_rgb\-losgdb_osgterrain\-losgdb_osg\-losgdb_ive\-losgdb_deprecated_osgviewer\-losgdb_deprecated_osgvolume\-losgdb_deprecated_osgtext\-losgdb_deprecated_osgterrain\-losgdb_deprecated_osgsim\-losgdb_deprecated_osgshadow\-losgdb_deprecated_osgparticle\-losgdb_deprecated_osgfx\-losgdb_deprecated_osganimation\-losgdb_deprecated_osg\-losgdb_serializers_osgvolume\-losgdb_serializers_osgtext\-losgdb_serializers_osgterrain\-losgdb_serializers_osgsim\-losgdb_serializers_osgshadow\-losgdb_serializers_osgparticle\-losgdb_serializers_osgmanipulator\-losgdb_serializers_osgfx\-losgdb_serializers_osganimation\-losgdb_serializers_osg\-losgViewer\-losgVolume\-losgTerrain\-losgText\-losgShadow\-losgSim\-losgParticle\-losgManipulator\-losgGA\-losgFX\-losgDB\-losgAnimation\-losgUtil\-losg\-lOpenThreads\-lgnustl_static\-lgdalinclude $(BUILD_SHARED_LIBRARY)#include $(BUILD_STATIC_LIBRARY)

  下面对各个配置变量进行详细讲解。

  LOCAL_PATH:这个变量用于在项目结构树中查找源文件。在这个例子中,对其配置为$(call my-dir),这是一个宏函数,由编译系统提供,表示返回当前路径,也就是包含了这个Android.mk文件的路径;

  include $(CLEAR_VARS):这句配置的意思是清空之前的除了LOCAL_PATH以外的所有LOCAL_XXX的变量配置。可以看出,我们所需要配置的变量都必须在这条配置语句之后进行,不然即使配置了,也会被这句给清空掉;

  LOCAL_MODULE:这个变量表示的是该配置文件描述的模块的名称,这个名称是唯一的。而且这个配置变量必须配置。在编译过程中,编译系统根据这个变量自动生成库动态库的名称,一般情况下,生成的动态库会以libxxx.so为名,其中的xxx就是LOCAL_MODULE变量配置时的名称;

  OSG_ANDROID_DIR:这个配置变量表示的是OSG的所在位置,即经过编译的OSG的位置。在这个例子中,我写了两个路径,其中一个是被#注释掉的。之前也我提到过,OSG for Android在编译时根据参数不同,会产生两个版本,分别是GLES1和GLES2,这两个版本的OSG在配置时是不同的,这里就是不同点之一;

  LIBDIR:这个配置变量是指向OSG函数库的位置,根据OSG_ANDROID_DIR所指向的OSG位置,向下寻找静态库的位置。其实,如果我们打开这个文件夹,我们可以发现一系列后缀为.a的文件,这些文件就是OSG的静态库。接下来的四行代码,则是用于判断目标ABI(即应用程序二进制接口),根据判断结果重新配置静态库位置;

  LOCAL_C_INCLUDES:这个变量指向相应版本OSG的include文件夹,用于指定OSG头文件位置;

  LOCAL_CFLAGS:这个变量是一个可选设置的变量,用于附加编译选项。在编写配置文件时,可以照搬此处的设置,无需修改;

  LOCAL_CPPFLAGS:与上一个变量类似,区别是这个变量用于对cpp文件编译进行设置,从字面意思就可以看出,同上,可照搬。

  LOCAL_LDLIBS:用于添加系统。注意!在配置这个变量时,其中存在对GLES1和GLES2两个版本配置的不同,这是第二个不同的地方。尤其需要注意的是,在选择使用GLES1版本的OSG时,该变量配置的是-lGLESv1_CM,而不是想当然的-lGLESv1!新手在刚接触时,很容易犯这个错,而且很难察觉到。其余照搬即可。

  LOCAL_SRC_FILES:在这里列出需要编译进动态库的c和cpp文件。只要用到的c或cpp文件都要加进来,编译系统会根据这个变量的值来寻找文件,如果不加进来,编译系统就找不到相应的文件,就会造成编译错误。

  LOCAL_LDFLAGS:这个配置变量与LOCAL_LDLIBS变量功能类似,也是用于添加系统库的功能。

  include $(BUILD_SHARED_LIBRARY):这句代码的意思是将该模块定义为动态库,即.so文件。该例子中最后还有一句被#注释掉的include $(BUILD_STATIC_LIBRARY),这是指定该模块生成静态库,即.a文件。

  

  下面我们再来看一下另一个配置文件,即Application.mk文件的配置方法。

APP_BUILD_SCRIPT := $(call my-dir)/Android.mkAPP_OPTIM := releaseAPP_PLATFORM := android-10APP_STL := gnustl_staticAPP_CPPFLAGS := -fexceptions -frttiAPP_ABI := armeabi armeabi-v7aAPP_MODULES     := osgNativeLib

  下面对各个变量进行详细讲解。

  APP_BUILD_SCRIPT:这个变量将在当前路径下寻找Android.mk,也就是之前我们进行配置的mk文件;

  APP_OPTIM:这是个可选变量,其值可以设置为release或者debug。当设置为release时,将会生成高度优化的二进制代码,而设置为debug时,生成的是未优化的二进制代码,但可以检测出很多的BUG,可以用于调试;

  APP_PLATFORM:这个变量用于设置该项目的最小运行平台,需要注意的是,网上有很多教程,在这里设置的是android-8,但是根据我的测试,如果设置为android-8,会出现一些找不到文件的错误,但是设置为android-10以上,则可以正常编译;

  APP_STL:这个变量设置为gnustl_static,表示使用GNU libstlc++作为静态库;

  APP_CPPFLAGS:这个变量用于设置一个c++编译器开关集合,在编译任意模块的任意C或C++源代码时传递。它可以用于改变一个给定的应用程序需要依赖的模块的构建,而不是修改它自身的Android.mk文件;

  APP_ABI:用于设置二进制程序接口,默认情况下为armeabi,本文中的例子同时设置了armeabi和armeabi-v7a。注意!网上有的例子里面在这里同时设置了x86,根据我的测试,加上x86后会产生NDK的Abortting stop的错误,所以,不要添加-x86

  APP_MODULES:这个变量列出编译所需要的模块名称。模块名称就是我们之前在Android.mk文件中设置的LOCAL_MODULE的值。


  2. NDK Builder的配置

  在eclipse左边的project view里右击需要设置的项目,并选择Properties,如图所示:


  进入后在界面左侧选择Builder,然后点击界面邮编的New按钮,如图所示:


  在Choose configuration type的界面中选择Program,点击OK。如图所示:


  在出现的设置界面中,在Main选项卡内,Location设置为所用的NDK的安装目录下的nkd-build.cmd;Working directory设置为当前工程。在Refresh选项卡内,勾选上Refresh resources upon completion。在Build Options选项卡中,勾选Specify working set of relevent resouces,同时点击Specify Resouces按钮,选择当前工程的jni文件夹。







  3. Java中的配置

  在Java中的配置比较简单,但是也是容易遗忘的地方。因为在Android上显示OSG窗口是基于GLSurfaceView的,那么在创建GLSurfaceView时需要注意的是,应该根据自己使用的OSG版本对GLSurfaceView的GL版本。这个配置只需要一句代码:

myGLSurfaceView.setEGLContextClientVersion(1);
   因为我的例子中使用的是GLES1版本的OSG库,所以这里的值设置为1;同理,如果使用的是GLES2版本的OSG库,则将其设置为2。这里是比较容易遗忘的地方。



三、总结

  据我了解,很多刚接触OSG for Android的新手老手,在配置项目时都会遇到这样或那样的问题,我在刚接触时同样是这样。出问题的大部分都是对这个配置的内容不是很了解其中的意思,所以会在出了问题后不知道该怎么办。我总结了一下容易出错的地方。

  1. 乱加或乱减空格

  在mk文件中,对空格似乎十分的敏感。我们很多人有意无意的会习惯性打空格,特别是在一行代码的末尾处,很容易多一个空格。但是这种情况在mk文件中都有可能引起错误。我在刚接触时,就试过逐行逐行地查看空格是否有多余或遗漏;

  2. 在使用GLES1版本的库时,-lGLESv1_CM的错误

  也许在看到一些使用GLES2版本的例子上写着-lGLES2时,会想当然的认为,使用GLES1版本就直接设置为-lGLES1就行了。结果编译时就会发现出错了。而且错误并没有直接指向这里,而是会出现一些找不到OSG头文件的错误,会让人很摸不着头脑。其实这种错误很大可能就是出现在了这里。

  3. -x86的错误

  我也看到过一些教程上面提到过,NDK在对x86的兼容上有一些问题,但是仍然有不少示例会加上-x86。这里我的建议是不要在Application.mk文件的APP_ABI后面添加-x86。


---------------------------------------------------------

  OSG for Android新手教程的下一篇将对一个HelloWorld的示例进行详细讲解,通过一个简单的示例分析怎样运行起一个最简单的OSG for Android的程序。敬请关注。


更多相关文章

  1. Android:源码环境编译自定义的APP到ROM(System Image)中
  2. [置顶] Ionic项目打包Android版本实战
  3. Android(安卓)NDK开发简介
  4. [Android(安卓)Studio系列(三)]Android(安卓)Studio 编译、同步
  5. Android(安卓)Apk反编译和代码混淆(第二篇代码混淆)
  6. Android(安卓)Studio 导入 so 简明教程:通过一个示例让你理解整个
  7. Android(安卓)STB 编译自定义jar
  8. Android(安卓)热修复 关于接入Tinker所遇到的错误
  9. Android应用程序访问linux驱动第四步:实现android应用程序

随机推荐

  1. Android文件下载功能实现代码
  2. android实现携程购票起始点位置交换
  3. Android(Java):minSdkVersion、targetSdk
  4. android横向翻页滚动菜单
  5. Android面试题整理(1)
  6. android 自定义 3D View
  7. 使用原始的HTTP拼凑请求的方式上传多张图
  8. Android硬编解码MediaCodec使用笔记
  9. android Fragment 源码分析
  10. achartengine与Android中ScrollView的冲