以下均轉自Android遊戲編程入門經典,轉載請標明出處首先,定義一個三角形的組成部分:
一個三角形由3個點組成;
每個點都稱為頂點;
一個頂點對應3D空間中的一個位置;
3D空間中的一個位置由3個浮點數表示,分別是x、y、z座標;
一個頂點可以有一些附加屬性,例如顏色或紋理座標,這些屬性也由浮點數表示。
OpenGL ES採用數組的形式定義三角形。但是,OpenGL ES實際上是通過C API提供介面,因此無法使用標準Java數組。這裡使用的替代方法是採用Java的NIO緩衝區,該緩衝區是一段連續位元組的記憶體塊。
為了保證完全準確,需要使用直接NIO緩衝區。這意味著這塊記憶體不是在虛擬機器的堆記憶體中,而是在主機的堆記憶體中。為了構造這樣的一個直接NIO緩衝區,可以使用下面的代碼:
ByteBuffer buffer = ByteBuffer.allocateDirect(NUMBER_OF_BYTES);
buffer.order(ByteOrder.nativeOrder());
上面的代碼將分配一個總長NUMBER_OF_BYTES位元組的ByteBuffer,並且保證位元組的順序等於底層的CPU的位元組順序。一個NIO緩衝區有3個屬性:
Capacity: 緩衝區可以容納的元素總個數;
Position: 下一個元素將要寫入或讀取的當前位置;
Limit: 最後一個元素的索引加一。
一個緩衝區的容量實際上是它的大小。ByteBuffer的容量是位元組數。Position和Limit屬性可以看作是在緩衝區中從位置開始到界限(不包括在內)位置定義的一段。
既然需要使用浮點數表示頂點,那麼最好不用處理位元組。可以將ByteBuffer執行個體轉換成FloatBuffer執行個體,這樣就可以使用浮點數了:
FloatBuffer floatBuffer = buffer.asFloatBuffer();
在FloatBuffer中,容量,位置和界限都是浮點型。這些緩衝區的使用方式也很簡單--如下所示:
float[] vertices = {...};
floatBuffer.clear();
floatBuffer.put(vertices);
floatBuffer.flip(); // 將位置值和界限值交換
發送頂點給OpenGL ES:
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 2 * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertices = byteBuffer.asFloatBuffer();
vertices.put(new float[]{
0.0f, 0.0f,
319.0f, 0.0f,
160.0f, 479.0f
});
vertices.flip();
注意:只能夠用x、y座標指定頂點, OpenGL ES會自動將Z座標設定為0.
一旦NIO緩衝區可用,OpenGL ES便可根據它的目前狀態進行繪製(即視口和投影矩陣)。
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
glEnableClientState()方法需要告訴OpenGL ES這些需要繪製的頂點都有一個位置。
glVertexPointer()方法,需要告訴OpenGL ES從何處取得頂點的位置和其他一些附加資訊。第一個參數告訴OpenGL ES每個頂點的位置是由x、y座標組成。如果需要指定x、y和z值,那麼需要將參數設定為3.第二個參數告訴OpenGL ES座標使用的資料類型。在這裡是GL10.GL_FLOAT,這說明座標值使用的是浮點型,佔用4個位元組。第三個參數是步長,告訴OpenGL頂點位置之間的位元組距離。本例中,步長為零,說明位置值是緊密封裝的。最後一個參數是FloatBuffer,它代表原生堆中的一個記憶體塊,並有一個起始地址。
當需要繪製緩衝區中的內容時,OpenGL ES將從該位置讀取這些頂點值。
最後調用的是glDrawArrays()方法,它將繪製一個三角形。第一個參數指明了將要繪製的物體類型。本例中通過GL10.GL_TRIANGLES指明將渲染三角形。下一個參數是與頂點指標指向第一個頂點相關聯的位移量。該位移量是以頂點為單位進行測量的,而不是以位元組或浮點為單位。如果指定了多個三角形,那麼可以使用這個位移量渲染三角形列表的一個子集。最後一個參數告訴OpenGL
ES渲染時使用的頂點數量。
每一個頂點可能擁有多個屬性,不僅僅只是位置。其他的屬性可能是頂點顏色。
在沒有指定頂點屬性時,OpenGL ES會將這些屬性設為預設值。絕大多數預設值可直接設定。例如,當需要為繪製的所有頂點設定預設顏色時,使用如下方法;
GL10.glColor4f(float r, float g, float b, float a)
OpenGL ES預設顏色值從(1, 1, 1, 1 )開始,這意味著從白色開始。
FirstTriangleTest.java
package org.example.androidgames.glbasics;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL10;import org.example.androidgames.framework.Game;import org.example.androidgames.framework.Screen;import org.example.androidgames.framework.impl.GLGame;import org.example.androidgames.framework.impl.GLGraphics;public class FirstTriangleTest extends GLGame {@Overridepublic Screen getStartScreen() {// TODO Auto-generated method stubreturn new FirstTriangleScreen(this);}class FirstTriangleScreen extends Screen{GLGraphics glGraphics;FloatBuffer vertices;public FirstTriangleScreen(Game game){super(game);glGraphics = ((GLGame)game).getGLGraphics();ByteBuffer byteBuffer = ByteBuffer.allocateDirect(3 * 2 * 4);byteBuffer.order(ByteOrder.nativeOrder());vertices = byteBuffer.asFloatBuffer();vertices.put(new float[]{0.0f, 0.0f,319.0f, 0.0f,160.0f, 479.0f});vertices.flip();}@Overridepublic void update(float deltaTime) {// TODO Auto-generated method stubgame.getInput().getTouchEvents();game.getInput().getKeyEvents();}@Overridepublic void present(float deltaTime) {// TODO Auto-generated method stubGL10 gl = glGraphics.getGL();gl.glViewport(0, 0, glGraphics.getWidth(), glGraphics.getHeight());gl.glClear(GL10.GL_COLOR_BUFFER_BIT);gl.glMatrixMode(GL10.GL_PROJECTION);gl.glLoadIdentity();gl.glOrthof(0, 320, 0, 480, 1, -1);gl.glColor4f(1, 0, 0, 1);gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);}@Overridepublic void pause() {// TODO Auto-generated method stub}@Overridepublic void resume() {// TODO Auto-generated method stub}@Overridepublic void dispose() {// TODO Auto-generated method stub}}}
運行效果: