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);

 

posted on 2025-04-18 00:38  邗影  阅读(22)  评论(0)    收藏  举报

导航