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 © 著作权归作者所有,转载或内容合作请联系作者 喜欢的朋友记得点赞、收藏、关注哦!!…...
python 人工智能 机器学习 当损失函数的数值变成 `nan` 时,这通常意味着在模型训练过程中出现了数值不稳定性以及解决办法,数据分析
当损失函数的数值变成 nan 时,这通常意味着在模型训练过程中出现了数值不稳定性。以下是一些可能导致这个问题的原因以及相应的解决方法: 1. **学习率过高**:如果学习率设置得过高,可能会导致梯度爆炸,从而导致损失函…...
Kafka快速实战与基本原理详解
笔记:https://note.youdao.com/ynoteshare/index.html?id=b0357bdb4821ed2e35ecdbdacd65aa06&type=note&_time=1727570043631 启动kafka之前先启动zookper 看看ZK里面都有什么数据 : 刚开始什么数据都没有 接下来启动kafka,启动好后,日志在这里看: 启动好了kaf…...
tftp传文件被服务器拒绝进入tftp: server error: (768) Access to staonline.pcap denied
环境:测试一个ac下挂ap,ap下的抓包文件传出时,出现问题: ac的wan口ip是192.168.186.167/24,gw是192.168.186.1,下挂ap的ip是192.168.202.199/24,ac上开子接口192.168.202.1/24,ac上开…...
express,生成用户登录后的 token
在 Node.js 中使用 Express 框架生成用户登录后的 token,通常会涉及到以下几个步骤: 设置 Express 应用:首先,你需要有一个基本的 Express 应用。安装必要的中间件:例如 jsonwebtoken(JWT)用于…...
银河麒麟桌面操作系统修改默认Shell为Bash
银河麒麟桌面操作系统修改默认Shell为Bash 💐The Begin💐点点关注,收藏不迷路💐 在银河麒麟桌面操作系统(ARM版)中,若要将默认Shell从Dash改为Bash,可执行以下步骤: 打开…...
卷积神经网络(Convolutional Neural Networks, CNN)
卷积神经网络(Convolutional Neural Networks, CNN)是深度学习领域中用于处理具有网格结构的输入(如图像和视频)的神经网络模型。下面以最简单、直观的方式概述CNN的主要流程及其基本概念: 1. 输入层 概念:…...
SpringBoot系列 启动流程
文章目录 SpringApplicationSpringApplication#run 启动流程BootstrapContextSpringApplicationRunListenersprepareEnvironmentconfigureEnvironmentconfigurePropertySourcesconfigureProfiles 上下文初始化prepareContextrefreshContextprepareRefreshobtainFreshBeanFactor…...
vgg19提取特征
一般来说,大家使用VGG16,用的是第四列的网络架构,而使用VGG19,使用的就是第六列的网络架构。 使用vgg进行提取特征,在这个项目中,使用的就是每一块卷积层的第一层。 import torch.nn as nn from torchvis…...
Qt 中的 QChartView
深入理解 Qt 的 QChartView:图表展示与交互 QChartView 是 Qt Charts 模块中的一个核心类,它用于在 Qt 应用程序中显示图表,并支持多种用户交互方式。它继承自 QGraphicsView,通过封装 QChart,为用户提供了强大的图表…...
cheese安卓版纯本地离线文字识别插件
目的 cheese自动化平台是一款可以模拟鼠标和键盘操作的自动化工具。它可以帮助用户自动完成一些重复的、繁琐的任务,节省大量人工操作的时间。可以采用Vscode、IDEA编写,支持Java、Python、nodejs、GO、Rust、Lua。cheese也包含图色功能,识别…...
买产品做企业网站还是博客/百度搜索引擎优化怎么做
深克隆和浅克隆的实现原理1)深克隆和浅克隆的区别2)知识扩展2.1)clone() 源码分析2.2)Arrays.copyOf()2.3)深克隆实现方式汇总2.3.1)所有对象都实现克隆2.3.2)通过构造方法实现深克隆2.3.3&…...
北京营销型网站建设/百度网站域名
$User M("User"); // 实例化User对象$condition[name] thinkphp;$condition[status] 1;// 把查询条件传入查询方法$User->where($condition)->select(); 最后生成的SQL语句是 SELECT * FROM think_user WHERE namethinkphp AND status1 $User M("Us…...
重庆时时彩网站建设/推广什么app佣金高
一、前言 由于C语言的灵活性,用C语言开发出来的程序容易造成内存泄漏、运行异常、运行结果不可预期等程序质量问题,在用C语言开发程序的过程中,必须高度重视程序质量问题,应当把提高程序稳定性的方法加入到项目管理和开发过程中&a…...
应届生求职网站官网/惠州seo网站排名
直接使用FlashDevelop可以自动成生override. 但是对于只有一个参数的call不好使,查了一下资料,可以用以下方法解决 overridepublicfunction call(command:String, responder:Responder, args):void{ args.unshift(command, responder); super.call.apply(this, arg…...
网站开发成本包括/发布新闻稿
只要最后统计出有多少个集合就好了 我用并查集还有set做的,好像用set慢了一点 #include<stdio.h> #include<set> using namespace std; int f[1010]; int find(int x) {if(xf[x])return f[x];f[x]find(f[x]);return f[x]; } void Union(int x,int y) {i…...
丽水网站建设哪家好/seo技术网
1.时间戳转日期 函数:FROM_UNIXTIME select FROM_UNIXTIME(1661997078,%Y-%m-%d %H:%i:%s) ; 注意时间戳长度为:10 当时间戳长度大于10,要截取前十位 select substr(1661997078000, 1, 10); 2.日期转时间戳 函数:UNIX_TIMESTA…...