1. 程式人生 > >Android OpenGL ES 開發教程(8):基本幾何圖形定義

Android OpenGL ES 開發教程(8):基本幾何圖形定義

通常二維圖形庫可以繪製點,線,多邊形,圓弧,路徑等等。OpenGL ES 支援繪製的基本幾何圖形分為三類:點,線段,三角形。也就是說OpenGL ES 只能繪製這三種基本幾何圖形。任何複雜的2D或是3D圖形都是通過這三種幾何圖形構造而成的。

比如下圖複雜的3D圖形,都有將其分割成細小的三角形面而構成的。然後通過上色(Color),新增材質(Texture),再新增光照(lighting),構造3D效果的圖形:

點,線段,三角形都是通過頂點來定義的,也就是頂點陣列來定義。對應平面上的一系列頂點,可以看出一個個孤立的點(Point),也可以兩個兩個連線成線段(Line Segment) ,也可以三個三個連成三角形(Triangle)。這些對一組頂點的不同解釋就定義了Android OpenGL ES可以繪製的基本幾何圖形,下面定義了OpenGL ES定義的幾種模式:

GL_POINTS

繪製獨立的點。

GL_LINE_STRIP

繪製一系列線段。

GL_LINE_LOOP

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

GL_LINES

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

GL_TRIANGLES

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

GL_TRIANGLE_STRIP

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

GL_TRIANGLE_FAN

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

以上模式對應到Android渲染方法:

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 指定。

其中mode 為上述解釋頂點的模式。

如下面定義三個頂點座標,並把它們存放在FloatBuffer 中:

float[] vertexArray = new float[]{
 -0.8f , -0.4f * 1.732f , 0.0f ,
 0.8f , -0.4f * 1.732f , 0.0f ,
 0.0f , 0.4f * 1.732f , 0.0f ,
 };
 
ByteBuffer vbb
 = ByteBuffer.allocateDirect(vertexArray.length*4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertex = vbb.asFloatBuffer();
vertex.put(vertexArray);
vertex.position(0);

有了頂點的定義,下面就可以通過開啟OpenGL ES管道(Pipeline)的相應開關將頂點引數傳給OpenGL 庫:

開啟頂點開關和關閉頂點開關的方法如下:

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
 
...
 
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

在開啟頂點開關後,將頂點座標傳給OpenGL 管道的方法為:glVertexPointer:

public void glVertexPointer(int size,int type,int stride,Buffer pointer)

  • size: 每個頂點座標維數,可以為2,3,4。
  • type: 頂點的資料型別,可以為GL_BYTE, GL_SHORT, GL_FIXED,或 GL_FLOAT,預設為浮點型別GL_FLOAT。
  • stride: 每個相鄰頂點之間在陣列中的間隔(位元組數),預設為0,表示頂點儲存之間無間隔。
  • pointer: 儲存頂點的陣列。

應用用上可以般頂點的顏色值存放在對應頂點後面,如下圖,RGB 採用4 位元組表示,此時相鄰頂點就不是連續存放的,stride 值為4

對應頂點除了可以為其定義座標外,還可以指定顏色,材質,法線(用於光照處理)等。

glEnableClientState 和 glDisableClientState 可以控制的pipeline開關可以有:GL_COLOR_ARRAY (顏色) ,GL_NORMAL_ARRAY (法線), GL_TEXTURE_COORD_ARRAY (材質), GL_VERTEX_ARRAY(頂點), GL_POINT_SIZE_ARRAY_OES等。

對應的傳入顏色,頂點,材質,法線的方法如下:

glColorPointer(int size,int type,int stride,Buffer pointer)
glVertexPointer(int size, int type, int stride, Buffer pointer)
glTexCoordPointer(int size, int type, int stride, Buffer pointer)
glNormalPointer(int type, int stride, Buffer pointer)

如果需要使用三角形來構造複雜圖形,可以使用GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN模式,另外一種是通過定義頂點序列:

如下圖定義了一個正方形:

對應的頂點和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);

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

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

gl.glFrontFace(GL10.GL_CCW);

開啟 忽略“後面”設定:

gl.glEnable(GL10.GL_CULL_FACE);

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


gl.glCullFace(GL10.GL_BACK);