OpenGl(四) 提升Shader性能--VBO、EBO、VAO之VBO

什么是VBO

Vertex Buffer Object顶点缓冲对象,用于在GPU中存储数据,加速渲染过程。
优点:(1)减少CPU到GPU数据的传输,提高渲染效率(举例渲染三角形,需要知道顶点+颜色,这些数据都在cpu,如果模型复杂,每次都需要时才拷贝数据,因此这里使用VBO会将数据进行一次性拷贝到GPU,使用时直接从GPU存储空间获取数据,进行渲染)
(2)数据保存在GPU,可重复使用
(3)可以直接在GPU对数据进行转换,减少GPU负载

使用VBO基本步骤

  • 生成VBO对象并进行绑定
  • 将顶点数据赋值到VBO对象中
  • 绘制几何图元,从VBO中读取数据进行处理
  • 解绑VBO对象(因为数据都在GPU中,因此需要使用之后进行释放GPU空间,否则会耗尽GPU空间)

相关API

  • glGenBuffer,生成VBO (该函数有三个参数,n表示一次生成多少个VBO,buffers,存放生成好的VBO对象的索引值,offset,目前没什么用,一般设置为0)
  • glBindBuffer,绑定VBO到GPU (该函数有2个参数,target,指定存放的目标数据类型,它是常量,如GL_ARRAY_BUFFER表示用于存储顶点数据, int buffer,绑定的VBO对象ID,解绑定时将第二个参数设置为0)
  • glBufferData,拷贝数据到VBO (该函数有4个参数,target,指定存放的目标数据类型,同glBindBuffer中的target,size指定拷贝数据的大小,data,从哪儿拷贝数据,usage,常量,指定拷贝数据的方式,一般设置为GL_STATIC_DRAW表示一次性拷贝)
  • glVerTexAttribPoint(…,0)从VBO获取数据,最后一个参数必须设置为0

代码示例

class DemoVBOGlRender : GLSurfaceView.Renderer {
    /*
     * 顶点位置程序
     */
    private val vertexShaderCode =
        "attribute vec4 vPosition;" +
                "void main() { " +
                "   gl_Position = vPosition;" +
                "}"

    /**
     * 片元颜色程序
     */
    private val fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() { " +
                "   gl_FragColor = vColor;" +
                "}"
    /**
     * 三角形顶点位置
     */
    private val triangleCoors = floatArrayOf(
        0.5f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f
    )

    /**
     * 三角形颜色值
     */
    private val color = floatArrayOf(
        1.0f, 1.0f, 1.0f, 1.0f
    )

    private var program: Int? = null
    private var vertexBuffer: FloatBuffer? = null
    private lateinit var byteBuffer: ByteBuffer
    private var vboIds = IntArray(1)

    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
        // 设置背景颜色
        GLES20.glClearColor(1f, 0f, 0f, 1.0f)
        // 清理缓存
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        createFloatBuffer()
        // 创建定点着色程序
        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        // 创建片元着色程序
        val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        if (vertexShader != 0 && fragmentShader != 0) {
            linkProgram(vertexShader, fragmentShader)
            // VBO 需要在linkProgram之后再使用VBO,原因是管线渲染顺序
            // glGenBuffer,生成VBO  n表示一次生成多少个VBO,buffers,存放生成好的VBO对象的索引值,offset,目前没什么用,一般设置为0
            GLES20.glGenBuffers(1, vboIds, 0)
            // glBindBuffer,绑定VBO到GPU (该函数有2个参数,target,指定存放的目标数据类型,它是常量,如GL_ARRAY_BUFFER表示用于存储顶点数据,  int buffer,绑定的VBO对象ID,解绑定时将第二个参数设置为0)
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboIds[0])
            // glBufferData,拷贝数据到VBO   (该函数有4个参数,target,指定存放的目标数据类型,同glBindBuffer中的target,size指定拷贝数据的大小,data,从哪儿拷贝数据,usage,常量,指定拷贝数据的方式,一般设置为GL_STATIC_DRAW表示一次性拷贝)
            GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, byteBuffer.capacity(), byteBuffer, GLES20.GL_STATIC_DRAW)
            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
        }
    }

    private fun createFloatBuffer() {
        // 申请物理层空间
        byteBuffer = ByteBuffer.allocateDirect(triangleCoors.size * 4).apply {
            this.order(ByteOrder.nativeOrder())
        }
        // 坐标数据转换
        vertexBuffer = byteBuffer.asFloatBuffer()
        vertexBuffer?.put(triangleCoors, 0, triangleCoors.size)
        vertexBuffer?.position(0)
    }

    private fun linkProgram(vertexShader: Int, fragmentShader: Int) {
        // 创建空的opengl es 程序
        program = GLES20.glCreateProgram()
        program?.let {
            // 将顶点着色器加入程序
            GLES20.glAttachShader(it, vertexShader)
            // 将片元着色器加入程序
            GLES20.glAttachShader(it, fragmentShader)
            // 链接到着色器程序
            GLES20.glLinkProgram(it)
            // 将程序加入到opengl30环境中
            GLES20.glUseProgram(it)
            val info = GLES20.glGetProgramInfoLog(it)
            // 打印链接程序日志
            Log.e("wdf", "info==" + info)
        }
    }

    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        // 设置绘制窗口
        GLES20.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame(p0: GL10?) {
        program ?: return
        if (program == 0) {
            return
        }
        program?.let {
            GLES20.glClear(GLES30.GL_COLOR_BUFFER_BIT)
            GLES20.glUseProgram(it)
            // 再次绑定VBO,表示从哪个VBO读取
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboIds[0])
            // 获取顶点着色器的vPosition,与程序中声明vPosition变量名保持一致
            val vPosition = GLES20.glGetAttribLocation(it, "vPosition")
            GLES20.glEnableVertexAttribArray(vPosition)
            // 3*4是指  跨3个读下一个顶点
//            GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 3 * 4, vertexBuffer)
            // 最后一个参数设置为0时,会从GPU中读取数据
            GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, 0)


            // 设置三角形颜色,与程序中声明vColor变量名保持一致
            val vColor = GLES20.glGetUniformLocation(it, "vColor")
            GLES20.glUniform4fv(vColor, 1, color, 0)
            // 绘制
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, triangleCoors.size/3)
            GLES20.glDisableVertexAttribArray(vPosition)
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
        }
    }


    /**
     * 创建shader,加载shader程序
     */
    private fun loadShader(type: Int, shaderCode: String): Int {
        val shader = GLES20.glCreateShader(type)
        GLES20.glShaderSource(shader, shaderCode)
        GLES20.glCompileShader(shader)
        return shader
    }

}
class TriangleView : GLSurfaceView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    init {
        setEGLContextClientVersion(2)
        setRenderer(DemoVBOGlRender())
        renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949482.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

导出中心设计

业务背景 应用业务经常需要导出数据,但是并发的导出以及不合理的导出参数常常导致应用服务的内存溢出、其他依赖应用的崩溃、导出失败;因此才有导出中心的设计 设计思想 将导出应用所需的内存转移至导出中心,将导出的条数加以限制&#xf…

构建智能企业:中关村科金大模型企业知识库的技术解析与应用

在数字化转型的浪潮中,企业对智能化知识管理的需求日益增长。知识作为企业的核心资产,其高效管理和应用对于提升企业运营效率和决策质量至关重要。中关村科金大模型企业知识库凭借其强大的技术架构和广泛的应用场景,成为构建智能企业的重要工…

多线程访问FFmpegFrameGrabber.start方法阻塞问题

一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能,其底层利用javacv的FFmpegFrameGrabber进行拉流、推流,进而实现了视频中转。 …

C++11——2:可变模板参数

一.前言 C11引入了可变模板参数(variadic template parameters)的概念,它允许我们在模板定义中使用可变数量的参数。这样,我们就可以处理任意数量的参数,而不仅限于固定数量的参数。 二.可变模板参数 我们早在C语言…

ENSP综合实验(中小型网络)

一、实验背景 在当今数字化的企业环境中,一个稳定、高效且安全的网络架构对于业务的持续运营和发展至关重要。随着企业内部各部门业务的不断拓展,如财务部门对数据保密性要求极高,访客区域的网络接入需求逐渐增多,以及对外提供特定…

nvidia控制面板找不到怎么回事?这有解决方法!

NVIDIA控制面板是一款用于管理和调整NVIDIA显卡的软件,它可以让你优化游戏和图形应用程序的性能和画质,以及设置多显示器、音视频、CUDA等功能。但是,有时候你可能会发现你的电脑上找不到NVIDIA控制面板,这可能是由于以下原因造成…

在Vue3项目中使用svg-sprite-loader

1.普通的svg图片使用方式 1.1 路径引入 正常我们会把项目中的静态资源放在指定的一个目录&#xff0c;例如assets,使用起来就像 <img src"../assets/svgicons/about.svg" /> 1.2封装组件使用 显然上面的这种方法在项目开发中不太适用&#xff0c;每次都需…

html+css+js网页设计 美食 美食3个页面(带js)

htmlcssjs网页设计 美食 美食3个页面(带js) 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&…

【235. 二叉搜索树的最近公共祖先 中等】

题目&#xff1a; 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一…

Visual Studio C++使用笔记

个人学习笔记 右侧项目不显示 CTRL ALT L 创建第一个项目 添加类&#xff08;头文件、CPP文件&#xff09;

【Shell脚本】Docker构建Java项目,并自动停止原镜像容器,发布新版本

本文简述 经常使用docker部署SpringBoot 项目&#xff0c;因为自己的服务器小且项目简单&#xff0c;因此没有使用自动化部署。每次将jar包传到服务器后&#xff0c;需要手动构建&#xff0c;然后停止原有容器&#xff0c;并使用新的镜像启动&#xff0c;介于AI时代越来越懒的…

vulhubn中potato靶场

IP和端口探测 80端口是一个图片 7120端口是这个 使用 hydra爆破密码 使用ssh远程登录 执行exp提权到root成功&#xff0c;找到Flag&#xff01;

复杂园区网基本分支的构建

目录 1、各主机进行网络配置。2、交换机配置。3、配置路由交换&#xff0c;进行测试。4、配置路由器接口和静态路由&#xff0c;进行测试。5、最后测试任意两台主机通信情况 模拟环境链接 拓扑结构 说明&#xff1a; VLAN标签在上面的一定是GigabitEthernet接口的&#xff0c…

信息科技伦理与道德2:研究方法

1 问题描述 1.1 讨论&#xff1f; 请挑一项信息技术&#xff0c;谈一谈为什么认为他是道德的/不道德的&#xff0c;或者根据使用场景才能判断是否道德。判断的依据是什么&#xff08;自身的道德准则&#xff09;&#xff1f;为什么你觉得你的道德准则是合理的&#xff0c;其他…

git理解记录

文章目录 1. 背景2. 基本概念3. 日常工作流程4. 其他常见操作4.1 merge合并操作4.2 tag打标签操作4.3 remoute远程操作4.4 撤销修改 git理解记录 1. 背景 git作为分布式版本控制系统&#xff0c;开源且免费&#xff0c;相比svn集中式版本控制系统存在速度快(HEAD指针指向某次co…

【连续学习之LwM算法】2019年CVPR顶会论文:Learning without memorizing

1 介绍 年份&#xff1a;2019 期刊&#xff1a; 2019CVPR 引用量&#xff1a;611 Dhar P, Singh R V, Peng K C, et al. Learning without memorizing[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2019: 5138-5146. 本文提…

使用Paddledetection进行模型训练【Part1:环境配置】

目录 写作目的 安装文档 环境要求 版本依赖关系 安装说明 写作目的 方便大家进行模型训练前的环境配置。 安装文档 环境要求 PaddlePaddle &#xff1e;&#xff1d;2.3.2OS 64位操作系统Python 3(3.5.1/3.6/3.7/3.8/3.9/3.10)&#xff0c;64位版本pip/pip3(9.0.1)&am…

【51单片机-零基础chapter1】

安装软件(配套的有,不多赘述) 1.管理员身份运行keil和破解软件kegen 将CID代码复制粘贴到 一定要管理员方式,不然会error 插入板子 我的电脑,管理 1.如果是拯救者,查看端口,如果没有则显示隐藏 2.苹果不知道,好像不可以 3.其他电脑在"其他设备找" (注:本人在校已…

现代密码学期末重点(备考ing)

现代密码学期末重点&#xff0c;个人备考笔记哦 密码学概念四种密码学攻击方法什么是公钥密码&#xff1f;什么是对称密码&#xff1f;什么是无条件密码&#xff1f; 中国剩余定理&#xff08;必考&#xff09;什么是原根什么是阶 经典密码学密码体制什么是列置换&#xff1f; …

xinput1_3.dll丢失的解决之道:简单易懂的几种xinput1_3.dll操作方法

在计算机系统和游戏领域中&#xff0c;xinput1_3.dll是一个备受关注的动态链接库文件。它在游戏输入设备的支持和交互方面发挥着至关重要的作用。接下来&#xff0c;我们将详细探讨xinput1_3.dll的各种属性。 一、xinput1_3.dll文件的常规属性介绍 xinput1_3.dll文件名 xinpu…