在前面 Android OpenGL ES 開發教程(7):創建實例應用 OpenGLDemos 程序框架 我們創建了示例程序的基本框架,并提供了一個 “Hello World” 示例,將屏幕顯示為紅色。
本例介紹 OpenGL ES 3D 圖形庫支持的幾種基本幾何圖形,本篇部分內容與 Android OpenGL ES 簡明開發教程三:3D 繪圖基本概念 類似。
通常二維圖形庫可以繪制點,線,多邊形,圓弧,路徑等等。OpenGL ES 支持繪制的基本幾何圖形分為三類:點,線段,三角形。也就是說 OpenGL ES 只能繪制這三種基本幾何圖形。任何復雜的2D或是3D圖形都是通過這三種幾何圖形構造而成的。
比如下圖復雜的 3D 圖形,都有將其分割成細小的三角形面而構成的。然后通過上色 (Color),添加材質 (Texture),再添加光照(lighting),構造3D效果的圖形:
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/46.png" alt="" />
點,線段,三角形都是通過頂點來定義的,也就是頂點數組來定義。對應平面上的一系列頂點,可以看出一個個孤立的點 (Point),也可以兩個兩個連接成線段 (Line Segment) ,也可以三個三個連成三角形 (Triangle)。這些對一組頂點的不同解釋就定義了 Android OpenGL ES 可以繪制的基本幾何圖形,下面定義了 OpenGL ES 定義的幾種模式:
繪制獨立的點。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/47.png" alt="" />
繪制一系列線段。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/48.png" alt="" />
類同上,但是首尾相連,構成一個封閉曲線。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/49.png" alt="" />
頂點兩兩連接,為多條線段構成。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/50.png" alt="" />
每隔三個頂點構成一個三角形,為多個三角形組成。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/51.png" alt="" />
每相鄰三個頂點組成一個三角形,為一系列相接三角形構成。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/52.png" alt="" />
以一個點為三角形公共頂點,組成一系列相鄰的三角形。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/53.png" alt="" />
以上模式對應到 Android 渲染方法:
OpenGL ES 提供了兩類方法來繪制一個空間幾何圖形:
其中 mode 為上述解釋頂點的模式。
前面說過頂點一般使用數組來定義,并使用 Buffer 來存儲以提高繪圖性能,參見Android OpenGL ES 開發中的Buffer使用
如下面定義三個頂點坐標,并把它們存放在 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)
應用用上可以般頂點的顏色值存放在對應頂點后面,如下圖,RGB 采用 4 字節表示,此時相鄰頂點就不是連續存放的,stride 值為 4 。
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/54.png" alt="" />
對應頂點除了可以為其定義坐標外,還可以指定顏色,材質,法線(用于光照處理)等。
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 模式,另外一種是通過定義頂點序列:
如下圖定義了一個正方形:
http://wiki.jikexueyuan.com/project/opengl-es-guide/images/55.png" alt="" />
對應的頂點和 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);