Android3D编程之导入3dsMd2模型

来源:互联网 发布:算法与数据结构kmpnext 编辑:程序博客网 时间:2024/06/07 02:08

提要

3d模型的导入是游戏开发中比较基础的部分了,这里通过jpct这个游戏引擎来加载的,实现起来比较简单。


jpct简介

jPCT是一款基于OpenGL技术开发的3D图形引擎(PC环境为标准OpenGL,Android为OpenGL ES), 以Java语言为基础的,拥有功能强大的Java 3D解决方案。该引擎与LGame(此为2D游戏引擎)相类似,目前拥有PC(J2SE)以及Android两个开发版本。

jPCT的最大优势之一,就在于它惊人的向下兼容性。在PC环境中,jPCT甚至可以运行在JVM1.1环境之中,因为jPCT内部提供的图形渲染接口完 全符合所有的Java 1.1规范(就连已经消失的Microsoft VM乃至更古老的Netscape 4 VM也不例外)。

最低运行环境要求为Android 1.5。

去官网 - http://www.jpct.net/可以下载到打包好的jar文件,还有自带的两个demo。

使用jPCT之前最好把两个demo都跑一下,还有常去查看jpct的doc http://www.jpct.net/jpct-ae/doc/

模型的加载都是基于HelloWorld来修改的。


主要用到的对象及方法

Object3D

 表示的是3维物体对象,在渲染的时候,需要添加进World对象。一个Object3D只能被一个world加载依次,调用的方法是 World.addObject() 或者继承式的绑定。

其中有一个 animate(float index)  方法用于md2的关键帧动画。index取值在(0,1),0为第一帧。

Loader

Loader类提供了很多用于加载文件的静态方法,用于加载模型,动作,纹理或者文本。主要用的的方法有:

loadMD2 - 加载md2模型;

load3DS - 加载3DS模型;

loadOBJ - 加载obj模型;


代码实现

首先看MainActivity.java

package com.threed.jpct.example;import java.lang.reflect.Field;import javax.microedition.khronos.egl.EGL10;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.egl.EGLDisplay;import javax.microedition.khronos.opengles.GL10;import android.annotation.SuppressLint;import android.app.Activity;import android.opengl.GLSurfaceView;import android.os.Bundle;import android.view.MotionEvent;import com.threed.jpct.Camera;import com.threed.jpct.FrameBuffer;import com.threed.jpct.Light;import com.threed.jpct.Logger;import com.threed.jpct.Object3D;import com.threed.jpct.Primitives;import com.threed.jpct.RGBColor;import com.threed.jpct.SimpleVector;import com.threed.jpct.Texture;import com.threed.jpct.TextureManager;import com.threed.jpct.World;import com.threed.jpct.util.BitmapHelper;import com.threed.jpct.util.MemoryHelper;/** * A simple demo. This shows more how to use jPCT-AE than it shows how to write * a proper application for Android. It includes basic activity management to * handle pause and resume... *  * @author EgonOlsen *  */public class MainActivity extends Activity {// Used to handle pause and resume...private static MainActivity master = null;private GLSurfaceView mGLView;private MyRender render = null;private FrameBuffer fb = null;private World world = null;private RGBColor back = new RGBColor(50, 50, 100);private float touchTurn = 0;private float touchTurnUp = 0;private float xpos = -1;private float ypos = -1;private Object3D cube = null;private int fps = 0;private Light sun = null;@SuppressLint("NewApi") protected void onCreate(Bundle savedInstanceState) {Logger.log("onCreate");if (master != null) {copy(master);}super.onCreate(savedInstanceState);mGLView = new GLSurfaceView(getApplication());mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall// back to Pixelflinger on some device (read: Samsung I7500)int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };EGLConfig[] configs = new EGLConfig[1];int[] result = new int[1];egl.eglChooseConfig(display, attributes, configs, 1, result);return configs[0];}});render = new MyRender(this);mGLView.setRenderer(render);setContentView(mGLView);}@Overrideprotected void onPause() {super.onPause();mGLView.onPause();}@Overrideprotected void onResume() {super.onResume();mGLView.onResume();}@Overrideprotected void onStop() {super.onStop();}private void copy(Object src) {try {Logger.log("Copying data from master Activity!");Field[] fs = src.getClass().getDeclaredFields();for (Field f : fs) {f.setAccessible(true);f.set(this, f.get(src));}} catch (Exception e) {throw new RuntimeException(e);}}public boolean onTouchEvent(MotionEvent me) {if (me.getAction() == MotionEvent.ACTION_DOWN) {xpos = me.getX();ypos = me.getY();return true;}if (me.getAction() == MotionEvent.ACTION_UP) {xpos = -1;ypos = -1;touchTurn = 0;touchTurnUp = 0;render.setTouchTurn(0);render.setTouchTurnUp(0);return true;}if (me.getAction() == MotionEvent.ACTION_MOVE) {float xd = me.getX() - xpos;float yd = me.getY() - ypos;xpos = me.getX();ypos = me.getY();touchTurn = xd / -100f;touchTurnUp = yd / -100f;render.setTouchTurn(touchTurn);render.setTouchTurnUp(touchTurnUp);//System.out.println("Move");return true;}try {Thread.sleep(15);} catch (Exception e) {// No need for this...}return super.onTouchEvent(me);}}

MyRender .java

package com.threed.jpct.example;import java.io.IOException;import java.io.InputStream;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import android.util.Log;import com.threed.jpct.Camera;import com.threed.jpct.FrameBuffer;import com.threed.jpct.Light;import com.threed.jpct.Loader;import com.threed.jpct.Logger;import com.threed.jpct.Matrix;import com.threed.jpct.Object3D;import com.threed.jpct.Primitives;import com.threed.jpct.RGBColor;import com.threed.jpct.SimpleVector;import com.threed.jpct.Texture;import com.threed.jpct.TextureManager;import com.threed.jpct.World;import android.annotation.SuppressLint;import android.content.Context;import com.threed.jpct.util.BitmapHelper;import com.threed.jpct.util.MemoryHelper;@SuppressLint("NewApi") public class MyRender  implements GLSurfaceView.Renderer {private long time = System.nanoTime();  private FrameBuffer fb = null;private Light sun = null;private Object3D cube = null;private World world = null;private int fps = 0;private Object3D rockModel;private Object3D chongLou;private Object3D mdModel;private Context mContext;private float touchTurn = 0;private float touchTurnUp = 0;// 行走动画  private int an = 2;  private float ind = 0;  public MyRender(Context c) {mContext = c;}public void onSurfaceChanged(GL10 gl, int w, int h) {if (fb != null) {fb.dispose();}fb = new FrameBuffer(gl, w, h);GLES20.glViewport(0, 0, w, h);}public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);world = new World();world.setAmbientLight(150, 150, 150);Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(mContext.getResources().getDrawable(R.drawable.rock)), 64, 64));Texture texture2 = new Texture(BitmapHelper.rescale(BitmapHelper.convert(mContext.getResources().getDrawable(R.drawable.texture2)), 64, 64));Texture texture3 = new Texture(BitmapHelper.rescale(BitmapHelper.convert(mContext.getResources().getDrawable(R.drawable.snork)), 64, 64));TextureManager.getInstance().addTexture("texture", texture);TextureManager.getInstance().addTexture("texture2", texture2);TextureManager.getInstance().addTexture("texture3", texture3);cube =Primitives.getCube(10);cube.calcTextureWrapSpherical();cube.setTexture("texture");cube.strip();cube.build(); rockModel = loadModel("rock.3ds", 1);//rockModel.setTexture("texture");rockModel.setTexture("texture");rockModel.strip();rockModel.build(); rockModel.translate(0, 5, 0);chongLou = loadModel("hu.3ds", 1);chongLou.setTexture("texture2");chongLou.strip();chongLou.build(); mdModel = loadMdModel("snork.md2", 0.3f);mdModel.setTexture("texture3");mdModel.strip();mdModel.build(); mdModel.translate(-2, 0, 0); //System.out.println(mdModel.getAnimationSequence().getName(1));world.addObject(rockModel);world.addObject(chongLou);world.addObject(mdModel);sun = new Light(world);sun.setIntensity(250, 250, 250);Camera cam = world.getCamera();cam.moveCamera(Camera.CAMERA_MOVEOUT, 10);cam.lookAt(cube.getTransformedCenter());SimpleVector sv = new SimpleVector();sv.set(cube.getTransformedCenter());sv.y -= 100;sv.z -= 100;sun.setPosition(sv);MemoryHelper.compact();}public void onDrawFrame(GL10 gl) {// Clears the screen and depth buffer.  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.  GL10.GL_DEPTH_BUFFER_BIT); doAnim();  fb.clear(RGBColor.BLACK);world.renderScene(fb);world.draw(fb);fb.display();if (touchTurn != 0) {rockModel.rotateY(touchTurn);chongLou.rotateY(touchTurn);mdModel.rotateY(touchTurn);touchTurn = 0;}if (touchTurnUp != 0) {rockModel.rotateX(touchTurnUp);chongLou.rotateX(touchTurnUp);mdModel.rotateX(touchTurnUp);touchTurnUp = 0;}if (System.nanoTime() - time >= 1000000000) {Logger.log(fps + "fps");Log.d("FPSCounter", "fps: " + fps);  //System.out.println(fps+"fps");fps = 0;time = System.nanoTime() ;}//fps++;}public static int loadShader(int type, String shaderCode){  // create a vertex shader type (GLES20.GL_VERTEX_SHADER)  // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)  int shader = GLES20.glCreateShader(type);  // add the source code to the shader and compile it  GLES20.glShaderSource(shader, shaderCode);  GLES20.glCompileShader(shader);  return shader;  }  public Object3D loadModel(String filename, float scale){InputStream is = null;try {is =mContext.getAssets().open(filename);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}Object3D[] model = Loader.load3DS(is, scale);Object3D o3d = new Object3D(0);Object3D temp = null;for (int i = 0; i < model.length; i++) {temp = model[i];temp.setCenter(SimpleVector.ORIGIN);temp.rotateX((float)( -.5*Math.PI));temp.rotateMesh();temp.setRotationMatrix(new Matrix());o3d = Object3D.mergeObjects(o3d, temp);o3d.build();}return o3d;}public Object3D loadMdModel(String filename, float scale){InputStream is = null;try {is =mContext.getAssets().open(filename);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}Object3D model = Loader.loadMD2(is, scale);  return model;  }public void doAnim() {  //每一帧加0.018f  ind += 0.018f;  if (ind > 1f) {  ind -= 1f;}  mdModel.animate(ind, an); }public void setTouchTurn(float count){touchTurn = count;}public void setTouchTurnUp(float count){touchTurnUp = count;}}


代码还是比较简单 。。。


运行结果:





源码下载(包含模型)

原创粉丝点击