提要

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; 	}  } 


代码还是比较简单 。。。


运行结果:

Android3D编程之导入3dsMd2模型_第1张图片


Android3D编程之导入3dsMd2模型_第2张图片


×××(包含模型)