VBO
Vertex Buffer object
為什么要用VBO
不使用VBO時,我們每次繪制( glDrawArrays )圖形時都是從本地內存處獲取頂點數(shù)據(jù)然后傳輸給OpenGL來繪制,這樣就會頻繁的操作CPU->GPU增大開銷,從而降低效率。
使用VBO,我們就能把頂點數(shù)據(jù)緩存到GPU開辟的一段內存中,然后使用時不必再從本地獲取,而是直接從顯存中獲取,這樣就能提升繪制的效率。
創(chuàng)建VBO的主要步驟:
//1. 創(chuàng)建VBO得到vboId
int[] vbos = new int[1];
GLES20.glGenBuffers(1, vbos, 0);
vboId = vbos[0];
//2. 根據(jù)id綁定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
//3. 分配VBO需要的緩存大小
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertex.length * 4,null, GLES20. GL_STATIC_DRAW);
//4. 為VBO設置頂點數(shù)據(jù)的值
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
//5. 解綁VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
使用VBO的主要步驟:
//1. 根據(jù)id綁定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
//2. 設置頂點數(shù)據(jù)
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, 0);
//3. 解綁VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
我使用繪制圖片紋理的代碼來進行改造為VBO,OpenGLES 繪制圖片紋理
改造的只有BitmapTexture這個類
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
//紋理 根據(jù)坐標系映射
public class BitmapTexture {
//頂點坐標
static float vertexData[] = { // in counterclockwise order:
-1f, -1f, 0.0f, // bottom left
1f, -1f, 0.0f, // bottom right
-1f, 1f, 0.0f, // top left
1f, 1f, 0.0f, // top right
};
//紋理坐標 對應頂點坐標 與之映射
static float textureData[] = { // in counterclockwise order:
0f, 1f, 0.0f, // bottom left
1f, 1f, 0.0f, // bottom right
0f, 0f, 0.0f, // top left
1f, 0f, 0.0f, // top right
};
//每一次取點的時候取幾個點
static final int COORDS_PER_VERTEX = 3;
private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;
//每一次取的總的點 大小
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private Context context;
//位置
private FloatBuffer vertexBuffer;
//紋理
private FloatBuffer textureBuffer;
private int program;
private int avPosition;
//紋理位置
private int afPosition;
//紋理id
private int textureId;
//vbo id
private int vboId;
public BitmapTexture(Context context) {
this.context = context;
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureData);
textureBuffer.position(0);
}
public void onSurfaceCreated() {
String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);
String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);
program = ShaderUtil.createProgram(vertexSource, fragmentSource);
if (program > 0) {
//獲取頂點坐標字段
avPosition = GLES20.glGetAttribLocation(program, "av_Position");
//獲取紋理坐標字段
afPosition = GLES20.glGetAttribLocation(program, "af_Position");
//創(chuàng)建vbo
createVBO();
int[] textureIds = new int[1];
//創(chuàng)建紋理
GLES20.glGenTextures(1, textureIds, 0);
if (textureIds[0] == 0) {
return;
}
textureId = textureIds[0];
//綁定紋理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
//環(huán)繞(超出紋理坐標范圍) (s==x t==y GL_REPEAT 重復)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//過濾(紋理像素映射到坐標點) (縮小、放大:GL_LINEAR線性)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.bg);
if (bitmap == null) {
return;
}
//設置紋理為2d圖片
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}
}
public void draw() {
//使用程序
GLES20.glUseProgram(program);
GLES20.glEnableVertexAttribArray(avPosition);
GLES20.glEnableVertexAttribArray(afPosition);
//直接設置
// 設置頂點位置值
// GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
//設置紋理值
// GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);
//使用vbo設置
useVboDraw();
//繪制 GLES20.GL_TRIANGLE_STRIP:復用坐標
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
GLES20.glDisableVertexAttribArray(avPosition);
GLES20.glDisableVertexAttribArray(afPosition);
}
private void createVBO() {
//1. 創(chuàng)建VBO
int[] vbos = new int[1];
GLES20.glGenBuffers(vbos.length, vbos, 0);
vboId = vbos[0];
//2. 綁定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
//3. 分配VBO需要的緩存大小
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4 + textureData.length * 4, null, GLES20.GL_STATIC_DRAW);
//4. 為VBO設置頂點數(shù)據(jù)的值
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, textureData.length * 4, textureBuffer);
//5. 解綁VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
private void useVboDraw() {
//1. 綁定VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
//2. 設置頂點數(shù)據(jù)
GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, 0);
GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexData.length * 4);
//3. 解綁VBO
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
}