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

}


代码还是比较简单 。。。


运行结果:





源码下载(包含模型)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值