这几天在Android项目中需要加载三维模型,找了多种方法,最后决定使用jpct引擎。话不多说,上代码。

一、代码解析

首先创建一个活动MainActivity,活动布局如下:

包括五个button,一个ImageView作为背景,一个GLSurfaceView显示模型,布局代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/screen"android:layout_width="fill_parent"android:layout_height="fill_parent" ><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorBg"/><android.opengl.GLSurfaceViewandroid:id="@+id/surfaceView"android:layout_width="fill_parent"android:layout_height="fill_parent" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="180dip"android:orientation="vertical"><Buttonandroid:id="@+id/btnLoadModel"android:layout_width="match_parent"android:layout_height="60dip"android:text="loadModel"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="60dip"android:orientation="horizontal"><Buttonandroid:id="@+id/btnLeft"android:layout_width="180dip"android:layout_height="60dip"android:text="left"/><Buttonandroid:id="@+id/btnRight"android:layout_width="180dip"android:layout_height="60dip"android:text="right"/></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="60dip"android:orientation="horizontal"><Buttonandroid:id="@+id/btnTop"android:layout_width="180dip"android:layout_height="60dip"android:text="top"/><Buttonandroid:id="@+id/btnDown"android:layout_width="180dip"android:layout_height="60dip"android:text="down"/></LinearLayout></LinearLayout></RelativeLayout>

新建RenderView.class用于加载模型和显示处理:(如果有Unity或者其他游戏引擎的开发经验的话,下面的代码非常好理解。)

public class RenderView implements GLSurfaceView.Renderer{public World myWorld;private FrameBuffer frameBuffer;private Object3D selectedObj;public RenderView(Context context) {myWorld = new World();myWorld.setAmbientLight(25, 25, 25);Light light = new Light(myWorld);light.setIntensity(250, 250, 250);light.setPosition(new SimpleVector(0, 0, -15));Camera cam = myWorld.getCamera();cam.setFOVLimits(0.1f,2.0f);cam.setFOV(1.08f);cam.setYFOV(1.92f);cam.setClippingPlanes(0f,2000f);System.out.println(cam.getFOV());System.out.println(cam.getYFOV());System.out.println(cam.getPosition());String[] names=Config.getParameterNames();for(String i:names){System.out.println(i);}}public void onSurfaceChanged(GL10 gl, int w, int h) {if (frameBuffer != null) {frameBuffer.dispose();}frameBuffer = new FrameBuffer(gl, w, h);}public void onSurfaceCreated(GL10 gl, EGLConfig config) {gl.glClearColor(1.0f,1.0f,1.0f,0.3f);}public void onDrawFrame(GL10 gl) {frameBuffer.clear(Color.TRANSPARENT);myWorld.renderScene(frameBuffer);myWorld.draw(frameBuffer);frameBuffer.display();}public void addObject(Context context) {Object3D newObject = null;try {createTextures(context);Object3D[] objectsArray2 = Loader.loadOBJ(context.getResources().getAssets().open("policecar.obj"), context.getResources().getAssets().open("policecar.mtl"), 1f);newObject = Object3D.mergeAll(objectsArray2);newObject.setTexture("policecar_texture");newObject.setOrigin(new SimpleVector(0, 0, 300));newObject.rotateZ(3.1415926f);newObject.setName("policecar.obj");} catch (IOException e) {e.printStackTrace();}newObject.strip();newObject.build();Message msg=new Message();msg.what=MainActivity.MSG_LOAD_MODEL_SUC;msg.obj=newObject;MainActivity.handler.sendMessage(msg);selectedObj=newObject;}public void applyTranslation(float incX, float incY, float incZ) {if (this.selectedObj != null) {SimpleVector objOrigin = this.selectedObj.getOrigin();SimpleVector currentPoition=this.selectedObj.getTransformedCenter();System.out.println(currentPoition);this.selectedObj.translate(incX, incY, incZ);}}private void createTextures(Context context) {Bitmap bitmap=BitmapFactory.decodeResource(context.getResources(),R.mipmap.policecar);Texture texture = new Texture(bitmap);if(!TextureManager.getInstance().containsTexture("policecar_texture")){TextureManager.getInstance().addTexture("policecar_texture", texture);}}
}

myWorld是当前的场景,所有的物体都在当前场景中,FrameBuffer是显示缓存,selectedObj是当前选择的物体。下面我们来详细解释这些代码。

public RenderView(Context context) {myWorld = new World();myWorld.setAmbientLight(25, 25, 25);Light light = new Light(myWorld);light.setIntensity(250, 250, 250);light.setPosition(new SimpleVector(0, 0, -15));Camera cam = myWorld.getCamera();cam.setFOVLimits(0.1f,2.0f);cam.setFOV(1.08f);cam.setYFOV(1.92f);cam.setClippingPlanes(0f,2000f);System.out.println(cam.getFOV());System.out.println(cam.getYFOV());System.out.println(cam.getPosition());String[] names=Config.getParameterNames();for(String i:names){System.out.println(i);}}

RenderView是类的 构造函数,定义了场景中的一些关键要素,例如摄像机,光照等。myWorld.setAmbientLight设置全局光,Light是当前场景中的光线设置,light.setIntensity设置光照强度,light.setPosition设置光源位置,此处光源是点光源。cam是场景中的摄像机,cam.setFOVLimits设置摄像机的视场角范围,此处设置为0.1-2.0。摄像机的X和Y方向的视场角可以分别设置。cam.setClippingPlanes设置相机的视距,此处为0-2000。

public void onSurfaceChanged(GL10 gl, int w, int h) {if (frameBuffer != null) {frameBuffer.dispose();}frameBuffer = new FrameBuffer(gl, w, h);}public void onSurfaceCreated(GL10 gl, EGLConfig config) {gl.glClearColor(1.0f,1.0f,1.0f,0.3f);}public void onDrawFrame(GL10 gl) {frameBuffer.clear(Color.TRANSPARENT);myWorld.renderScene(frameBuffer);myWorld.draw(frameBuffer);frameBuffer.display();}

这几个函数是用于定义GLSurfaceView创建时和刷新时的函数,gl.glClearColor定义了SurfaceView刷新颜色。frameBuffer.clear定义了frameBuffer刷新颜色。

public void addObject(Context context) {Object3D newObject = null;try {createTextures(context);Object3D[] objectsArray2 = Loader.loadOBJ(context.getResources().getAssets().open("policecar.obj"), context.getResources().getAssets().open("policecar.mtl"), 1f);newObject = Object3D.mergeAll(objectsArray2);newObject.setTexture("policecar_texture");newObject.setOrigin(new SimpleVector(0, 0, 300));newObject.rotateZ(3.1415926f);newObject.setName("policecar.obj");} catch (IOException e) {e.printStackTrace();}newObject.strip();newObject.build();Message msg=new Message();msg.what=MainActivity.MSG_LOAD_MODEL_SUC;msg.obj=newObject;MainActivity.handler.sendMessage(msg);selectedObj=newObject;}

addObject用于向场景中添加物体,loadOBJ函数采用的是二进制流的形式加载模型数据。加载OBJ格式的模型需要三个文件,分别是模型.obj,模型.mtl以及模型的贴图文件,Obj文件是模型的面信息,mtl文件定义了模型贴图与面位置信息。

public void applyTranslation(float incX, float incY, float incZ) {if (this.selectedObj != null) {SimpleVector objOrigin = this.selectedObj.getOrigin();SimpleVector currentPoition=this.selectedObj.getTransformedCenter();System.out.println(currentPoition);this.selectedObj.translate(incX, incY, incZ);}}

此函数用于模型的位移,其中object.translate()函数定义了模型的位移,translate将会将模型位移到当前世界坐标分别加上函数参数之后的坐标。也就是新的坐标=旧坐标+参数。getTransfromedCenter获取当前物体的当前世界坐标。、

下面解析MainActivity中的代码

public class MainActivity extends AppCompatActivity{public final static int MSG_LOAD_MODEL_SUC=0;private GLSurfaceView myGLView;private RenderView myRenderer;private Button btnLoad;private Button btnLeft;private Button btnRight;private Button btnTop;private Button btnDown;private Thread threadLoadModel;public static Handler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);handler=new Handler(){@Overridepublic void handleMessage(Message msg){switch (msg.what){case MSG_LOAD_MODEL_SUC:Toast.makeText(MainActivity.this, "模型加载成功", Toast.LENGTH_SHORT).show();Object3D object3D=(Object3D) msg.obj;myRenderer.myWorld.addObject(object3D);break;}}};btnLoad=findViewById(R.id.btnLoadModel);btnLeft=findViewById(R.id.btnLeft);btnRight=findViewById(R.id.btnRight);btnTop=findViewById(R.id.btnTop);btnDown=findViewById(R.id.btnDown);btnLoad.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "开始加载模型", Toast.LENGTH_SHORT).show();threadLoadModel.start();}});btnLeft.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myRenderer.applyTranslation(-10,0,0);}});btnRight.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myRenderer.applyTranslation(10,0,0);}});btnTop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myRenderer.applyTranslation(0,-10,0);}});btnDown.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myRenderer.applyTranslation(0,10,0);}});myGLView = (GLSurfaceView) this.findViewById(R.id.surfaceView);myGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);myGLView.getHolder().setFormat(PixelFormat.TRANSLUCENT);myGLView.setZOrderOnTop(true);myRenderer = new RenderView(this);myGLView.setRenderer(myRenderer);threadLoadModel=new Thread(new Runnable() {@Overridepublic void run() {myRenderer.addObject(MainActivity.this);}});}@Overrideprotected void onPause() {super.onPause();myGLView.onPause();}@Overrideprotected void onResume() {super.onResume();myGLView.onResume();}
}

有关View的代码就不多做解析。具体解释一下模型的加载和GLView的设置。

为了使加载模型的过程中程序不堵塞住,开辟一个子线程进行模型解析。模型解析之后,向主线程发送消息,提醒主线程将模型添加到场景中,即myRenderer.myWorld.addObjct()。同时也为了避免模型过大导致加载过程失败导致的程序崩溃。

myGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);myGLView.getHolder().setFormat(PixelFormat.TRANSLUCENT);myGLView.setZOrderOnTop(true);

这段代码将GLSurfaceView的刷新设置为透明并将View设置到所有View的最顶层。

二、jpct的世界坐标系

jpct中的正世界坐标系格式如下,以GlSurfaceView中心为原点,垂直于屏幕向内为z轴正方向,平行于屏幕向右为X轴正方向,向下为Y轴正方向,与Android设备的屏幕xy正方向相一致。

jpct下载地址:http://www.jpct.net/

项目下载地址:https://download.csdn.net/download/njnutzhou/10968296

Android加载三维模型相关推荐

  1. 关于 android 加载 res 图片 out of memory 问题 解决 同样适用于 sd卡图片

    2019独角兽企业重金招聘Python工程师标准>>> 发现android 加载res图片如果过多也会崩溃 android 也是使用 Bitmap  bm = BitmapFacto ...

  2. Android加载大图片OOM异常解决

    Android加载大图片OOM异常解决 参考文章: (1)Android加载大图片OOM异常解决 (2)https://www.cnblogs.com/jevan/archive/2012/07/05 ...

  3. android如何添加gif,Android加载Gif和ImageView的通用解决方案:android-gif-drawable(1)...

     Android加载Gif和ImageView的通用解决方案:android-gif-drawable(1) Android自己的ImageView或者View不能直接加载运行Gif图片,如果要在 ...

  4. Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)【系列1】...

     Android加载/处理超大图片神器!SubsamplingScaleImageView(subsampling-scale-image-view)[系列1] Android在加载或者处理超大巨 ...

  5. android加载html

    今天写了一个小测试  android加载本地的一个html 首先main目录下新建一个assets 在android studio中新建目录时选中foder的assets 把html放入其中 在and ...

  6. Android手机内存图片读取,有效解决Android加载大图片内存溢出的问题

    今天在交流群里,有人问我他经常遇到加载图片时内存溢出的问题,遇到的情况还是在自己的测试机或者手机里没有问题,做好了, 到了客户手机里就内存溢出了.其实有时候不同的手机和不同的系统对内存的要求不一样,尤 ...

  7. Android加载大图片不OutOfMemoryError

    Android加载图片时,对于分辨率小,配置低的机子,很容易发生OutOfMemoryError.手机的内存比图片的大很多,怎么会这样? 在设置Android虚拟机的内存时: RAM:模拟器的内存空间 ...

  8. android 加载外部矢量图SVG

    转自:http://blog.csdn.net/jiabailong/article/details/53736689 android加载矢量图的方式主要有以下两种: 一.Web方式 利用WebVIe ...

  9. World Wind Java开发之十五——加载三维模型(转)

    之前的一篇博客是关于加载粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能加载纹理的问题,一直没呢解决 ...

最新文章

  1. hive in 写法/linux OR CDH如果查看hive的版本
  2. 对话找钢网创始人王东:电竞少年凭什么革了钢贸行业的命?
  3. Nginx + PHP CGI的fix_pathinfo安全漏洞
  4. Python3 字符串切片 slice 操作
  5. 课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 1、两层神经网络的单样本向量化表示与多样本向量化表示...
  6. UOJ #587. 天天和不可描述
  7. 问题:连接查询和子查询的区别和连接及优劣?
  8. 7 centos 时钟跟物理机同步_同步FIFO和异步FIFO
  9. CSS中的类class和标识id选择符(.和#号)
  10. sencha touch 彩色图标按钮(button+ico)
  11. 新型智慧城市建设绘出沈阳“N朵云”
  12. 中国鲷鱼养殖产量和捕捞产分析,养殖产业区域集中度高「图」
  13. 青少年Python编程
  14. IMDb站点起诉加州限制演员年龄信息披露法案的有效性
  15. 欧拉计划 P429 (数论)
  16. 基于Python-OpenCV的图片覆盖技术——即把一个图片P到另一个图片上
  17. JavaWeb开发与代码的编写(一)
  18. 朴素贝叶斯算法新闻文本分类
  19. 颜色rgb设置透明度 16进制常见颜色
  20. 基于android的远程视频监控系统

热门文章

  1. axios跨域携带cookie_axios 跨域处理以及带 cookies 的请求
  2. 亿信华辰成为大数据标准工作组成员单位
  3. Android Studio上Session 'app': Error Installing APK错误解决方案
  4. Java面试宝典,怎样用cmd运行java文件
  5. 石墨文档的云端表格实时压缩策略
  6. Android大厂面试题锦集附答案(BAT TMD JD 小米)
  7. 如何让图片无损放大?可以试试这些方法
  8. 用python画渐变色_用Python画colorbar渐变图+修改刻度大小+修改渐变颜色
  9. 解决Python使用matplotlib绘图时出现的中文标签报错问题
  10. 互联网广告之功能讲解