1. 程式人生 > >Android 3D jpct-ae 一個場景小例子

Android 3D jpct-ae 一個場景小例子

         jpct-ae 一個場景小例子,載入了一些3ds模型,並且實現了手指觸控移動,實現了上下左右鍵。但是,此處有兩個3ds模型在最終的畫面裡面沒有顯示,程式也沒有報錯,不知道是為什麼,這一點讓我很納悶。

注意:1,Loader.load3DS返回的是Object3D[],是一個數組,一般選擇陣列的第一項。

    2,jpct-ae 裡面rotate()預設的是逆時針方向旋轉,若要順時針方向旋轉,則rotate(負數);

程式碼:

package com.je;
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 com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
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.MemoryHelper;

import android.app.Activity;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;
  
public class JpctExampleActivity extends Activity {
	//JpctAdvancedExampleActivity物件用來處理activity的onPause和onResume
	public static JpctExampleActivity master=null;
	
	private GLSurfaceView mGLView;
	private MRenderer mRenderer=null;

	private float touchTurn = 0;
	private float touchTurnUp = 0;

	private float xpos = -1;
	private float ypos = -1;
	
	private int move=0;
	private float turn=0;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		// 如果本類物件不為NULL,將從Object中所有屬性裝入該類
		if(master!=null)
			copy(master);
		super.onCreate(savedInstanceState);
		mGLView=new GLSurfaceView(getApplication());
		// 使用自己實現的 EGLConfigChooser,該實現必須在setRenderer(renderer)之前
		// 如果沒有setEGLConfigChooser方法被呼叫,則預設情況下,
		//   檢視將選擇一個與當前android.view.Surface相容至少16位深度緩衝深度EGLConfig。
		mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
			
			@Override
			public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
				// TODO Auto-generated method stub
				int[] att=new int[]{EGL10.EGL_DEPTH_SIZE,16,EGL10.EGL_NONE};
				EGLConfig[] config=new EGLConfig[1];
				int[] result = new int[1];
				egl.eglChooseConfig(display, att, config, 1, result);
				return config[0];
			}
		});
	
		mRenderer=new MRenderer();
		mGLView.setRenderer(mRenderer);
		setContentView(mGLView);
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		mGLView.onPause();
	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		mGLView.onResume();
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
	}
	
	
	//實現手勢觸控移動
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		//按下手指
		if(event.getAction()==MotionEvent.ACTION_DOWN){
			xpos=event.getX();
			ypos=event.getY();
			return true;
		}
		//擡起手指
		if (event.getAction() == MotionEvent.ACTION_UP) {
			xpos = -1;
			ypos = -1;
			touchTurn = 0;
			touchTurnUp = 0;
			return true;
		}
		//移動
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			float xd = event.getX() - xpos;
			float yd = event.getY() - ypos;

			xpos = event.getX();
			ypos = event.getY();

			touchTurn = xd / 100f;
			touchTurnUp = yd / 100f;
			return true;
		}

		try {
			Thread.sleep(15);
		} catch (Exception e) {
			
		}

		return super.onTouchEvent(event);
	}
	
	//實現上下左右鍵
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
			move=2;
			return  true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
			move = -2;
			return true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
			turn = 0.05f;
			return true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
			turn = -0.05f;
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		// TODO Auto-generated method stub
		if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
			move = 0;
			return true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
			move = 0;
			return true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
			turn = 0;
			return true;
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
			turn = 0;
			return true;
		}
		return super.onKeyUp(keyCode, event);
	}

	private void copy(Object src) {
	        try {
	            // 列印日誌
	            Logger.log("Copying data from master Activity!");
	            // 返回一個數組,其中包含目前這個類的的所有欄位的Filed物件
	            Field[] fs = src.getClass().getDeclaredFields();
	            // 遍歷fs陣列
	            for (Field f : fs) {
	                // 嘗試設定無障礙標誌的值。標誌設定為false將使訪問檢查,設定為true,將其禁用。
	                f.setAccessible(true);
	                // 將取到的值全部裝入當前類中
	                f.set(this, f.get(src));
	            }
	        } catch (Exception e) {
	            // 丟擲執行時異常
	            throw new RuntimeException(e);
	        }
	    }
	

	class MRenderer implements GLSurfaceView.Renderer {
		
		private FrameBuffer fb=null;
		private World world=null;
		private RGBColor back=new RGBColor(100,100,100);
		private Object3D plane=null;//平面
		private Object3D tree1=null;//樹
		private Object3D tree2=null;
		private Object3D rock=null;//石頭
		private Object3D grass=null;//草
		private Object3D cube=null;//長方體
		private Object3D house=null;//房子
		private Object3D head=null;//一個骷髏頭
		private Light light=null;
		
		private long time=System.currentTimeMillis();//返回的是以毫秒為單位的當前時間
		private SimpleVector lightRot=new SimpleVector(-100,-100f,100);
		
		public MRenderer(){
			//此程式碼在下一個例子中會解釋
			Config.maxPolysVisible = 500;
			Config.farPlane = 1500;
			Config.glTransparencyMul = 0.1f;
			Config.glTransparencyOffset = 0.1f;
			Texture.defaultToMipmapping(true);
			Texture.defaultTo4bpp(true);
		}
		
		@Override
		public void onDrawFrame(GL10 gl) {
			// TODO Auto-generated method stub
			try {
				if (true) {
					Camera cam = world.getCamera();
					if (turn != 0) {
						world.getCamera().rotateY(-turn);
					}

					if (touchTurn != 0) {
						world.getCamera().rotateY(touchTurn);
						touchTurn = 0;
					}

					if (touchTurnUp != 0) {
						world.getCamera().rotateX(touchTurnUp);
						touchTurnUp = 0;
					}

					if (move != 0) {
						world.getCamera().moveCamera(cam.getDirection(), move);
					}

					fb.clear(back);
					world.renderScene(fb);//轉換燈光和所有的多邊形
					world.draw(fb);
					fb.display();//顯示

					if (light != null) {
						light.rotate(lightRot, plane.getTransformedCenter());
					}
				} else {
					if (fb != null) {
						fb.dispose();
						fb = null;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				Logger.log("Drawing thread terminated!", Logger.MESSAGE);
			}
		}

		@Override
		public void onSurfaceChanged(GL10 gl, int width, int height) {
			// TODO Auto-generated method stub
			if(fb!=null)
				fb.dispose();//清理緩衝器
			fb=new FrameBuffer(gl,width,height);
			
		}

		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
			// TODO Auto-generated method stub
			if(JpctExampleActivity.master==null){
				world=new World();
				Resources res = getResources();
				//取得材質管理器
				TextureManager tm=TextureManager.getInstance();
				//取得紋理
				Texture grass2 = new Texture(res.openRawResource(R.raw.grassy));
				Texture leaves = new Texture(res.openRawResource(R.raw.tree2y));
				Texture leaves2 = new Texture(res.openRawResource(R.raw.tree3y));
				Texture rocky = new Texture(res.openRawResource(R.raw.rocky));
				Texture planetex = new Texture(res.openRawResource(R.raw.planetex));	
				Texture housey2 = new Texture(res.openRawResource(R.raw.photo));
				Texture heady=new Texture(res.openRawResource(R.raw.photo));
				//將紋理新增到材質管理器裡面
				tm.addTexture("grass2", grass2);
				tm.addTexture("leaves", leaves);
				tm.addTexture("leaves2", leaves2);
				tm.addTexture("rock", rocky);
				tm.addTexture("grassy", planetex);
				tm.addTexture("housey2",housey2);
				tm.addTexture("heady",heady);
				//構造平面,該出用的是經過處理的資料
				plane = Loader.loadSerializedObject(res.openRawResource(R.raw.serplane));
				//載入岩石,樹,草,房子,骷髏頭的3ds模型
				//檢視API文件可知,Loader.load3DS返回的是Object3D[],是一個數組,這裡選擇陣列的第一項
				//陣列第一項就是我們需要的模型,所以寫為Loader.load3DS(  )[0];
				rock=Loader.load3DS(res.openRawResource(R.raw.rock), 30f)[0];
				tree1=Loader.load3DS(res.openRawResource(R.raw.tree2), 5f)[0];
				tree2=Loader.load3DS(res.openRawResource(R.raw.tree3), 5f)[0];
				grass=Loader.load3DS(res.openRawResource(R.raw.grass), 2f)[0];
				cube=Loader.load3DS(res.openRawResource(R.raw.cube), 1f)[0];
				//?????????? 在這裡有些問題,house和head這兩個3ds模型載入不進去?????????
				house=Loader.load3DS(res.openRawResource(R.raw.house1), 1f)[0];
				head=Loader.load3DS(res.openRawResource(R.raw.head), 1f)[0];
				//上面的house和head兩個模型在最終的畫面裡面看不到,沒有出現,筆者也不知道是為什麼??????????????
				
				grass.translate(-45, -17, -50);//平移
				grass.rotateZ((float) Math.PI);
				rock.translate(0, 0, -90);
				//繞X軸旋轉90度,注意:rotateX()預設的是逆時針方向旋轉
				rock.rotateX(-(float) Math.PI / 2);
				tree1.translate(-50, -100, -50);
				tree1.rotateZ((float) Math.PI);
				tree2.translate(60, -95, -10);
				tree2.rotateZ((float) Math.PI);
				plane.rotateX((float) Math.PI / 2f);
				cube.translate(-80, 0, -110);
				cube.rotateX((float)Math.PI/2f);
				head.translate(-45, -17, -50);
				head.rotateZ((float) Math.PI);
				house.translate(-70, 0, -110);
				house.rotateX((float)Math.PI/2f);
				//下面的可要可不要
				house.setName("house");
				plane.setName("plane");
				tree1.setName("tree1");
				tree2.setName("tree2");
				grass.setName("grass");
				rock.setName("rock");
				//設定紋理方式
				house.calcTextureWrapSpherical();
				head.calcTextureWrapSpherical();
				cube.calcTextureWrapSpherical();
				//設定紋理
				house.setTexture("housey2");
				head.setTexture("heady");
				cube.setTexture("housey2");
				tree1.setTexture("leaves");
				tree2.setTexture("leaves2");
				rock.setTexture("rock");
				grass.setTexture("grass2");
				
				//加入到world裡面
				world.addObject(plane);
				world.addObject(tree1);
				world.addObject(tree2);
				world.addObject(grass);
				world.addObject(rock);
				world.addObject(house);
				world.addObject(head);
				world.addObject(cube);
				//釋放記憶體
				plane.strip();
				tree1.strip();
				tree2.strip();
				grass.strip();
				rock.strip();
				house.strip();
				head.strip();
				cube.strip();
				
				world.setAmbientLight(250, 250, 250);//設定光環境光
				world.buildAllObjects();//Calls build() for every object in the world.
				
				light = new Light(world);//設定光照
				light.setIntensity(250, 250, 0);//設定光顏色

				Camera cam = world.getCamera();
				cam.moveCamera(Camera.CAMERA_MOVEOUT, 250);
				cam.moveCamera(Camera.CAMERA_MOVEUP, 100);
				//相機的在plane的中心
				cam.lookAt(plane.getTransformedCenter());

				SimpleVector sv = new SimpleVector();
				sv.set(plane.getTransformedCenter());
				Log.e("X:", plane.getTransformedCenter().toString());
				sv.y -= 500;
				sv.x -= 300;
				sv.z += 200;
				//設定光照的位置,此處的sv為plane的中心
				light.setPosition(sv);
				//釋放記憶體
				MemoryHelper.compact();
				if (master == null) {
					Logger.log("Saving master Activity!");
					master = JpctExampleActivity.this;
				}
			}
		}
	}
}