OpenGL ES 索引缓冲区(4)

news2024/12/27 1:51:08

OpenGL ES 索引缓冲区(4)

简述

本节会介绍索引缓冲区,索引缓冲区和顶点缓冲区类似,也是显存上的一段内存,只不过上面的数据用处不同,索引缓冲区故名思义里面的数据是用于索引,主要作用是用于复用顶点缓冲区里的数据。
我们之前说过OpenGL渲染都是渲染三角形,如果我们想渲染一个正方形,就要通过渲染两个三角形,拼接成一个正方形,那么这两个三角形有两个顶点是重合的,如果没有索引缓冲区,两个三角形则需要六个顶点,而实际上一个正方形只有四个顶点,这里有两个顶点时数据冗余。仅仅一个正方形就有这么多冗余,那么一个复杂的游戏场景就会浪费非常多的内存。
下面我们就以渲染一个正方形为例来使用索引缓冲区。

接口使用

索引缓冲区的接口使用方式和顶点缓冲区类似,只不过参数不同,这里使用的GL_ELEMENT_ARRAY_BUFFER表示索引缓冲区。

GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, bufferId);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER,
                    size,
                    data,
                    type);

glDrawElements是用于渲染索引缓冲区,第一个和其他DrawCall一样,第二个参数是count,表示有多少顶点需要渲染,第三个参数是索引缓冲区参数类型,必须是GLES30.GL_UNSIGNED_SHORT或者GL_UNSIGNED_BYTE,第四个参数是offset。

GLES30.glDrawElements(GLES30.GL_TRIANGLES, count, type, offset)

不使用索引缓冲区渲染正方形

配置顶点数据

顶点数据如下,6个顶点。我我们可以发现第3个和第5个是一样的,第2个和第4个是一样的。

private float[] vertexArray = new float[] {
        -0.25f, -0.25f, 0.0f,
        0.25f, -0.25f, 0.0f,
        -0.25f, 0.25f, 0.0f,
        0.25f, -0.25f, 0.0f,
        -0.25f, 0.25f, 0.0f,
        0.25f, 0.25f, 0.0f,
};

配置着色器

着色器和我们三角形demo的时候基本是一样的,通过一个统一变量来控制颜色。

private final String vertexShaderCode =
        "attribute vec4 vPosition;" +
                "void main() {" +
                "  gl_Position = vPosition;" +
                "}";

private final String fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() {" +
                "  gl_FragColor = vColor;" +
                "}";

配置顶点缓冲区数据和布局

onSurfaceCreated中填充顶点缓冲区的数据以及加载着色器的逻辑和绘制三角形的时候一样。

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    // 清除颜色
    GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    // 创建顶点缓冲区
    int[] idBuffer = new int[1];
    GLES30.glGenBuffers(1, idBuffer, 0);
    vertexBufferId = idBuffer[0];

    // 顶点缓冲区数据填充
    FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    vertexBuffer.put(vertexArray);
    vertexBuffer.position(0);

    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);
    GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            vertexArray.length * 4,
            vertexBuffer,
            GLES30.GL_STATIC_DRAW
    );
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

    // shader
    shaderProgramId = initShaderProgram(vertexShaderCode, fragmentShaderCode);
}

onDrawFrame方法中其他的基本和绘制三角形的时候一样,参数布局其实也是一样的,变化的只有glDrawArrays中count变成了6个顶点。

public void onDrawFrame(GL10 gl) {
    // 清除屏幕
    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
    // 使能着色器程序
    GLES30.glUseProgram(shaderProgramId);

    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);
    int positionLocation = GLES30.glGetAttribLocation(shaderProgramId, "vPosition");

    GLES30.glEnableVertexAttribArray(positionLocation);
    // 告诉GPU顶点缓冲区的布局情况,即那些数据的意义是什么。
    GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 0, 0);

    // 配置统一变量,用于CPU和GPU通信的
    int colorLocation = GLES30.glGetUniformLocation(shaderProgramId, "vColor");
    GLES30.glUniform4f(colorLocation, 1.0f, 1.0f, 1.0f, 1.0f);

    // 调用DrawCall绘制三角形
    GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 6);

    // 清除配置
    GLES30.glDisableVertexAttribArray(positionLocation);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
    GLES30.glUseProgram(0);
}

效果

渲染图像看起来不是正方形,而是长方形,是因为OpenGL的坐标比例是按照屏幕显示的比例,我们的手机屏幕是长方形的,所以按照比例也是长方形的。

在这里插入图片描述

使用索引缓冲区

我们前面看到了渲染这个正方形我们使用了6个顶点,而其中有2个顶点是重复的,我们使用索引缓冲区可以复用顶点。

配置顶点数据

顶点数据如下,indexArray为索引缓冲区的数据,必须要short或者byte类型。
这里索引缓冲区就是表示第一个三角形使用的顶点缓冲区中0,1,2号顶点,第二个三角形使用顶点缓冲区中1,2,3号顶点。

private float[] vertexArray = new float[] {
        -0.25f, -0.25f, 0.0f,
        0.25f, -0.25f, 0.0f,
        -0.25f, 0.25f, 0.0f,
        0.25f, 0.25f, 0.0f,
};

private short[] indexArray = new short[] {
        0,1,2,
        1,2,3
};

配置顶点缓冲区数据和布局

着色器和之前一样,顶点缓冲区配置修改如下,除了申请顶点缓冲区之外还申请了索引缓冲区。

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    // 清除颜色
    GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    // 申请两个缓冲区,一个作为顶点缓冲区,一个座位索引缓冲区
    int[] idBuffer = new int[2];
    GLES30.glGenBuffers(2, idBuffer, 0);
    vertexBufferId = idBuffer[0];
    elementBufferId = idBuffer[1];

    // 顶点缓冲区数据填充
    FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexArray.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    vertexBuffer.put(vertexArray);
    vertexBuffer.position(0);

    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);
    GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER,
            vertexArray.length * 4,
            vertexBuffer,
            GLES30.GL_STATIC_DRAW
    );
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

    // 索引缓冲区数据填充,类型必须为short/byte
    ShortBuffer indexBuffer = ByteBuffer.allocateDirect(indexArray.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer();
    indexBuffer.put(indexArray);
    indexBuffer.position(0);
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);
    GLES30.glBufferData(
            GLES30.GL_ELEMENT_ARRAY_BUFFER,
            indexArray.length * 4,
            indexBuffer,
            GLES30.GL_STATIC_DRAW
    );
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);

    // shader
    shaderProgramId = initShaderProgram(vertexShaderCode, fragmentShaderCode);
}

通过GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId)绑定索引缓冲区,然后调用glDrawElements来进行绘制。

public void onDrawFrame(GL10 gl) {
    // 清除屏幕
    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
    // 使能着色器程序
    GLES30.glUseProgram(shaderProgramId);

    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexBufferId);
    int positionLocation = GLES30.glGetAttribLocation(shaderProgramId, "vPosition");

    GLES30.glEnableVertexAttribArray(positionLocation);
    // 告诉GPU顶点缓冲区的布局情况,即那些数据的意义是什么。
    GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 0, 0);

    // 配置统一变量,用于CPU和GPU通信的
    int colorLocation = GLES30.glGetUniformLocation(shaderProgramId, "vColor");
    GLES30.glUniform4f(colorLocation, 1.0f, 1.0f, 1.0f, 1.0f);
    // 绑定索引缓冲区
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, elementBufferId);
    // 调用DrawCall绘制三角形
    GLES30.glDrawElements(GLES30.GL_TRIANGLES, 6, GLES30.GL_UNSIGNED_SHORT, 0);

    // 清除配置
    GLES30.glDisableVertexAttribArray(positionLocation);
    GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);
    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
    GLES30.glUseProgram(0);
}

效果

和之前一样。
在这里插入图片描述

小结

索引缓冲区里面就是存储了一系列索引,用于复用顶点缓冲区。
有个问题,大家可能会想之前用6个顶点也不过18个数,使用了顶点缓冲区后变为12个,但是索引缓冲区还有6个,好像没有节省多少内存。
但是实际上顶点可能包含了非常多的数据,比如我们之前用它来存颜色,它还可以存纹理等额外数据,实际应用场景一个顶点可能有非常多数据,所以复用可节省的内存是非常可观的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kd-tree介绍和使用

GeoHash原理介绍以及在redis中的应用-CSDN博客 这边文章中介绍了GeoHash编码原理以及它的一个应用——利用GeoHash编码可以建立一个索引,从而实现快速的空间搜索。今天,我们介绍一个常见的数据结构Kd-Tree,利用它也可以快速实现多位数据的搜索…

调用智谱AI,面试小助手Flask简单示例

文章目录 1.接入AI获取API密钥Python代码 2.小助手的实现流程3.Flask应用示例Python文件.pyindex.html运行Flask应用地址栏输入 http://localhost:5000/ 1.接入AI 获取API密钥 在智谱AI的官方网站上注册,右上角点击API密钥,新建并复制一个 API Key&…

掌握未来:产品经理学习AI大模型的重要性解析

前言 在AI大模型时代,技术的迅猛进步正在重塑各行各业的面貌。作为产品经理,我们不仅要紧跟时代步伐,更要深入探索与运用这一前沿技术。学习大模型等AI技术,不仅是为了理解其背后的工作原理和应用潜力,更是为了将智能…

天选思路怎能不会!小波变换+CNN完美融合,最新idea发了CV顶会!

今天给大家推荐一个涨点发顶会的好方向:小波变换CNN。这俩热点的结合可以轻松实现“11>2”的效果。 这是因为,一方面小波变换可以作为预处理步骤,提取出关键的局部特征,加速CNN收敛并提升性能;另一方面&am…

配置树莓派打开SSH服务

在树莓派终端中查看IP 在终端中输入命令来查看IP地址。最常用的命令是:hostname -I注意,这里的参数I是大写的,它表示查看本机上所有配置的IP地址(包括IPv4和IPv6,如果有的话)。如果你只需要查看IPv4地址&am…

Linux:磁盘管理

一、静态分区管理 静态的分区方法不可以动态的增加或减少分区的容量。 1、磁盘分区-fdisk 该命令是用于查看磁盘分区情况,和分区管理的命令 命令格式:fdisk [选项] 设备文件名常用命令: -h:查看分区信息 fdisk系统常用命令&…

19、网络安全合规复盘

数据来源:5.网络安全合规复盘_哔哩哔哩_bilibili

山大电力研发费用率远弱同行,先分红上亿再补流9000万?

《港湾商业观察》施子夫 8月9日,证监会网站披露深交所已向山东山大电力技术股份有限公司(以下简称,山大电力)发出第三轮审核问询函。据悉,2023年6月,山大电力递表深交所,保荐机构为兴业证券。 …

Linux中find命令详解

记录linux中find命令的详细用法。 文章目录 find命令简介基本语法常用选项-name-iname-type-size-mtime,-atime,-ctime-perm-user-group-delete-exec-printand or find --help find命令简介 find 是一个搜索目录树以查找一个文件或一组文件的程序。它遍历目录树并报告与用户规…

VMware虚拟机NAT模式配置

1、宿主机 2、宿主机网络适配器 VMnet8 ①要与虚拟机在同一网段 ②不能和宿主机同一网段 3、VMware 4、虚拟机

短视频剪辑工具有哪些?推荐4个简单好用的工具

短视频如今充斥着我们的生活,刷短视频已经成了很多人的生活必备。所以掌握短视频剪辑技能是一件很重要的事情,能够为视频创作者带来很多的流量。如果想要学习剪辑的话,可以先从选择一款合适的剪辑工具开始,这几款功能丰富的软件&a…

Google ads投广中的这些问题,看你中了没

谷歌广告是一个强大的工具,可以显著提升外贸独立站的流量和销售。但是,要想充分发挥其潜力,需要深入了解其工作原理,并掌握如何设定预算、选择关键词、创建广告文案等技巧。以下是一些在谷歌广告投放过程中网友遇到的一些问题及其…

基于ESP8266—AT指令连接阿里云+MQTT透传数据(1)

在阿里云创建MQTT产品的过程涉及几个关键步骤,主要包括注册阿里云账号、实名认证、开通MQTT服务实例、创建产品与设备等。以下是详细的步骤说明: 一、准备工作 访问阿里云官网,点击注册按钮,填写相关信息(如账号、密码、手机号等)完成注册。注册完成后,需要对账号进行实…

Solaris11.4配置远程桌面登录

Solaris11.4配置远程桌面登录 一. 版本信息 1. 内核版本信息 rootsolaris11:~# uname -a SunOS solaris11 5.11 11.4.27.82.1 sun4v sparc sun4v rootsolaris11:~# rootsolaris11:~# rootsolaris11:~# cat /etc/releaseOracle Solaris 11.4 SPARCCopyright (c) 1983, 2020, …

【EXCEL数据处理】000009 案列 EXCEL单元格数字格式。文本型数字格式和常规型数字格式的区别

前言:哈喽,大家好,今天给大家分享一篇文章!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【EXCEL数据处理】000009 案列 EXCEL单元格数字格式。文本型数字格式和…

2024年国外优质API:情绪识别口碑佳

随着全球一体化进程的加速,跨语言沟通需求提升,进而催生出大量语种识别类型API服务。此类服务致力于协助使用者便捷且精确地辨识文本所属的语种,从而实现各类多语言文本处理、自动化翻译及文本解析等功能。 目前,市面上已出现多种…

麒麟服务器装完系统后删除backup以及swap分区的操作步骤

一、需求描述 将V10-SP3服务器的klas-backup、klas-swap两个lvm分区删除掉。 现场原来lvm结构如下: 二、注意事项 在缩减lvm前,必须做好数据备份。 三、操作步骤 1、执行vgs、lvs查看vg、lv [root@server-sp3 ~]# vgsVG #PV #LV #SN Attr VSize VFreeklas 1 3 …

微服务——服务保护

1.雪崩问题 级联失败或雪崩问题指的是在微服务架构中,由于服务间的相互依赖和调用,当一个服务出现故障时,会引起调用它的服务也出现故障,进而引发整个调用链路的多个服务都出现故障,最终导致整个系统崩溃的现象。 产生…

阿里巴巴国际站获取商品详情item_get接口技术分享

在跨境电商日益繁荣的今天,如何高效、准确地获取商品信息成为了商家们关注的焦点。阿里巴巴作为全球领先的B2B电商平台,其提供的item_get API接口成为了跨境电商获取商品信息的必备工具。本文将详细介绍item_get接口的功能、优势、应用场景以及返回数据字…

yolov5/v7/v8随机种子固定方法

参考:https://blog.csdn.net/qq_45062768/article/details/133852543 https://blog.csdn.net/qq_45062768/article/details/133204618 yolov7的 import pkg_resources as pkg def check_version(current0.0.0, minimum0.0.0, nameversion , pinnedFalse, hardFal…