OpenGL ES 索引缓冲区(4)
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);// shadershaderProgramId = 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/byteShortBuffer 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);// shadershaderProgramId = 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个,好像没有节省多少内存。
但是实际上顶点可能包含了非常多的数据,比如我们之前用它来存颜色,它还可以存纹理等额外数据,实际应用场景一个顶点可能有非常多数据,所以复用可节省的内存是非常可观的。
相关文章:
OpenGL ES 索引缓冲区(4)
OpenGL ES 索引缓冲区(4) 简述 本节会介绍索引缓冲区,索引缓冲区和顶点缓冲区类似,也是显存上的一段内存,只不过上面的数据用处不同,索引缓冲区故名思义里面的数据是用于索引,主要作用是用于复用顶点缓冲区里的数据。…...
01:(寄存器开发)点亮一个LED灯
寄存器开发 1、单片机的简介1.1、什么是单片机1.2、F1系列内核和芯片的系统架构1.3、存储器映像1.4、什么是寄存器 2、寄存器开发模板工程3、使用寄存器点亮一个LED4、代码改进15、代码改进2 本教程使用的是STM32F103C8T6最小系统板,教程来源B站up“嵌入式那些事”。…...
.Net 6.0 Windows平台如何判断当前电脑是否联网
最近在工作中开发需要判断当前电脑是否联网的需求,在网上找了一个调用window API来判断本机是否联网。具体请看下面介绍: 1.方法一(调用winAPI) [DllImport("wininet")] public static extern bool InternetGetConnec…...
微软准备了 Windows 11 24H2 ISO “OOBE/BypassNRO“命令依然可用
Windows 11 24H2 可能在未来几周内开始推出。 微软已经要求 OEM 遵循新的指南准备好 Windows 11 24H2 就绪的驱动程序,并且现在已经开始准备媒体文件 (.ISO)。 OEM ISO 的链接已在微软服务器上发布。 一个标有"X23-81971_26100.1742.240906-0331.ge_release_sv…...
MacOS 终端执行安装 Brew
在配置新的 Mac 环境时,如果你发现终端中无法识别 brew 命令,可以按照以下步骤进行解决。 步骤 1:确保网络稳定 为了避免安装过程中出现中断,建议使用 Wi-Fi 或有线连接,不推荐使用移动网络。 步骤 2:打…...
【设计模式-解释模式】
定义 解释器模式是一种行为设计模式,用于定义一种语言的文法,并提供一个解释器来处理该语言的句子。它通过为每个语法规则定义一个类,使得可以将复杂的表达式逐步解析和求值。这种模式适用于需要解析和执行语法规则的场景。 UML图 组成角色…...
51单片机应用开发(进阶)---数码管+按键+蜂鸣器(电磁炉显示模拟)
实现目标 1、加强数码管、按键的学习,实现数码显示变量数据(四位数的显示); 2、4位数码2个按键无源蜂鸣器实现模拟电磁炉功率调节及显示; 一、内容描述 功能描述:1、开机显示电磁炉功率300,每…...
Emergency Stop (ES)
文章目录 1. 介绍2. Feature List3. 紧急停止信号触发方式3.1 Port触发紧急停止信号3.2 SMU事件触发紧急停止信号3.3 软件触发紧急停止信号 4. 应用场景4.1 Port4.2 MSC 1. 介绍 Emergency Stop (ES)是Ifx System Control Units (SCU)六大模块之一。详细信息可以参考Infineon-…...
[C++][第三方库][gtest]详细讲解
目录 1.介绍2.安装3.使用1.头文件包含2.框架初始化接口3.调用测试样例4.TEST宏5.断言宏6.示例 1.介绍 gtest是一个跨平台的C单元测试框架,由Google公司发布gtest是为了在不同平台上为编写C单元测试而生成的,它提供了丰富的断言、致命和非致命判断、参数…...
【Java数据结构】 链表
【本节目标】 1. ArrayList 的缺陷 2. 链表 3. 链表相关 oj题目 一. ArrayList的缺陷 上节课已经熟悉了ArrayList 的使用,并且进行了简单模拟实现。通过源码知道, ArrayList 底层使用数组来存储元素: public class ArrayList<E>…...
前端——Ajax和jQuery
一、Ajax Ajax即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML), 通过 JS 异步的向服务器发送请 求并接收响应数据。 同步访问:当客户端向服务器发送请求时,服务器在处理的过程中,浏览器…...
C++-vector模拟实现
###vector底层相当于是数组,查看源码可以发现,这个类的私有成员变量是三个迭代器;在实现时迭代器就可以当作是vector里面的元素的指针类型; ###vector是一个类模板,实现时也应当按照这样的写法用一个模板去实现&#…...
Activity
69[toc] 1.启停活动页面 1.Activity启动和结束 从当前页面跳到新页面 startActivity(new Intent(this, ActFinishActivity.class));从当前页面返回上一个页面,相当于关闭当前页面 finish();2.Activity生命周期 官方描述生命周期 onCreate:创建活…...
【力扣 | SQL题 | 每日四题】力扣1581, 1811, 1821, 1831
今天的题目就1811这个比较难,其他非常的基础。 1. 力扣1581:进店却未进行过交易的顾客 1.1 题目: 表:Visits ---------------------- | Column Name | Type | ---------------------- | visit_id | int | | customer…...
洛谷【P1955 [NOI2015] 程序自动分析】
反思: 这道题一眼就是并查集 但是数据太大 mle和re都是有可能的我看了题解才知道是离散化数组加并查集离散化再两个月前我觉得好难啊 那道题跟本看不懂 现在觉得还行 离散化思路: 需要一个离散记录数组----ls[N]用来记录下出现的数 步骤: …...
Swift并发笔记
1.同步和异步 说到线程的执行方式,最基本的一组概念是同步和异步。所谓同步,就是在操作执行完成之前,运行操作的这个线程都会被占用,直到函数最终被抛出或返回。Swift5.5之前,func关键字声明的所有的函数都是同步的。…...
React 组件命名规范
在 React 项目中,如果希望保持组件命名的一致性,并防止在引入时出现不同名称的问题,可以遵循以下的组件规范: 1、默认导出组件: 所有特殊要求的组件(如页面组件或根组件)应该使用 export defau…...
eNSP网络配置指南:IP设置、DNS、Telnet、DHCP与路由表管理
1.eNSP基本操作和路由器IP配置命令 登录设备:通过Console口或通过eNSP的Telnet/SSH客户端登录到设备。进入特权模式:输入system-view进入系统视图。接口配置: 进入接口视图,例如interface GigabitEthernet0/0/0。配置IP地址和子网…...
初步认识产品经理
产品经理 思考问题的维度 1️⃣为什么要抓住核心用户? 所有和产品有关系的群体就是用户,存在共性和差异了解用户的付费点,更好的优化产品是否使用:(目标用户-已使用产品:种子用户-尝鲜;核心用…...
web前端面试中拍摄的真实js面试题(真图)
web前端面试中拍摄的真实js面试题(真图) WechatIMG258.jpeg WechatIMG406.jpeg WechatIMG407.jpeg WechatIMG922.jpeg WechatIMG1063.jpeg © 著作权归作者所有,转载或内容合作请联系作者 喜欢的朋友记得点赞、收藏、关注哦!!…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
