2011年4月17日 星期日

[ Android OpenGL ES 教學(二)] 建立多邊形

基礎閱讀:http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es.html
延伸閱讀:[ Android OpenGL ES 教學(三)] 轉換相關方法 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_3388.html
參考文章:OpenGL ES Tutorial for Android – Part II – Building a polygon 發表在http://blog.jayway.com/2009/12/04/opengl-es-tutorial-for-android-%E2%80%93-part-ii-building-a-polygon/
在OpenGL中建立多邊形是利用點連接而成,如下圖(摘自參考文章)

上述的圖形可以轉換成點的陣列如下所示:

 // 點的陣列
 private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角
   -1.0f, -1.0f, 0.0f, // 1, 左下角
   1.0f, -1.0f, 0.0f, // 2, 右下角
   1.0f, 1.0f, 0.0f, // 3, 右上角
                            }

接下來我們來實作看看, 其步驟如下:
1. 建立Square類別


2. 以下是Square.java程式列表(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl;


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;
public class Square {

 // 點的陣列
 private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角
   -1.0f, -1.0f, 0.0f, // 1, 左下角
   1.0f, -1.0f, 0.0f, // 2, 右下角
   1.0f, 1.0f, 0.0f, // 3, 右上角
 };

 // 連接點的次序
 private short[] indices = { 0, 1, 2, 0, 2, 3 };

 // 點的緩衝區
 private FloatBuffer vertexBuffer;

 // 索引值緩衝區
 private ShortBuffer indexBuffer;

 public Square() {
  // 浮點數是4位元組因此需要把點陣列長度乘以4
  ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
  vbb.order(ByteOrder.nativeOrder());
  vertexBuffer = vbb.asFloatBuffer();
  vertexBuffer.put(vertices);
  vertexBuffer.position(0);

  // 短整數是2位元組因此需要把點陣列長度乘以2
  ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
  ibb.order(ByteOrder.nativeOrder());
  indexBuffer = ibb.asShortBuffer();
  indexBuffer.put(indices);
  indexBuffer.position(0);
 }

 /**
  * 畫圖函式
  * 
  * @param gl
  */
 public void draw(GL10 gl) {
  // 逆時鐘
  gl.glFrontFace(GL10.GL_CCW);
  // 啟動CULL_FACE
  gl.glEnable(GL10.GL_CULL_FACE);
  // 刪除多邀形的背景
  gl.glCullFace(GL10.GL_BACK);

  // 啟動點的緩衝區
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  // 指定位置和資料格式
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);

  // 以三點劃出三角形
  gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
    GL10.GL_UNSIGNED_SHORT, indexBuffer);

  // 除能點的緩衝區
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  // 除能CULL_FACE
  gl.glDisable(GL10.GL_CULL_FACE);
 }
}

3. 以下是OpenGLRenderer.java程式列表(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;

public class OpenGLRenderer implements Renderer {
 private Square square;

 public OpenGLRenderer() {
  // 初始化
  square = new Square();
 }

 @Override
 public void onDrawFrame(GL10 gl) {
  // TODO Auto-generated method stub
  // 清除螢幕和深度緩衝區
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

  // 以單位矩陣取代目前的矩陣
  gl.glLoadIdentity();
  // Z軸轉置 4 單位
  gl.glTranslatef(0, 0, -4);
  // 畫出方形
  square.draw(gl);
 }

 @Override
 public void onSurfaceChanged(GL10 gl, int width, int height) {
  // TODO Auto-generated method stub
  // 設定新視域視窗的大小
  gl.glViewport(0, 0, width, height);
  // 選擇投射的陣列模式
  gl.glMatrixMode(GL10.GL_PROJECTION);
  // 重設投射陣
  gl.glLoadIdentity();
  // 計算視窗的寬高比率
  GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
    100.0f);
  // 選擇MODELVIEW陣列
  gl.glMatrixMode(GL10.GL_MODELVIEW);
  // 重設MODELVIEW陣列
  gl.glLoadIdentity();
 }

 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  // TODO Auto-generated method stub
  // 設定背景顏色為黑色, 格式是RGBA
  gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
  // 設定流暢的陰影模式
  gl.glShadeModel(GL10.GL_SMOOTH);
  // 深度緩區的設定
  gl.glClearDepthf(1.0f);
  // 啟動深度的測試
  gl.glEnable(GL10.GL_DEPTH_TEST);
  // GL_LEQUAL深度函式測試
  gl.glDepthFunc(GL10.GL_LEQUAL);
  // 設定很好的角度計算模式
  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
 }

}

4. 執行結果

3 則留言:

  1. 作者已經移除這則留言。

    回覆刪除
  2. 想請問一下,每個角的三個數字-1.0f, 1.0f, 0.0f,是不是分別是X Y Z啊!?

    回覆刪除