OSG for Android新手教程系列(二)——项目配置

  在上一篇教程中,主要介绍了如何把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_1
OSG_ANDROID_DIR := D:/MyTools/osggles1_3_0_1
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    := -fno-short-enums
LOCAL_CPPFLAGS  := -DOSG_LIBRARY_STATIC

LOCAL_LDLIBS := -L $(SYSROOT)/usr/lib -llog
#LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv2
LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv1_CM
LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lz
LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -gnustl_static
LOCAL_LDLIBS += -landroid

LOCAL_SRC_FILES :=osgMain.cpp osgNativeLib.cpp modelUtil.cpp AnimationUtil.cpp ExternVariables.cpp

LOCAL_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-lgdal

include $(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.mk

APP_OPTIM := release

APP_PLATFORM 	:= android-10
APP_STL 	:= gnustl_static
APP_CPPFLAGS 	:= -fexceptions -frtti
APP_ABI 	:= armeabi armeabi-v7a
APP_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的程序。敬请关注。

时间: 2024-12-15 05:44:27

OSG for Android新手教程系列(二)——项目配置的相关文章

Swift新手教程系列5-函数+selector在swift中的使用方法

原创blog.转载请注明出处 近期在用swift写代码,尽管遇到一些问题,可是代码量确实减了不少. swfit新手教程系列会随着我使用swfit中的积累,不断地去修正更新 之前的教程 swift单例模式具体解释-线程安全,多核性能 swift新手教程4-集合(Array,Dictionary) swift新手教程3-字符串String swift新手教程2-运算符 swift新手教程1-准备知识 在swift中,函数有keywordfunc声明 格式 func 函数名(參数1,參数2,...)-

Android 适配器教程(二)

上次我写了一个类似前言的东西,向大家粗略介绍了一下什么是适配器,并且举了一个最简单的例子帮助大家理解,使用了安卓原生的ArrayAdapter,现在我们继续向下学习,同时也继续在我们上次的Demo项目中继续添加例子,一步步的向下深入学习. 这次要讲解的是另外一个常用的安卓原生适配器-SimpleCursorAdapter: 关于SimpleCursorAdapter,sdk的解释是这样的: An easyadapter to map columns from a cursor to TextVi

WPF入门教程系列二——Application介绍

原文:WPF入门教程系列二--Application介绍 一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只有一个 Application 实例存在.和 WinForm 不同的是WPF Application默认由两部分组成 : App.xaml 和 App.xaml.cs,这有点类似于 Asp.Net WebForm,将定义和行为代码相分离. 微

WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProperty)只能拥有一个binding. 这一点可以通过设置binding对象的方法名得知: public static BindingExpressionBase SetBinding( DependencyObject target, DependencyProperty dp, BindingB

Windows server 2012 搭建VPN图文教程(二)配置路由和远程访问服务

Windows server 2012 搭建VPN图文教程(一)安装VPN相关服务 Windows server 2012 搭建VPN图文教程(二)配置路由和远程访问服务 Windows server 2012 搭建VPN图文教程(三)配置VPN访问账户 Windows server 2012 搭建VPN图文教程(四)客户端访问VPN测试 PartII 配置路由和远程访问服务 本部分主要介绍如何安装和配置路由及远程访问服务的方法,请参考以下操作步骤: (续上)前面提到重新启动操作系统,重启后服务

Android Data Binding 系列(二) -- Binding与Observer实现

写在前面 上篇文章 Android Data Binding 系列(一) – 详细介绍与使用 介绍了 Data Binding 的基础及其用法,本文接上篇,结合DataBindingDemo 来学习下 Data Binding 的实现. 绑定实现 Activity在inflate layout时,通过DataBindingUtil来生成绑定,从代码看,是遍历contentView得到View数组对象,然后通过数据绑定library生成对应的Binding类,含Views.变量.listeners

[Android]GreenDao(1)--项目配置

项目配置 grdle配置 在Android Studio的gradle配上 compile 'de.greenrobot:greendao:1.3.7' compile 'de.greenrobot:greendao-generator:1.3.1' 项目配置 注意,src-gen是我们新建一个文件夹,用来放GreenDao生成的文件 未完成该步骤之前,src-gen是空文件夹,我们需要新建一个包,在该包下新建一个Java文件,做初始化工作. 如图所示,我创建了名为'com.usst.chens

Spring Boot从入门到进阶教程系列 -- 集成Freemarker配置

步骤1. 我们可先配置application.properties的Freemarker基本配置,可参考第一篇教程[Spring Boot从入门到进阶教程系列 -- 外部Tomcat多方式启动,加密解密配置数据] 核心配置 ######################################################## ### freemarker ######################################################## spring.fr

Netty4.x中文教程系列(二) Hello World !<转>

在中国程序界.我们都是学着Hello World !慢慢成长起来的.逐渐从一无所知到熟悉精通的. 第二章就从Hello World 开始讲述Netty的中文教程. 首先创建一个Java项目.引入一个Netty 框架的包.这个步骤我在本系列教程的后面就不在重复了. 先上一张我示例的项目工程图给大家看一下: 1.下载并为项目添加Netty框架 Netty的包大家可以从Netty官网:http://netty.io/downloads.html 下载 如图所示: Netty提供了三个主要版本的框架包给