最近在寫畢設的時候用到OpenGL ES中的VBO,由於對一些接口用到的變量不了解被坑得很慘,在此記錄一下防止以后再被坑。
本文為大便一籮筐的原創內容,轉載請注明出處,謝謝:http://www.cnblogs.com/dbylk/p/4492306.html
使用VBO的好處在此就不多說了,在Java中操作VBO繪圖涉及到的OpenGL接口主要有以下幾個:
1. void glGenBuffers(int n, int[] buffers, int offset)
向OpenGL ES申請開辟新的VBO,並通過buffers數組獲取VBO handle,handle的類型為整型。
int n 申請的VBO個數
int[] buffers 用於存儲VBO handle的數組
int offset buffers數組的偏移量,即從buffers的第offset個位置開始存儲handle
注意需要滿足 n + offset <= buffers.length
2. void glBindBuffer(int target, int buffer)
通過handle綁定指定的VBO,同一時間只能綁定一個同類型的VBO,只有當前被綁定的VBO才會被用戶操作。通過綁定handle為0的VBO,可以取消對所有同類型VBO的綁定。
int target 指定綁定的VBO類型,具體類型有GL_ARRAY_BUFFER(用於為頂點數組傳值)和GL_ELEMENT_ARRAY_BUFFER(用於為索引數組傳值)
int buffer 指定綁定的VBO handle
3. void glBufferData(int target, int size, Buffer data, int usage)
將數據傳遞給當前綁定的VBO。
int target 指定VBO類型,同上
int size 指定VBO的大小,單位為byte
Buffer data 指定需要傳遞的數據
int usage 指定VBO的存儲方式,例如GL_STATIC_DRAW或GL_DYNAMIC_DRAW
4. void glVertexAttribPointer(int indx, int size, int type, boolean normalized, int stride, int offset)
將VBO中的數據傳遞給頂點數組。
int indx 指定Shader屬性的頂點數組handle
int size 指定該屬性的頂點數組大小,單位為數組元素的類型
int type 指定該屬性的頂點數組元素類型,如GL_FLOAT和GL_UNSIGNED_BYTE
boolean normalize 指定傳遞給該屬性頂點數組的數據是否需要歸一化(轉化為單位向量)
int stride 指定該屬性的頂點數據在VBO中的躍度,即每個頂點所占的數據長度,單位為byte
int offset 指定該屬性在VBO中起始位置的偏移量,單位為byte
5. void glDrawArrays(int mode, int first, int count)
直接使用頂點數組繪制圖元。
int mode 指定繪圖的模式,如GL_TRIANGLES和GL_TRIANGLE_STRIP
int first 指定從第幾個頂點開始繪制
int count 指定繪制幾個頂點
本人博客地址,防止無腦抄襲,影響閱讀見諒:http://www.cnblogs.com/dbylk
6. void glDrawElements(int mode, int count, int type, int offset)
使用索引數組繪制圖元。
int mode 指定繪圖的模式,如GL_TRIANGLES和GL_TRIANGLE_STRIP
int count 指定繪制幾個頂點
int type 指定索引數組的數據類型,如GL_UNSIGNED_SHORT和GL_UNSIGNED_INT
int offset 指定索引數組起始位置的偏移量,單位為byte
通過下面的簡單實例中可以了解這些方法在實際操作中如何使用:
// Author DaBianYiLuoKuang. // http://www.cnblogs.com/dbylk/ public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 設置旋轉矩陣的函數,在此可以忽略 setRotationView(0); // 獲取Position屬性的location int positionHandle = GLES20.glGetAttribLocation(programHandle, "Position"); // 獲取SourceColor屬性的location int colorHandle = GLES20.glGetAttribLocation(programHandle, "SourceColor"); // 激活兩個屬性的數組 GLES20.glEnableVertexAttribArray(positionHandle); GLES20.glEnableVertexAttribArray(colorHandle); // 每個頂點的躍度,即一個頂點占有的數據類型個數 int stride = 6; // 頂點數據數組,6個float組成一個頂點,前2個float為位置坐標,后4個float為顏色RGBA float[] data = { -0.5f, -0.5f, 1f, 1f, 1f, 1f, 0.5f, -0.5f, 1f, 1f, 1f, 1f, 0f, 1f, 1f, 1f, 1f, 1f }; // 將頂點數組封裝進Buffer中 // 值得注意的一點是通過Buffer.wrap()方法生成的Buffer無法在OpenGL ES中使用,必須通過如下方法創建Buffer ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length * 4); // OpenGL ES中使用的數據為小端字節序(低位字節在前,高位字節在后),而Java的Buffer默認使用大端字節序(高位字節在前,低位字節在后)存儲數據,所以在此需要通過下面的方法進行轉換 byteBuffer.order(ByteOrder.nativeOrder()); // 將ByteBuffer轉換為FloatBuffer FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); // 將data中的數據放入FloatBuffer中 floatBuffer.put(data); // 重新定義Buffer的起點和終點,等價於同時使用postion(0)方法和limit(data.length)方法 floatBuffer.flip(); // 用於獲取VBO handle的臨時變量 int[] temp = new int[1]; // 向OpenGL申請新的VBO,將handle存於temp中 GLES20.glGenBuffers(1, temp, 0); // 從temp中取出VBO handle vertexBufferHandle = temp[0]; // 綁定剛剛申請到的VBO GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferHandle); // 將FLoatBuffer中的數據傳遞給OpenGL ES GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, floatBuffer.limit() * 4, floatBuffer, GLES20.GL_STATIC_DRAW); // 將VBO中的數據傳遞給shader中的頂點數組 GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, stride * 4, 0); GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, stride * 4, 2 * 4); // 繪制三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); // 取消buffer的綁定 GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); // 反激活頂點數組 GLES20.glDisableVertexAttribArray(positionSlot); GLES20.glDisableVertexAttribArray(colorSlot); }
關於注釋中提到的大端字節序和小端字節序,具體可以查閱下篇博文:
http://www.cnblogs.com/xiehy/archive/2010/11/25/1887779.html