OpenGL ES 顶点缓冲区和布局(3)

news2024/9/30 14:53:44

OpenGL ES 顶点缓冲区和布局(3)

简述

顶点缓冲区的本质就是一段GPU上的显存,我们通过绑定顶点缓冲区的方式来将数据从CPU传到GPU。
我们之前在绘制三角形的例子中,我们往顶点缓冲区只传入了坐标,但是其实顶点是可以包含很多数据的,比如纹理索引,颜色等,因为它的本质其实就是一个Buffer,所以我们可以使用它做非常多的事情。
我们前面说了,顶点缓冲区只是一个一段内存,但是GPU并不知道这段内存里的这些数是什么意思,每个数据的含义是什么。所以我们需要告诉GPU顶点缓冲区布局,定义每个数据是什么意思。

配置布局接口

glVertexAttribPointer

  • 第一个参数是index,表示这个数据要传递给shader哪一个属性,这个我们在shader对篇章会详细介绍。
  • 第二个参数是size,表示有几个数
  • 第三个参数是type,表示数据类型
  • 第四个参数是normalized,表示参数是否需要归一化
  • 第五个参数是stride,每个顶点的步长,基本可以理解为一个顶点的长度
  • 第六个参数是offset,表示当前属性在当前顶点的偏移

绑定BufferData

glBufferData

  • 第一个参数,数据类型,顶点缓冲区一般用GL_ARRAY_BUFFER,后续我们还会介绍索引缓冲区
  • 第二个参数,size,我们需要分配缓冲区的大小。
  • 第三个参数,data,我们定义的数据。
  • 第四个参数,缓冲区用于使用的场景,GL_STREAM_DRAW/GL_STATIC_DRAW/GL_DYNAMIC_DRAW。
    GL_STREAM_DRAW:缓冲区数据代码设置,仅渲染一次,使用很少。
    GL_STATIC_DRAW:缓冲区数据是静态的,不会修改的。
    GL_DYNAMIC_DRAW:缓冲区数据会动态变化,常常需要更新数据。

实现渐变颜色三角形

我们这里通过顶点缓冲区传递数据,实现一个渐变三角形。这个demo会有助于我们对顶点缓冲区数据传递,同时还能对顶点着色器属性有一些了解。
我们基于之前那个三角形的案例来修改。

修改顶点缓冲区Buffer

我们之前顶点缓冲区只有9个数,三个顶点,每个顶点三个坐标,修改后每个顶点有7个数,前三个点依旧是坐标,和之前相同,而后面新增的四个顶点是坐标,即RGBA。
我们之前提过,着色器会对每个像素都调用一次,而顶点着色器则会根据顶点坐标渐变,对每个像素都进行调用。
这里实现的三个角的颜色分别是红黄蓝,然后向中间渐变。

private float[] vertexArray = new float[] {
        -0.5f, -0.5f, 0.0f, 1f, 0f, 0f, 1f,
        0.5f, -0.5f, 0.0f, 0f, 1f, 0f, 1f,
        0.0f, 0.5f, 0.0f, 0f, 0f, 1f, 1f
};

修改shader

添加了属性attribute vec4 inputColor,用于接收顶点缓冲区新增的四维用于表示颜色的数组,顶点缓冲区传递给vertexColor,通过varying传递给片段着色器。
片段着色器直接使用varying vec4 vertexColor作为gl_FragColor返回。

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

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

顶点缓冲区创建/数据填充

创建绑定顶点缓冲区,后使用glBufferData填充数据,这里和之前创建三角形一样,基本没有修改。

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

配置顶点缓冲区布局

通过这里的glVertexAttribPointer使用,配合上面的api介绍,我们大概就能理解这个布局接口是怎么使用的。

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);
    // 主要改动部分在这里
    // 这里的步长为7个顶点 * sizeof(float), 这里index是传给vPosition,type还是GL_FLOAT,size为3个顶点
    GLES30.glVertexAttribPointer(positionLocation, 3, GLES30.GL_FLOAT, false, 7 * 4, 0);

    // 步长和上面一样, 这里index是传给inputColor,type还是GL_FLOAT,size为4个顶点
    int colorInputLocation = GLES30.glGetAttribLocation(shaderProgramId, "inputColor");
    GLES30.glEnableVertexAttribArray(colorInputLocation);
    GLES30.glVertexAttribPointer(colorInputLocation, 4, GLES30.GL_FLOAT, false, 7 * 4, 3 * 4);

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

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

效果

在这里插入图片描述

顶点数组

还有一个概念是顶点数组,我们简称VAO,相关的接口glGenVertexArrays,这个接口在GLES20上没有,但是在GLES30上有。
顶点数组的本质的作用是用于记录顶点缓冲区和顶点布局的关系,如果有多个缓冲区,顶点数组可以记录这些,可以减少调用绑定的次数。
相信大家会有一个问题,为什么GLES20上没有这个api,而且我们之前绘制三角形的demo中也没有使用这个顶点数组,为什么还可以正常绘制呢。
按照技术上的作用,这个顶点数组是必要的,前面这个问题的答案其实是因为OpenGL默认配置下就会有一个顶点数组。
这个目前了解一下即可,后续我们绘制多个对象的时候会再仔细介绍顶点数组。

小结

本节介绍了顶点缓冲区和布局,且通过实现一个渐变色的三角形demo来展示了怎么使用顶点缓冲区和布局。
顶点缓冲区的数据可以是位置,颜色,纹理等等,本质这里就是一个内存缓冲区,这里展示了颜色的用法。
配置顶点布局的接口使用比较简单,按照文档的使用即可。

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

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

相关文章

指定PDF或图片多个识别区域,识别区域文字,并导出到Excel文件中

常见场景 用户有大量图片/PDF文件,期望能将图片/PDF中的多个区域中的文字批量识别出来,并导入到Excel文件中。期望工具可以批量处理、离线识别(保证数据安全性)。手工操作麻烦。具体场景:用户有工程现场照片&#xff…

xgboost cross validation

在R中使用xgboost 假设X为训练数据,y为label,为0或者1.用xgboost建立分类模型代码如下 调用caret包中的createFolds方法,进行10倍交叉验证 最后画出AUC曲线 library(xgboost) library(caret) library(caTools) library(pROC)set.seed(123) …

【北京迅为】《STM32MP157开发板嵌入式开发指南》- 第十一章 Linux 帮助手册讲解

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐…

3DGS中Densification梯度累计策略的改进——绝对梯度策略(Gaussian Opacity Fields)

在学习 StreetGS 代码中发现了其中的 Densification 策略与原 3DGS 不太一样,其是使用的 Gaussian Opacity Fields 中的一个的策略 我们先来回忆一下 3DGS 中一个比较重要 contribution:自适应密度控制 1 自适应密度控制 其具体步骤如下: …

概率论——随机分布

离散型——二项分布 X ~ B(n , p) 例题: 例题二: 离散型——泊松分布 例题 注意:记住题二的结论!!! 连续性——均匀分布 例题:求解概率密度(具体方法见随机…

请问PMP英文报名被审查该怎么通过?

审核抽查是随机进行的(一般概率约为30%),并非所有人都会接受资料抽查。如果您报考了机构,他们会协助您解决这个问题。 一、资料审查: 如果被PMI选中进行审查,这是正常情况,不必惊慌。如果你参…

要洞察数字化本质,才能形成破局之道...

在深入探索数字化转型的突破路径之前,首要之务是构筑对数字化及其转型过程的深刻而准确的认知体系。唯有透彻理解数字化的内在本质,精准把握数字化转型的演变规律,方能引领数字化转型的航向,确保数字化工具与策略得以高效、精准地…

(一)万字详解G1垃圾收集器 —G1的设计目标是什么?G1的分区是什么?卡表的作用和工作原理?如何解决漏标问题?

一、G1垃圾收集器简介 G1 GC(Garbage-First Garbage Collector)是一款先进的垃圾收集器,通过 -XX:UseG1GC 参数启用。它首次亮相于JDK 6u14版本,并在JDK 7u4中正式发布。对于熟悉JVM的开发者而言,G1已是一个广为人知的…

测试卡(1)灰卡

#灵感# 灰卡为什么是18%?文章分为三部分,前部分,解释灰卡的定义,后部分是 市场买的18%灰卡的说明书,其中穿插了网络上搜到的灰卡使用案例。 目录 18% 中性灰卡应用说明 1) 曝光水平 例子:用灰…

ppt模板如何制作?建议试试这4招

在追求效率和简洁的现代办公环境中,简约风格的PPT模板因其清晰、直观的特点而备受青睐。制作一个简约的PPT模板不仅能提升演示的专业感,还能帮助观众快速抓住重点。 今天,我来告诉大家:ppt模板简约怎么制作?让你能够利…

Kubernetes 节点何时处于就绪状态?

在 Kubernetes 中,节点(Node)是一个工作负载的基本单元,容器被部署和运行在这些节点上。每个 Kubernetes 节点在加入集群后都需要经过一定的健康检查和状态评估,才能被集群标记为“就绪”状态。这一过程的关键是节点的…

Linux相关概念和重要知识点(9)(父进程、子进程、进程状态)

1.父进程、子进程 (1)父进程 CLI本质上是一款命令行界面的软件,是用户调用接口层面的程序(上层,可以和系统调用接口做沟通),CLI和GUI是同级别的。用户的操作都是建立在CLI和GUI之上的。 但是…

奔三理工男适合转行做AI算法工程师吗?

奔三男生转行可以做什么? 干了几年开发程序员却面临降薪优化? 说实话,如果学历一般技术一般, 无法与时俱进的话,会容易面临尴尬情况…… 就业这件事,选对赛道方向至关重要!! 这…

profinet转ethercat连接伺服在工业现场的配置案例

在工业通信领域,Profinet 转 EtherCAT 网关的应用为实现不同工业网络之间的通信提供了有效的解决方案。以下是一个关于 Profinet 转 EtherCAT 网关链接伺服配置的案例。 首先,我们需要准备好相关的硬件设备,包括 Profinet 转 EtherCAT 网关、…

Docker Desktop 安装Centos 7.9 使用yum install不可用问题

安装centos镜像并run之后,使用yum install 命令安装出现如下错误,可使用此命令替换mirror。 报错信息: Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archaarch64&repoos&infracontainer error was…

2024第八届御网杯信息安全网络大赛线上WP详解(misc+cryoto)(详解-思路-脚本)

芜湖~ 首届御网杯线上和ISCC分开进行 但还是用的ISCC的页面差评 嘻嘻 又是玄乎的一天 以下是我自己的一些思路和解析 有什么问题或者建议随时都可以联系我 目录 附件 # Misc ##Notice ##编码转换 Brainfuck编码 jsfuck编码 Ook! 编码 ##bluetooth 导出压缩包 第一…

OpenGL 使用离屏渲染技术进行截图

文章目录 背景第三方库注意参考资料 一、离屏渲染(一)帧缓冲与帧缓冲对象(FBO)(二)附件(Attachment) 二、具体代码(一)主线程创建OpenGL窗口(二&a…

python画图|自制渐变柱状图

在前述学习过程中,我们已经通过官网学习了如何绘制渐变的柱状图及其背景。 掌握一门技能的最佳检验方式就是通过实战,因此,本文尝试做一些渐变设计。 前述学习记录可查看链接: Python画图|渐变背景-CSDN博客 【1】柱状图渐变 …

CORE 中间件、wwwroot

ASP.NET Core中间件组件是被组装到应用程序管道中以处理HTTP请求和响应的软件组件(从技术上来说,组件只是C#类)。 ASP.NET Core应用程序中的每个中间件组件都执行以下任务。 选择是否将 HTTP 请求传递给管道中的下一个组件。这可…

《C++》解密--单链表

目录 一、概念与结构 二、实现单链表 三、链表的分类 四、单链表算法题 一、概念与结构 1、节点 结点的组成主要有:当前结点要保存的数据和保存下一个节点的地址(指针变量) 图中指针变量plist保存的是第一个结点的地址,我们称p…