Android3D编程之导入3dsMd2模型
提要
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);
- }
- @Override
- protected void onPause() {
- super.onPause();
- mGLView.onPause();
- }
- @Override
- protected void onResume() {
- super.onResume();
- mGLView.onResume();
- }
- @Override
- protected 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 block
- e.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 block
- e.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;
- }
- }
代码还是比较简单 。。。
运行结果: