Android视频采集渲染学习(4)
EBO(IBO)和VAO的使用;代码中注释掉了EBO的部分使用;最终执行的是VAO套用VBO的代码


https://blog.csdn.net/qq_36383623/article/details/85144685
(图片和代码学习来源于慕课网李超,如有侵权请及时联系)第一部分是VAO套VBO的例子
package com.example.glestest import android.opengl.GLES30 import android.opengl.Matrix import androidx.core.graphics.translationMatrix import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.FloatBuffer class triangre { private var program = 0; private var positionHandle = 0; private var colorHandle = 0; private var matrixHandle = 0; //着色器 private val vertexShaderCode = "uniform mat4 mTMatrix; " + "attribute vec4 vPosition;" + "void main() {" + " gl_Position = mTMatrix * vPosition;" + "}" private val fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}" //顶点坐标(系统坐标系 -1~1) private val triangleCoords = floatArrayOf( 0.0f, 0.5f, 0.0f,//左上 -0.5f, -0.5f, 0.0f,//左下 0.5f, -0.5f, 0.0f, //右下 1.0f, 0.5f, 0.0f //右上 ) private val color = floatArrayOf(0.5f, 0.5f, 0.5f, 1.0f)//颜色数据 //变换矩阵 private var vertex_matrix = FloatArray(16); private lateinit var vertexBuf:FloatBuffer; //vbO vertex vuffer obj private var VBOid = IntArray(1); //EBO private var EBOid = IntArray(1); //顶点索引 private var EBOindex = intArrayOf(0,1,2,2,3,0); //VAO private var VAOid =IntArray(1); private fun loadshader(type: Int,shadercode:String):Int{ val shader =GLES30.glCreateShader(type); GLES30.glShaderSource(shader,shadercode); GLES30.glCompileShader(shader); return shader; } constructor(){ //分配GPU可访问内存的操作是用ByteBuffer.allocate分配一段Native内存(直接缓冲),GPU 可以直接访问(DMA) // 他是直接内存,不是VBO val buf = ByteBuffer.allocateDirect(triangleCoords.size*4);//开辟空间;顶点数据 buf.order(ByteOrder.nativeOrder());//设置字节序 vertexBuf =buf.asFloatBuffer();//只是转成float存储访问,但是数据仍然会存在buf中,所以VBO方式用的是buf vertexBuf.put(triangleCoords);//CPU 拷贝到GPU(拷贝到直接缓冲,是一个GPU可以访问的存储,但是不是GPU) vertexBuf.position(0);//从头读数据 var indexbuf= ByteBuffer.allocateDirect(EBOindex.size*4).order(ByteOrder.nativeOrder()).asIntBuffer();//索引缓冲 indexbuf.put(EBOindex).position(0); Matrix.setIdentityM(vertex_matrix,0); // Matrix.translateM(vertex_matrix,0,0.5f,0f,0f);//平移 Matrix.scaleM(vertex_matrix, 0, 0.5f, 0.5f,1.0f);//缩放 //创建着色器,指定源码,编译,绑定(attach),链接 val vertexShader = loadshader(GLES30.GL_VERTEX_SHADER,vertexShaderCode); val fregmentShader = loadshader(GLES30.GL_FRAGMENT_SHADER,fragmentShaderCode); //绑定 program = GLES30.glCreateProgram(); GLES30.glAttachShader(program,vertexShader); GLES30.glAttachShader(program,fregmentShader); //链接 GLES30.glLinkProgram(program); //VAO GLES30.glGenVertexArrays(1,VAOid,0); GLES30.glBindVertexArray(VAOid[0]) //VBO 生成,绑定,数据拷贝,使用 GLES30.glGenBuffers(1,VBOid,0); GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,VBOid[0]); GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,buf.capacity(),buf,GLES30.GL_STATIC_DRAW);//一次拷贝 //glVertexAttribPointer将拷贝到VBO中的数据传给VAO--------------这段代码如果不使用VAO是放在draw里的-----放在这个位置是为了绑定VAO与VBO--------------------------------- //数据传给着色器 positionHandle= GLES30.glGetAttribLocation(program,"vPosition");//接入点 GLES30.glEnableVertexAttribArray(positionHandle);//从GPU中读取数据;最后一个参数是0就去GPU中找数据 //这句话让我们使用VAO时候相当于使用里边的VBO的数据 GLES30.glVertexAttribPointer(positionHandle,3,GLES30.GL_FLOAT,false,0,0); //-------------------------------------------------------------------------------------- //解绑 GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0); //解绑VAO GLES30.glBindVertexArray(0); // //生成EBO绑定 // GLES30.glGenBuffers(1,EBOid,0); // GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,EBOid[0]); // GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexbuf.capacity()*4,indexbuf,GLES30.GL_STATIC_DRAW);//一次拷贝 // //解绑 // GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0); } fun Draw(){ //使用program GLES30.glUseProgram(program); //再次指定绑定的VBO // GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,VBOid[0]); // GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,EBOid[0]); GLES30.glBindVertexArray(VAOid[0]) matrixHandle = GLES30.glGetUniformLocation(program,"mTMatrix") GLES30.glUniformMatrix4fv(matrixHandle,1,false,vertex_matrix,0); colorHandle =GLES30.glGetUniformLocation(program,"vColor"); GLES30.glUniform4fv(colorHandle,1,color,0) //VBO绘制 //GLES30.glDrawArrays(GLES30.GL_TRIANGLES,0,triangleCoords.size/3); //EBO 绘制 //GLES30.glDrawElements(GLES30.GL_TRIANGLES,EBOindex.size,GLES30.GL_UNSIGNED_INT,0); //VAO绘制 GLES30.glDrawArrays(GLES30.GL_TRIANGLES,0,triangleCoords.size/3) //释放顶点资源 //GLES30.glDisableVertexAttribArray(positionHandle); //解绑 //GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0); //GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0); GLES30.glBindVertexArray(0) } }
package com.example.glestest import android.opengl.GLSurfaceView import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import com.example.android.camera2.myglsurfaceview.MyGLSurfaceView class MainActivity : AppCompatActivity() { private lateinit var glview:GLSurfaceView; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) glview =MyGLSurfaceView(this) setContentView(/* view = */ this.glview) } }
package com.example.android.camera2.myglsurfaceview import android.content.Context import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.opengles.GL10 import android.opengl.GLES30 import android.opengl.GLSurfaceView import com.example.glestest.triangre class MyGLSurfaceView : GLSurfaceView { constructor(context: Context) : super(context) { //使用的OpenGL ES 版本 setEGLContextClientVersion(3) //为GLSurfaceView设置Renderer,在该函数中会启动一个新的线程来构造EGL环境 setRenderer(MyGLRenderer()) } } class MyGLRenderer : GLSurfaceView.Renderer { private lateinit var trangle:triangre; override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { //设置OpenGL ES清屏色为红色, R,G,B,A GLES30.glClearColor(1.0f, 1.0f, 1.0f, .5f) trangle =triangre(); } override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { //设置OpenGLES的视口大小 GLES30.glViewport(0, 0, width, height) } override fun onDrawFrame(gl: GL10?) { //清空当前缓冲区的颜色缓冲区 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT) trangle.Draw(); } }
下边的代码是使用VBO和EBO的例子:
注意顶点的index在顶点数据中;这个index不是EBO的序号
注意这里使用6个顶点是为了避免4个顶点的时候有两个顶点是复用的导致绘制颜色异常
vColor在顶点着色器中指定颜色,varying变量会在片元着色中进行颜色的绘制
package com.example.glestest
import android.opengl.GLES30
import android.opengl.Matrix
import androidx.core.graphics.translationMatrix
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
class triangre {
private var program = 0;
private var positionHandle = 0;
private var matrixHandle = 0;
private var aIndexHandle = 0;
//着色器
private val vertexShaderCode =
"uniform mat4 mTMatrix; " +
"attribute vec4 vPosition;" +
"attribute float aIndex ;"+
" varying vec4 vColor;" +
"void main() {" +
" gl_Position = mTMatrix * vPosition;" +
" if(aIndex < 0.5){"+
"vColor = vec4(0.0,0.0,1.0,1.0);"+
"}else{" +
" vColor =vec4(1.0,0.0,1.0,1.0);" +
"}"+
"}"
private val fragmentShaderCode =
"precision mediump float;" +
" varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}"
//顶点坐标(系统坐标系 -1~1)
private val triangleCoords = floatArrayOf(
0.0f, 0.5f, 0.0f, 0.0f,//左上 //第四个数字是aindex
-0.5f, -0.5f, 0.0f, 0.0f,//左下
0.5f, -0.5f, 0.0f, 0.0f,//右下
1.0f, 0.5f, 0.0f , 1.0f,//右上
0.0f, 0.5f, 0.0f,1.0f,//左上
0.5f, -0.5f, 0.0f, 1.0f,//右下
)
private val color = floatArrayOf(0.5f, 0.5f, 0.5f, 1.0f)//颜色数据
//变换矩阵
private var vertex_matrix = FloatArray(16);
private lateinit var vertexBuf:FloatBuffer;
//vbO vertex vuffer obj
private var VBOid = IntArray(1);
//EBO
private var EBOid = IntArray(1);
//顶点索引
private var EBOindex = intArrayOf(0,1,2,3,4,5);//使用6个节点是为了避免复用节点无法分开颜色
private fun loadshader(type: Int,shadercode:String):Int{
val shader =GLES30.glCreateShader(type);
GLES30.glShaderSource(shader,shadercode);
GLES30.glCompileShader(shader);
return shader;
}
constructor(){
//分配GPU可访问内存的操作是用ByteBuffer.allocate分配一段Native内存(直接缓冲),GPU 可以直接访问(DMA)
// 他是直接内存,不是VBO
val buf = ByteBuffer.allocateDirect(triangleCoords.size*4);//开辟空间;顶点数据
buf.order(ByteOrder.nativeOrder());//设置字节序
vertexBuf =buf.asFloatBuffer();//只是转成float存储访问,但是数据仍然会存在buf中,所以VBO方式用的是buf
vertexBuf.put(triangleCoords);//CPU 拷贝到GPU(拷贝到直接缓冲,是一个GPU可以访问的存储,但是不是GPU)
vertexBuf.position(0);//从头读数据
var indexbuf= ByteBuffer.allocateDirect(EBOindex.size*4).order(ByteOrder.nativeOrder()).asIntBuffer();//索引缓冲
indexbuf.put(EBOindex).position(0);
Matrix.setIdentityM(vertex_matrix,0);
//创建着色器,指定源码,编译,绑定(attach),链接
val vertexShader = loadshader(GLES30.GL_VERTEX_SHADER,vertexShaderCode);
val fregmentShader = loadshader(GLES30.GL_FRAGMENT_SHADER,fragmentShaderCode);
//绑定
program = GLES30.glCreateProgram();
GLES30.glAttachShader(program,vertexShader);
GLES30.glAttachShader(program,fregmentShader);
//链接
GLES30.glLinkProgram(program);
//VBO 生成,绑定,数据拷贝,使用
GLES30.glGenBuffers(1,VBOid,0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,VBOid[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,buf.capacity(),buf,GLES30.GL_STATIC_DRAW);//一次拷贝
//glVertexAttribPointer将拷贝到VBO中的数据传给VAO----------------------------------------------------
//数据传给着色器
positionHandle= GLES30.glGetAttribLocation(program,"vPosition");//接入点
GLES30.glEnableVertexAttribArray(positionHandle);
//index
aIndexHandle =GLES30.glGetAttribLocation(program,"aIndex");
GLES30.glEnableVertexAttribArray(aIndexHandle);
matrixHandle = GLES30.glGetUniformLocation(program,"mTMatrix")
//生成EBO绑定
GLES30.glGenBuffers(1,EBOid,0);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,EBOid[0]);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,indexbuf.capacity()*4,indexbuf,GLES30.GL_STATIC_DRAW);//一次拷贝
//解绑
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);
//解绑
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);
}
fun Draw(){
//使用program
GLES30.glUseProgram(program);
//再次指定绑定的VBO
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,VBOid[0]);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,EBOid[0]);
//从头(offset)开始读取,每次读取3个数【每个数4字节】(size);然后跳16个字节(4个float)
GLES30.glVertexAttribPointer(positionHandle,3,GLES30.GL_FLOAT,false,16,0);
//顶点数组每行的最后一个数字是aindex,aindex读数据规则
GLES30.glVertexAttribPointer(aIndexHandle,1,GLES30.GL_FLOAT,false,16,12);
GLES30.glUniformMatrix4fv(matrixHandle,1,false,vertex_matrix,0);
//EBO 绘制
GLES30.glDrawElements(GLES30.GL_TRIANGLES,EBOindex.size,GLES30.GL_UNSIGNED_INT,0);
//解绑
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER,0);
}
}

如果我们还是使用4个顶点绘制两个不同颜色的三角形的时候,交界处是这样的:
//顶点索引
private var EBOindex = intArrayOf(0,1,2,2,3,0);

浙公网安备 33010602011771号