Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android開發教程之OpenGL ES基礎(二)

Android開發教程之OpenGL ES基礎(二)

編輯:Android開發實例

 二、繪制多邊形

前面的教程都是關於設置GLSurfaceView.的,接下來的教程將教我們渲染出一個多邊形。3D模型用較小的元素創建(點,邊,面),他們可以被分別操作。

 

頂點

在Android中,我們通過float數組定義頂點,並將它放到字節型緩沖區內來獲取更好的性能。

下例的代碼即為上圖所示頂點。

OpenGL ES的很多功能都必須手動的開啟和關閉。

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 設置頂點數據,3代表XYZ坐標系
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// 關閉頂點設置
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

 

 

計算多邊形面的時候,一定要注意正確的方向.。因為這將決定哪一面為正面哪一面為背面。 所以我們盡量保證整個項目都使用相同的環繞。

gl.glFrontFace(GL10.GL_CCW);

控制多邊形的正面是如何決定的。在默認情況下,mode是GL_CCW。

mode的值為:   

GL_CCW 表示窗口坐標上投影多邊形的頂點順序為逆時針方向的表面為正面。   

GL_CW 表示頂點順序為順時針方向的表面為正面。

頂點的方向又稱為環繞。

gl.glEnable(GL10.GL_CULL_FACE);

gl.glCullFace(GL10.GL_BACK);

剔除多邊形的背面,禁用多邊形背面上的光照、陰影和顏色計算及操作。

gl.glDisable(GL10.GL_CULL_FACE);  

多邊形

到了繪制面的時候了, 我們使用默認的逆時針環繞。

下例代碼將繪制上圖多邊形。

  1. // 將坐標數組放入字節緩存中 
  2. // (1) 分配緩存,一個short為2個字節,所以要乘以2 
  3. ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); 
  4. // (2) 設置字節處理規則 
  5. ibb.order(ByteOrder.nativeOrder()); 
  6. // (3) 轉換為short型字符 
  7. ShortBuffer indexBuffer = ibb.asShortBuffer(); 
  8. // (4) 放入坐標數組 
  9. indexBuffer.put(indices); 
  10. // (5) 復位 
  11. indexBuffer.position(0); 

渲染

是時候弄些玩意兒到屏幕上去了,繪制時我們將用到兩個函數

public abstract void glDrawArrays(int mode, int first, int count)

通過我們構造的頂點緩存來繪制頂點

public abstract void glDrawElements(int mode, int count, int type, Buffer indices)

和glDrawArrays類似,但需要直接傳入type(索引值的類型,如GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT),和indices(索引緩存)

兩者的共同點是,都必須知道他們需要畫什麼。怎樣渲染圖元,有不同方式,為了幫助調試,我們應該了解它們。

 

Mode:

GL_POINTS

繪制獨立的點到屏幕

GL_LINE_STRIP

連續的連線,第n個頂點與第n-1個頂點繪制一條直線

GL_LINE_LOOP

和上面相同,但首尾相連

GL_LINES

各對獨立的線段

GL_TRIANGLES

各個獨立的三角形


GL_TRIANGLE_STRIP

繪制一系列的三角形,先是頂點 v0, v1, v2, 然後是 v2, v1, v3 (注意規律), 然後v2, v3, v4等。該規律確保所有的三角形都以相同的方向繪制。

GL_TRIANGLE_FAN

和GL_TRIANGLE_STRIP類似, 但其先繪制 v0, v1, v2, 再是 v0, v2, v3, 然後 v0, v3, v4等。

我認為GL_TRIANGLES是使用最方便的,所以我們將先使用它。

  1. public class Square { 
  2.     // 頂點坐標數組 
  3.     private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上 
  4.         -1.0f, -1.0f, 0.0f, // 1, 左下 
  5. .0f, -1.0f, 0.0f, // 2, 右下 
  6. .0f, 1.0f, 0.0f, // 3, 右上 
  7.     }; 
  8.     // 連接規則 
  9.     private short[] indices = { 0, 1, 2, 0, 2, 3 }; 
  10.     // 頂點緩存 
  11.     private FloatBuffer vertexBuffer; 
  12.     // 索引緩存 
  13.     private ShortBuffer indexBuffer; 
  14.  
  15.  
  16.     public Square() { 
  17.         // 一個float為4 bytes, 因此要乘以4 
  18.         ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); 
  19.         vbb.order(ByteOrder.nativeOrder()); 
  20.         vertexBuffer = vbb.asFloatBuffer(); 
  21.         vertexBuffer.put(vertices); 
  22.         vertexBuffer.position(0); 
  23.         // short類型同理 
  24.         ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); 
  25.         ibb.order(ByteOrder.nativeOrder()); 
  26.         indexBuffer = ibb.asShortBuffer(); 
  27.         indexBuffer.put(indices); 
  28.         indexBuffer.position(0); 
  29.         } 
  30.  
  31.     /** 
  32.      * 繪制正方形到屏幕 
  33.      *  
  34.      * @param gl 
  35.      */ 
  36.     public void draw(GL10 gl) { 
  37.         // 逆時針環繞 
  38.         gl.glFrontFace(GL10.GL_CCW); 
  39.         // 開啟剔除功能 
  40.         gl.glEnable(GL10.GL_CULL_FACE); 
  41.         // 剔除背面 
  42.         gl.glCullFace(GL10.GL_BACK); 
  43.         // 開啟頂點緩存寫入功能 
  44.         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
  45.         // 設置頂點 
  46.         // size:每個頂點有幾個數指描述。 
  47.         // type:數組中每個頂點的坐標類型。 
  48.         // stride:數組中每個頂點間的間隔,步長(字節位移)。 
  49.         // pointer:存儲著每個頂點的坐標值。初始值為0 
  50.         gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); 
  51.         gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, 
  52.         GL10.GL_UNSIGNED_SHORT, indexBuffer); 
  53.         // 關閉各個功能 
  54.         gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
  55.         gl.glDisable(GL10.GL_CULL_FACE); 
  56.     } 

我們必須在OpenGLRenderer類中初始化square

square = new Square();<!--EndFragment-->

並在主繪制方法中調用square的繪制方法

public void onDrawFrame(GL10 gl) {
// 清除屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 繪制正方形
square.draw(gl);
}

如果你現在運行應用,我們又看到了華麗的黑屏,為什麼?因為OpenGL ES渲染默認的當前位置為(0,0,0),窗口的定位也一樣。而且OpenGL ES不渲染太靠近窗體定位的東西。解決方法就是移動繪制的位置。

gl.glTranslatef(0, 0, -4);  <!--EndFragment-->

再次運行應用你將看到該正方形已經被繪制,但是它好像離我們越來越遠一樣,最後消失了。

OpenGL ES不會在畫面之間復位繪制點,所以我們要自己完成。

// 重置當前的模型觀察矩陣
gl.glLoadIdentity();<!--EndFragment-->

現在,我們運行應用將會看到一個固定位置的正方形。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved