您的位置:首页 > 移动开发 > Android开发

Android3D编程之导入3dsMd2模型

2013-08-10 11:04 351 查看

提要

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

}


代码还是比较简单 。。。

运行结果:





源码下载(包含模型)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: