###
在第一個例子裏面,我們創建了兩個類來更改背景顏色 Opengl ES(一):第一個例子
對於opengl ES的架構有了一定的認識,接下來我們繼續去畫一個三角形,代碼參考
https://developer.android.google.cn/training/graphics/opengl/shapes和
https://developer.android.google.cn/training/graphics/opengl/draw
###
可以分爲兩步,第一步是創造一個三角形,第二步是將這個三角形輸出到屏幕上顯示。
本篇文章先介紹如何創造一個三角形。
###創造一個三角形
根據Opengl的渲染流程,我們創造一個三角形就需要將三角形頂點座標表示出來,並存儲到頂點緩衝區,以待後面頂點着色器處理。
Opengl支持的座標是三維float型歸一化的,通常用一維數組來表示,如[0,0,0]表示座標原點,[1,1,0]表示最右上角。下面的一維float數組就存儲了三個頂點的信息。
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
接下來我們將頂點信息存儲到頂點緩存區即可,來看看代碼。
public class Triangle {
private FloatBuffer vertexBuffer;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
public Triangle() {
// 初始化頂點數據Buffer
ByteBuffer bb = ByteBuffer.allocateDirect(
// (一個float型4字節)
triangleCoords.length * 4);
// 字節序使用native order
bb.order(ByteOrder.nativeOrder());
// 將ByteBuffer轉換爲浮點型FloatBuffer
vertexBuffer = bb.asFloatBuffer();
// 將頂點數據添加到Buffer
vertexBuffer.put(triangleCoords);
// Buffer位置調整到開頭
vertexBuffer.position(0);
}
}
我們使用的類型是FloatBuffer,理論上直接將頂點數據put進我們創建的vertexBuffer即可。那爲什麼要繞一圈使用ByteBuffer再構建FloatBuffer呢?
##?爲什麼不直接使用FloatBuffer構建
我嘗試直接用FloatBuffer來存儲頂點座標,提示的錯誤是:Must use a native order direct Buffer
至於爲什麼要這樣做,我沒有查到,也許是opengl的規範?
網上很多文章說是因爲order的問題,即java是大端字節序,opengl是小端字節序,但根據FloatBuffer中order的描述和自己的驗證(使用.odrer()輸出字節序),直接使用FloatBuffer的allocate就是native order。所以問題應該出在direct這裏,這裏Buffer有兩個要求,一個是native order,另一個是direct Buffer。
我們可以從FloatBuffer的描述中發現,確實是direct Buffer的問題。有且僅有從direct的ByteBuffer轉換到FloatBuffer纔是direct的。再去查看ByteBuffer的方法函數,發現它有兩個allocate作用的函數,allocateDirect()就是我們需要的。
再查看ByteBuffer的其他方法的話,可以發現它也有兩個order()函數,一個是用於查詢,一個是用於修改,而FloatBuffer只有一個用於查看字節序的方法。
所以爲了保險起見,我們最好使用ByteBuffer.order()設置order爲native order。
這時候就清楚了,由於Must use a native order direct Buffer這個要求,我們需要先用ByteBuffer創建Direct緩存區,並保證order爲native order,再轉換成FloatBuffer,最後傳入數據即可。
###
我們就已經將頂點數據傳入了Buffer,在創造三角形的時候,我們還可以添加顏色等信息,所以在類中可以再加入一些信息。
最後創造三角形的代碼如下
public class Triangle {
private FloatBuffer vertexBuffer;
// 數組中每個頂點的座標數(即維數)
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
};
// 顏色信息,分別是RGB和alpha通道的歸一化值
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Triangle() {
// 初始化頂點數據Buffer
ByteBuffer bb = ByteBuffer.allocateDirect(
// (一個float型4字節)
triangleCoords.length * 4);
// 字節序使用native order
bb.order(ByteOrder.nativeOrder());
// 將ByteBuffer轉換爲浮點型FloatBuffer
vertexBuffer = bb.asFloatBuffer();
// 將頂點數據添加到Buffer
vertexBuffer.put(triangleCoords);
// Buffer位置調整到開頭
vertexBuffer.position(0);
}
}
接下來就是將這個三角形輸出顯示到屏幕上了!