Yet Another Tutorial on Android 3D Graphics using OpenGL ES Including Nehe's Port:
Android從1.0開始,就支援Open Graphics Library (OpenGL)移動裝置版 OpenGL ES API 用來進行硬體加速2D和3D圖形處理。從Android 2.2 (API Level 8)開始支援OpenGL ES 2.0 API規格(和J2ME JSR239 OpenGL ES API類似)。有兩個基本Class讓你方便使用OpenGL ES API。
GLSurfaceView
- 類似SurfaceView,像畫布一樣在上面作畫,若想接收觸控訊息時,就實做個touch listener,見範例TouchRotateActivity。@Override public boolean onTouchEvent(MotionEvent e) { ........}
此界面實現了在GLSurface上畫畫的動作,經由setRenderer()設定,必須實現方法:
- onSurfaceCreated(): 當產生GLSurface時呼叫一次。在這裡執行設定OpenGL環境變數,起始 OpenGL圖形物件等動作。
- onDrawFrame(): 每一次GLSurface重畫時呼叫此函數。
- onSurfaceChanged(): 當GLSurface改變時呼叫此函數,包含大小、方向等。
public class OpenGLES10 extends Activity { private GLSurfaceView mGLView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 產生一個GLSurfaceView實體,並指定為此Activity的ContentView mGLView = new GLES10sv(this); setContentView(mGLView); } @Override protected void onPause() { super.onPause(); // 若你的OpenGL程式重度使用記憶體時, // 也許可以在此釋放一些物件。 mGLView.onPause(); } @Override protected void onResume() { super.onResume(); // 若你的OpenGL程式在onPause曾釋放記憶體時, // 此時可以重新產生物件。 mGLView.onResume(); } }
class GLES10sv extends GLSurfaceView { private final float TOUCH_SCALE_FACTOR = 180.0f / 320; private GLES10Render mRender; private float mPreviousX; private float mPreviousY; public GLES10sv(Context context){ super(context); // 指定Renderer來作畫 mRender = new GLES10Render(); setRenderer(mRender); // 當畫面有改變時才畫 setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); } @Override public boolean onTouchEvent(MotionEvent e) { // MotionEvent reports input details from the touch screen // and other input controls. In this case, you are only // interested in events where the touch position changed. // 觸摸事件回傳的座標並不是和OpenGL座標相同,必須轉換才行。 float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dx = x - mPreviousX; float dy = y - mPreviousY; // reverse direction of rotation above the mid-line if (y > getHeight() / 2) { dx = dx * -1 ; } // reverse direction of rotation to left of the mid-line if (x < getWidth() / 2) { dy = dy * -1 ; } mRender.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR; requestRender(); } mPreviousX = x; mPreviousY = y; return true; } }
public class GLES10Render implements GLSurfaceView.Renderer { private FloatBuffer triangleVB; public float mAngle; public void onSurfaceCreated(GL10 gl, EGLConfig config) { //設定背景顏色 gl.glClearColor(0.0f,0.5f,0.0f,1.0f); //起始三角形陣列 initShapes(); //使用點陣列 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); } public void onDrawFrame(GL10 gl) { //重畫背景顏色 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL10.GL_MODELVIEW);// 設成GL_MODELVIEW轉換模式 gl.glLoadIdentity(); //重置成I矩陣 //當使用GL_MODELVIEW,必須設置視點(view point GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); //旋轉mAngle gl.glRotatef(mAngle, 0.0f, 0.0f, 1.0f); //畫三角形 gl.glColor4f(1.0f, 0.0f, 0.0f, 0.0f); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB); gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); } public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); float ratio = (float)width/height; //調整螢幕比例 gl.glMatrixMode(GL10.GL_PROJECTION);//設成投影模式 gl.glLoadIdentity(); //重置成I矩陣 gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);//使用此投影矩陣 } }
預設OpenGL ES將[0,0,0] (X,Y,Z)為GLSurfaceView畫面的中心,[1,1,0] 右上角,而[-1,-1,0]為畫面左下角
private void initShapes(){ //定義一個平面上的正三角形 float triangleCoords[] = { // X, Y, Z -0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0 }; // initialize vertex Buffer for triangle //(# of coordinate values * 4 每一個float佔4個byte) ByteBuffer vbb=ByteBuffer.allocateDirect(triangleCoords.length*4); // vbb.order(ByteOrder.nativeOrder()); //使用裝置硬體原生的位元組順序 triangleVB = vbb.asFloatBuffer(); //衍生floating point buffer triangleVB.put(triangleCoords); //放入座標 triangleVB.position(0); //指向第一個座標位置 }
把initShapes放入onSurfaceCreated()作起始動作,切記這些圖形物件的啟始動作千萬不要放在onDrawFrame()。
沒有留言:
張貼留言