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()。
沒有留言:
張貼留言