1. 程式人生 > >Android OpenGL ES 簡明開發教程三 3D繪圖基本概念

Android OpenGL ES 簡明開發教程三 3D繪圖基本概念

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

前面介紹了使用Android 編寫OpenGL ES應用的程式框架,本篇介紹3D繪圖的一些基本構成要素,最終將實現一個多邊形的繪製。

一個3D圖形通常是由一些小的基本元素(頂點,邊,面,多邊形)構成,每個基本元素都可以單獨來操作。

Vertex (頂點)

頂點是3D建模時用到的最小構成元素,頂點定義為兩條或是多條邊交會的地方。在3D模型中一個頂點可以為多條邊,面或是多邊形所共享。一個頂點也可以代表一個點光源或是Camera的位置。下圖中標識為黃色的點為一個頂點(Vertex)。

在Android系統中可以使用一個浮點數陣列來定義一個頂點,浮點數陣列通常放在一個Buffer(java.nio)中來提高效能。

比如:下圖中定義了四個頂點和對應的Android 頂點定義:

private float vertices[] = { -1.0f1.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.0f1.0f, 0.0f// 3, Top Right};

為了提高效能,通常將這些陣列存放到java.io 中定義的Buffer類中:

// 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);

Edge(邊)

邊定義為兩個頂點之間的線段。邊是面和多邊形的邊界線。在3D模型中,邊可以被相鄰的兩個面或是多邊形形共享。對一個邊做變換將影響邊相接的所有頂點,面或多邊形。在OpenGL中,通常無需直接來定義一個邊,而是通過頂點定義一個面,從而由面定義了其所對應的三條邊。可以通過修改邊的兩個頂點來更改一條邊,下圖黃色的線段代表一條邊:

Face (面)

在OpenGL ES中,面特指一個三角形,由三個頂點和三條邊構成,對一個面所做的變化影響到連接面的所有頂點和邊,面多邊形。下圖黃色區域代表一個面。

定義面的頂點的順序很重要 在拼接曲面的時候,用來定義面的頂點的順序非常重要,因為頂點的順序定義了面的朝向(前向或是後向),為了獲取繪製的高效能,一般情況不會繪製面的前面和後面,只繪製面的“前面”。雖然“前面”“後面”的定義可以應人而易,但一般為所有的“前面”定義統一的頂點順序(順時針或是逆時針方向)。

下面程式碼設定逆時針方法為面的“前面”:

gl.glFrontFace(GL10.GL_CCW);

開啟 忽略“後面”設定:

gl.glEnable(GL10.GL_CULL_FACE);

明確指明“忽略“哪個面的程式碼如下:

gl.glCullFace(GL10.GL_BACK);

Polygon (多邊形)

多邊形由多個面(三角形)拼接而成,在三維空間上,多邊形並一定表示這個Polygon在同一平面上。這裡我們使用預設的逆時針方向代表面的“前面Front),下圖黃色區域為一個多邊形。

來看一個多邊形的示例在Android系統如何使用頂點和buffer 來定義,如下圖定義了一個正方形:

對應的頂點和buffer 定義程式碼:


private short[] indices = { 0, 1, 2, 0, 2, 3 };To gain some performance we also put this ones in a byte buffer.// short is 2 bytes, therefore we multiply the number if vertices with 2.ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);ibb.order(ByteOrder.nativeOrder());ShortBuffer indexBuffer = ibb.asShortBuffer();indexBuffer.put(indices);indexBuffer.position(0);


 

Render (渲染)

我們已定義好了多邊形,下面就要了解如和使用OpenGL ES的API來繪製(渲染)這個多邊形了。OpenGL ES提供了兩類方法來繪製一個空間幾何圖形:

  • public abstract void glDrawArrays(int mode, int first, int count) 使用VetexBuffer 來繪製,頂點的順序由vertexBuffer中的順序指定。
  • public abstract void glDrawElements(int mode, int count, int type, Buffer indices) ,可以重新定義頂點的順序,頂點的順序由indices Buffer 指定。

前面我們已定義裡頂點陣列,因此我們將採用glDrawElements 來繪製多邊形。

同樣的頂點,可以定義的幾何圖形可以有所不同,比如三個頂點,可以代表三個獨立的點,也可以表示一個三角形,這就需要使用mode 來指明所需繪製的幾何圖形的基本型別。

GL_POINTS

繪製獨立的點。

GL_LINE_STRIP

繪製一系列線段。

GL_LINE_LOOP

類同上,但是首尾相連,構成一個封閉曲線。

GL_LINES

頂點兩兩連線,為多條線段構成。

GL_TRIANGLES

每隔三個頂點構成一個三角形,為多個三角形組成。

GL_TRIANGLE_STRIP

每相鄰三個頂點組成一個三角形,為一系列相接三角形構成。

GL_TRIANGLE_FAN

以一個點為三角形公共頂點,組成一系列相鄰的三角形。

下面可以來繪製正方形了,在專案中新增一個Square.java 定義如下:

package se.jayway.opengl.tutorial; 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 { // Our vertices. 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 };  // The order we like to connect them. private short[] indices = { 0, 1, 2, 0, 2, 3 };  // Our vertex buffer. private FloatBuffer vertexBuffer;  // Our index buffer. private ShortBuffer indexBuffer;  public Square() { // 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()); vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0);  // short is 2 bytes, therefore we multiply //the number if // vertices with 2. ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); ibb.order(ByteOrder.nativeOrder()); indexBuffer = ibb.asShortBuffer(); indexBuffer.put(indices); indexBuffer.position(0); }  /** * This function draws our square on screen. * @param gl */ public void draw(GL10 gl) { // Counter-clockwise winding. gl.glFrontFace(GL10.GL_CCW); // Enable face culling. gl.glEnable(GL10.GL_CULL_FACE); // What faces to remove with the face culling. gl.glCullFace(GL10.GL_BACK);  // Enabled the vertices buffer for writing //and to be used during // rendering. gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // Specifies the location and data format of //an array of vertex // coordinates to use when rendering. gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);  gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);  // Disable the vertices buffer. gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // Disable face culling. gl.glDisable(GL10.GL_CULL_FACE); } }

在OpenGLRenderer 中新增Square成員變數並初始化:

// Initialize our square. Square square = new Square(); 並在public void onDrawFrame(GL10 gl) 新增 // Draw our square.
square.draw(gl);
來繪製這個正方形,編譯執行,什麼也沒顯示,這是為什麼呢?這是因為OpenGL ES從當前位置開始渲染,預設座標為(0,0,0),和View port 的座標一樣,相當於把畫面放在眼前,對應這種情況OpenGL不會渲染離view Port很近的畫面,因此我們需要將畫面向後退一點距離: // Translates 4 units into the screen. gl.glTranslatef( 0 , 0 , - 4 ); 在編譯執行,這次倒是有顯示了,當正方形迅速後移直至看不見,這是因為每次呼叫onDrawFrame 時,每次都再向後移動4個單位,需要加上重置Matrix的程式碼。 // Replace the current matrix with the identity matrix gl.glLoadIdentity(); 最終onDrawFrame的程式碼如下:
public void onDrawFrame(GL10 gl) // Clears the screen and depth buffer. gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0, 0, -4); // Draw our square. square.draw(gl); // ( NEW ) }
本篇程式碼 下載
     
// Initialize our square. Square square = new Square();

 

 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述