【Android應用開發】-(11)使用JPCT-AE 3D框架實現旋轉的立方體(附效果圖及源碼)

本文采用http://www.eoeandroid.com/thread-114268-1-1.html的代碼 使用JPCT-AE 3D框架,實現一個立方體,代碼中有具體的說明。

一、效果圖:


二、下載地址:http://download.csdn.net/detail/tangcheng_ok/4374199

三、源碼:

package org.winplus.hw;

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

/**
 * 
 * 一個簡單的例子。比起展示如何寫一個正確的android應用它更着重於展示如何使用JPCT-AE這個3D遊戲框架。
 * 它包含了Activity類去處理pause和resume等方法
 * 
 * @author tangcheng_ok
 * 
 */
public class JPCT_AE_Activity extends Activity {
	// HelloWorld對象用來處理Activity的onPause和onResume方法
	private static JPCT_AE_Activity master = null;
	// GLSurfaceView對象
	private GLSurfaceView mGLView;
	// 類MyRenderer對象
	private MyRenderer renderer = null;
	// 當JPCT渲染背景時FrameBuffer類提供了一個緩衝,它的結果本質上是一個能顯示或者修改甚至能進行更多後處理的圖片。
	private FrameBuffer fb = null;
	// World類是JPCT時最重要的一個類,它好像膠水一樣把事物"粘"起來。它包含的對象和光線定義了JPCT的場景
	private World world = null;
	// 類似java.awt.*中的Color類
	private RGBColor back = new RGBColor(50, 50, 100);
	private float touchTurn = 0;
	private float touchTurnUp = 0;
	private float xpos = -1;
	private float ypos = -1;
	/*
	 * Object3D類是一個三維對象,千萬不要傻呼呼的認爲它與java.lang.Object類似。
	 * 一個Object3D對象作爲一個實例被添加到在渲染的World對象中。Object3D在World中一次添加一個實例
	 * ,他們可能被聯繫起作爲孩子/父母來在他們中建立一個制度.
	 * 人體模型當然也能應用在以上的規則中。他們常常不加到一個World實例中,而是綁定到其它對象中(人體模型或非人體模型)。有些方法
	 * 在這個類中需要一個實例添加到一個World實例中(用World.addObject()方法可以實現)。
	 */
	private Object3D cube = null;
	// 每秒幀數
	private int fps = 0;
	// 光照類
	private Light sun = null;

	protected void onCreate(Bundle savedInstanceState) {
		// Logger類中 jPCT中一個普通的用於打印和存儲消息,錯誤和警告的日誌類。 每一個JPCT生成的消息將被加入到這個類的隊列中
		Logger.log("onCreate");
		// 如果本類對象不爲NULL,將從Object中所有屬性裝入該類
		if (master != null) {
			copy(master);
		}
		super.onCreate(savedInstanceState);
		// 實例化GLSurfaceView
		mGLView = new GLSurfaceView(this);
		// 使用自己實現的 EGLConfigChooser,該實現必須在setRenderer(renderer)之前
		// 如果沒有setEGLConfigChooser方法被調用,則默認情況下,視圖將選擇一個與當前android.view.Surface兼容至少16位深度緩衝深度EGLConfig。
		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];
			}
		});
		// 實例化MyRenderer
		renderer = new MyRenderer();
		// 設置View的渲染器,同時啓動線程調用渲染,以至啓動渲染
		mGLView.setRenderer(renderer);
		// 設置一個明確的視圖
		setContentView(mGLView);
	}

	// 重寫onPause()
	@Override
	protected void onPause() {
		super.onPause();
		mGLView.onPause();
	}

	// 重寫onResume()
	@Override
	protected void onResume() {
		super.onResume();
		mGLView.onResume();
	}

	// 重寫onStop()
	@Override
	protected void onStop() {
		super.onStop();
	}

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

	public boolean onTouchEvent(MotionEvent me) {
		// 按鍵開始
		if (me.getAction() == MotionEvent.ACTION_DOWN) {
			// 保存按下的初始x,y位置於xpos,ypos中
			xpos = me.getX();
			ypos = me.getY();
			return true;
		}
		// 按鍵結束
		if (me.getAction() == MotionEvent.ACTION_UP) {
			// 設置x,y及旋轉角度爲初始值
			xpos = -1;
			ypos = -1;
			touchTurn = 0;
			touchTurnUp = 0;
			return true;
		}
		if (me.getAction() == MotionEvent.ACTION_MOVE) {
			// 計算x,y偏移位置及x,y軸上的旋轉角度
			float xd = me.getX() - xpos;
			float yd = me.getY() - ypos;
			// Logger.log("me.getX() - xpos----------->>"
			// + (me.getX() - xpos));
			xpos = me.getX();
			ypos = me.getY();
			Logger.log("xpos------------>>" + xpos);
			// Logger.log("ypos------------>>" + ypos);
			// 以x軸爲例,鼠標從左向右拉爲正,從右向左拉爲負
			touchTurn = xd / -100f;
			touchTurnUp = yd / -100f;
			Logger.log("touchTurn------------>>" + touchTurn);
			// Logger.log("touchTurnUp------------>>" + touchTurnUp);
			return true;
		}
		// 每Move一下休眠毫秒
		try {
			Thread.sleep(15);
		} catch (Exception e) {
			// No need for this...
		}
		return super.onTouchEvent(me);
	}

	// MyRenderer類實現GLSurfaceView.Renderer接口
	class MyRenderer implements GLSurfaceView.Renderer {
		// 當前系統的毫秒數
		private long time = System.currentTimeMillis();
		// 是否停止
		private boolean stop = false;

		// 停止
		public void stop() {
			stop = true;
		}

		// 當屏幕改變時
		public void onSurfaceChanged(GL10 gl, int w, int h) {
			// 如果FrameBuffer不爲NULL,釋放fb所佔資源
			if (fb != null) {
				fb.dispose();
			}
			// 創建一個寬度爲w,高爲h的FrameBuffer
			fb = new FrameBuffer(gl, w, h);
			Logger.log(master + "");
			// 如果master爲空
			if (master == null) {
				// 實例化World對象
				world = new World();
				// 設置了環境光源強度。設置此值是負的整個場景會變暗,而爲正將照亮了一切。
				world.setAmbientLight(20, 20, 20);
				// 在World中創建一個新的光源
				sun = new Light(world);
				// 設置光照強度
				sun.setIntensity(250, 250, 250);
				// 創建一個紋理
				// 構造方法Texture(Bitmap image)
				// static Bitmap rescale(Bitmap bitmap, int width, int height)
				// static Bitmap convert(Drawable drawable)
				Texture texture = new Texture(BitmapHelper.rescale(
						BitmapHelper.convert(getResources().getDrawable(
								R.drawable.i1)), 64, 64));
				// TextureManager.getInstance()取得一個Texturemanager對象
				// addTexture("texture",texture)添加一個紋理
				TextureManager.getInstance().addTexture("texture", texture);
				// Object3D對象開始了:-)
				// Primitives提供了一些基本的三維物體,假如你爲了測試而生成一些對象或爲
				// 其它目的使用這些類將很明智,因爲它即快速又簡單,不需要載入和編輯。
				// 調用public static Object3D getCube(float scale) scale:角度
				// 返回一個立方體
				cube = Primitives.getCube(10);
				// 以紋理的方式給對象所有面"包裝"上紋理
				cube.calcTextureWrapSpherical();
				// 給對象設置紋理
				cube.setTexture("texture");
				// 除非你想在事後再用PolygonManager修改,否則釋放那些不再需要數據的內存
				cube.strip();
				// 初始化一些基本的對象是幾乎所有進一步處理所需的過程。
				// 如果對象是"準備渲染"(裝載,紋理分配,安置,渲染模式設置,
				// 動畫和頂點控制器分配),那麼build()必須被調用,
				cube.build();
				// 將Object3D對象添加到world集合
				world.addObject(cube);
				// 該Camera代表了Camera/viewer在當前場景的位置和方向,它也包含了當前視野的有關信息
				// 你應該記住Camera的旋轉矩陣實際上是應用在World中的對象的一個旋轉矩陣。
				// 這一點很重要,當選擇了Camera的旋轉角度,一個Camera(虛擬)圍繞w旋轉和通過圍繞World圍繞w旋轉、
				// 將起到相同的效果,因此,考慮到旋轉角度,World圍繞camera時,camera的視角是靜態的。假如你不喜歡
				// 這種習慣,你可以使用rotateCamera()方法
				Camera cam = world.getCamera();
				// 以50有速度向後移動Camera(相對於目前的方向)
				cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
				// cub.getTransformedCenter()返回對象的中心
				// cam.lookAt(SimpleVector lookAt))
				// 旋轉這樣camera以至於它看起來是在給定的world-space 的位置
				cam.lookAt(cube.getTransformedCenter());
				// SimpleVector是一個代表三維矢量的基礎類,幾乎每一個矢量都
				// 是用SimpleVector或者至少是一個SimpleVector變體構成的(有時由於
				// 某些原因比如性能可能會用(float x,float y,float z)之類)。
				SimpleVector sv = new SimpleVector();
				// 將當前SimpleVector的x,y,z值設爲給定的SimpleVector(cube.getTransformedCenter())的值
				sv.set(cube.getTransformedCenter());
				// Y方向上減去100
				sv.y -= 100;
				// Z方向上減去100
				sv.z -= 100;
				// 設置光源位置
				sun.setPosition(sv);
				// 強制GC和finalization工作來試圖去釋放一些內存,同時將當時的內存寫入日誌,
				// 這樣可以避免動畫不連貫的情況,然而,它僅僅是減少這種情況發生的機率
				MemoryHelper.compact();
				// 如果master爲空,使用日誌記錄且設master爲HelloWorld本身
				if (master == null) {
					Logger.log("Saving master Activity!");
					master = JPCT_AE_Activity.this;
				}
			}
		}

		// 需實現的onSurfaceCreated(GL10 gl, EGLConfig config)
		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		}

		// 繪製到當前屏幕哦:-D
		public void onDrawFrame(GL10 gl) {
			try {
				// 如果stop爲true
				if (!stop) {
					// 如果touchTurn不爲0,向Y軸旋轉touchTure角度
					if (touchTurn != 0) {
						// 旋轉物體的旋轉繞Y由給定矩陣W軸角(弧度順時針方向爲正值),應用到對象下一次渲染時。
						cube.rotateY(touchTurn);
						// 將touchTurn置0
						touchTurn = 0;
					}
					if (touchTurnUp != 0) {
						// 旋轉物體的旋轉圍繞x由給定角度寬(弧度,逆時針爲正值)軸矩陣,應用到對象下一次渲染時。
						cube.rotateX(touchTurnUp);
						// 將touchTureUp置0
						touchTurnUp = 0;
					}
					// 用給定的顏色(back)清除FrameBuffer
					fb.clear(back);
					// 變換和燈光所有多邊形
					world.renderScene(fb);
					// 繪製
					world.draw(fb);
					// 渲染圖像顯示
					fb.display();
					// 記錄FPS
					if (System.currentTimeMillis() - time >= 1000) {
						// Logger.log(fps + "fps");
						fps = 0;
						time = System.currentTimeMillis();
					}
					fps++;
					// 如果stop爲false,釋放FrameBuffer
				} else {
					if (fb != null) {
						fb.dispose();
						fb = null;
					}
				}
				// 當出現異常,打印異常信息
			} catch (Exception e) {
				Logger.log(e, Logger.MESSAGE);
			}
		}
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章