2011年10月5日 星期三

OpenGL ES for Android的學習(二):建立多邊形(polygon)

一般來說,學繪圖的HelloWorld應該是要來劃一個三角形(Triangle),下面我綜合參考了
Jayway Team Blog:OpenGL ES Tutorial for Android –Part II– Building a polygon
3D Graphics using OpenGL ES (Including Nehe's Port)Example 2
來完成建立多邊形這個教學!

在開始建立程式前,先補充說明在建立3D模型時,需要用到的一些子元素
(頂點表面多邊形),他們都能獨立的分別被實做出來。
  • 頂點(Vertex)
         頂點是構成3D模型的最小建物,他是由兩個或兩個以上的邊交界而成的點。一個頂點可以在所有相關聯的邊、面和多邊形中共用。頂點也可以是照相機或光源位置的表示。Android中,我們浮點數陣列來定義它,同時我們將它放在byte buffer中以獲取較佳的效能。

 private float vertices[] = {  
    -1.0f, 1.0f, 0.0f, // 0, Top Left  
    -1.0f, -1.0f, 0.0f, // 1, Bottom Left  
     1.0f, -1.0f, 0.0f, // 2, Bottom Right  
     1.0f, 1.0f, 0.0f, // 3, Top Right  
 };  
 // a float is 4 bytes, therefore we multiply the number if vertices with 4.  
 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);  
 vbb.order(ByteOrder.nativeOrder());  
 FloatBuffer vertexBuffer = vbb.asFloatBuffer();  
 vertexBuffer.put(vertices);  
 vertexBuffer.position(0);  
要注意的一個浮點數是4個位元組,將它和頂點數相乘,才可以正確的配置buffer大小。
  • (Edge)
          邊是在兩個頂點之間的線段。它們是表面和多邊形的邊緣線。在3D模型中,便可以在       兩個鄰近表面或多邊形之間共用。轉換一條邊,影響所有相連接的頂點,面和多邊形 。OpenGL ES中,我們不能定義邊,你只能通過給定的頂點定義面,這將至少構建三條邊。如果你想要修改一條邊,你應該改變產生這條邊的兩個頂點。
  • (face)
          面是一個三角形,面就是這三個頂點和三個邊所圍成的表面,變換一個面影響所有關聯         的頂點,邊和多邊形。對於這些元素的介紹先到這裡,Jayway還有一些細部的介紹,都還蠻有價值的,但我相信大家沒看到code就很難過,我們就先來畫畫三角形吧!          


Triangle.java
 com.hanshuo.opengl.tutorial;  
 import java.nio.ByteBuffer;  
 import java.nio.ByteOrder;  
 import java.nio.FloatBuffer;  
 import javax.microedition.khronos.opengles.GL10;  
 /*  
  * A triangle with 3 vertices.  
  */  
 public class Triangle {  
   private FloatBuffer vertexBuffer; // 頂點陣列的緩衝  
   private ByteBuffer indexBuffer;  // 索引緩衝  
   private float[] vertices = { // 三角形的頂點們  
     0.0f, 1.0f, 0.0f, // 0. 頂  
    -1.0f, -1.0f, 0.0f, // 1. 左下  
     1.0f, -1.0f, 0.0f // 2. 右下  
   };  
   private byte[] indices = { 0, 1, 2 }; // 連結這些點的順序  
   // 建構子 – 建立資料陣列的緩衝  
   public Triangle() {  
    // 建立頂點陣列緩衝. 頂點是浮點數要乘4個byte.  
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);  
    vbb.order(ByteOrder.nativeOrder()); // 使用原生順序  
    vertexBuffer = vbb.asFloatBuffer(); // 轉換位元組緩衝為浮點數  
    vertexBuffer.put(vertices);     // 將資料複製到緩衝  
    vertexBuffer.position(0);      // 倒轉歸零  
    //建立頂點索引陣列緩衝
    indexBuffer = ByteBuffer.allocateDirect(indices.length);  
    indexBuffer.put(indices);  
    indexBuffer.position(0);  
   }  
   // 渲染這個圖形  
   public void draw(GL10 gl) {  
    // Enable vertex-array and define the buffers  
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);  
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);  
    // int size, int type, int stride, Buffer pointer  
    // size: 頂點的座標數 (只有2,3,4).  
    // type: 頂點座標的資料型態, GL_BYTE, GL_SHORT, GL_FIXED, or GL_FLOAT  
    // stride: 連續頂點可以有幾個byte的offset. 0是緊密的包裝?  
    // 透過index-array繪製元素
    gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);  
    // int mode, int count, int type, Buffer indices) 
    // mode: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES  
    // count: 有幾個元素將要被渲染 
    // type:頂點的資料型態 (must be GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT).  
    // indices:index array的指標   
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);  
   }  
 }  

TutorialPartI.java (藍色是新的程式碼)
 package com.hanshuo.opengl.tutorial;  
 import javax.microedition.khronos.egl.EGLConfig;  
 import javax.microedition.khronos.opengles.GL10;  
 import android.content.Context;  
 import android.opengl.GLU;  
 import android.opengl.GLSurfaceView.Renderer;  
 public class OpenGLRenderer implements Renderer {  
      Triangle triangle;   
      public OpenGLRenderer() {  
         // Set up the data-array buffers for these shapes (多了這裡)  
         triangle = new Triangle();  // (多了這裡)   
        }  
      public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
           // 將背景設成紅色 (rgba).  
           gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);  
           // 允許陰影平滑, 預設也可以,不是必須的  
           gl.glShadeModel(GL10.GL_SMOOTH);  
           // 深度緩衝設置  
           gl.glClearDepthf(1.0f);  
           // 允許深度測試  
           gl.glEnable(GL10.GL_DEPTH_TEST);  
           // 深度檢測類型  
           gl.glDepthFunc(GL10.GL_LEQUAL);  
           // 精細度設置  
           gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);  
      }  
      public void onDrawFrame(GL10 gl) {  
           // 清除螢幕和深度緩衝  
           gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);       
           gl.glLoadIdentity();         // Reset model-view matrix (多了這裡)
           gl.glTranslatef(-1.5f, 0.0f, -6.0f); // Translate left and into the screen (多了這裡)  
           triangle.draw(gl);          // Draw triangle (多了這裡)      
      }  

執行結果:

有沒有很簡單捏~

沒有留言:

張貼留言