第二十章 opengl之高级OpenGL(高级数据)
创始人
2025-05-29 07:57:46
0

OpenGL

  • 高级数据
  • 分批顶点属性
  • 复制缓冲

高级数据

前面都是使用缓冲来储存数据。
本节学习一些缓冲函数,使用纹理对象来存储大量数据等内容。

OpenGL中的缓冲只是一个管理特定内存块的对象,没有其它更多的功能了。在我们将它绑定到一个缓冲目标(Buffer Target)时,我们才赋予了其意义。
当我们绑定一个缓冲到GL_ARRAY_BUFFER时,它就是一个顶点数组缓冲,但我们也可以很容易地将其绑定到GL_ELEMENT_ARRAY_BUFFER。
OpenGL内部会为每个目标储存一个缓冲,并且会根据目标的不同,以不同的方式处理缓冲。

我们一直是调用glBufferData函数来填充缓冲对象所管理的内存,这个函数会分配一块内存,并将数据添加到这块内存中。如果我们将它的data参数设置为NULL,那么这个函数将只会分配内存,但不进行填充。这在我们需要预留(Reserve)特定大小的内存,之后回到这个缓冲一点一点填充的时候会很有用。

除了使用一次函数调用填充整个缓冲之外,我们也可以使用glBufferSubData,填充缓冲的特定区域。这个函数需要一个缓冲目标、一个偏移量、数据的大小和数据本身作为它的参数。这个函数不同的地方在于,我们可以提供一个偏移量,指定从何处开始填充这个缓冲。这能够让我们插入或者更新缓冲内存的某一部分。要注意的是,缓冲需要有足够的已分配内存,所以对一个缓冲调用glBufferSubData之前必须要先调用glBufferData。

glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // 范围: [24, 24 + sizeof(data)]

将数据导入缓冲另外一种方法是:请求缓冲内存的指针,直接将数据复制到缓冲中。通过调用glMapBuffer函数,OpenGL会返回当前绑定缓冲的内存指针:

float data[] = {0.5f, 1.0f, -0.35f...
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// 获取指针
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// 复制数据到内存
memcpy(ptr, data, sizeof(data));
// 记得告诉OpenGL我们不再需要这个指针了
glUnmapBuffer(GL_ARRAY_BUFFER);

使用glUnmapBuffer函数后,OpenGL知道已经完成指针操作了。解除映射后,指针就不可用了,如果能够将数据映射到缓冲中,则函数会返回GL_TRUE。

用处:
要直接映射数据到缓冲,而不是将其存储到临时内存中,则glMapBuffer函数很重要。可以直接从文件中读取数据,并直接将它们复制到缓冲内存中。

分批顶点属性

使用glVertexAttribPointer函数,能够制定顶点数组缓冲内容的属性布局。在顶点数组缓冲中,对属性进行了交错处理,意思是:将每一个顶点的位置,法线或纹理坐标紧密放到一起。现在要说下另外一种方法:分批顶点属性
做法:将每一种属性类型的向量数据打包为一个大的区块,而不是对它们进行交错存储。与交错布局(12341234)不同,分批是(11223344)
当从文件中加载顶点属性时,通常获取一个位置数组,一个法线数组,或一个纹理做标书组。需要将这些数组转化为一个大的交错数据数组。使用分批的方式会是一个简单的解决方法:
glBufferSubData函数:

float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 填充缓冲
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

这样子我们就能直接将属性数组作为一个整体传递给缓冲,而不需要事先处理它们了。另外一个不太方便的方法是:将它们合并为一个大的数组,再使用glBufferData来填充缓冲,但对于这种工作,使用glBufferSubData会更合适一点。

另外需要更新顶点属性指针来反应改变:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);  
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));  
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));

这给了我们设置顶点属性的另一种方法。两种方法都可以使用

复制缓冲

当缓冲填充好数据后,如果想与其他的缓冲共享其中的数据,或者想将缓冲的内容复制到另外一个缓冲中。glCopyBufferSubData函数能够容易的从一个缓冲中复制数据到另外一个缓冲中。函数原型如下:

void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,GLintptr writeoffset, GLsizeiptr size);

readtarget和writetarget参数需要填入复制源和复制目标的缓冲目标
举例:可以将VERTEX_ARRAY_BUFFER缓冲复制到VERTEX_ELEMENT_ARRAY_BUFFER缓冲,分别将这些缓冲目标设置为读和写的目标。当前绑定到这些缓冲目标的缓冲将会被影响到。

如果想读写数据的两个不同缓冲都为顶点数组缓冲。我们不能同时将两个缓冲绑定到同一个缓冲目标上。
正是出于这个原因,OpenGL提供给我们另外两个缓冲目标,叫做GL_COPY_READ_BUFFER和GL_COPY_WRITE_BUFFER。我们接下来就可以将需要的缓冲绑定到这两个缓冲目标上,并将这两个目标作为readtarget和writetarget参数。

接下来glCopyBufferSubData会从readtarget中读取size大小的数据,并将其写入writetarget缓冲的writeoffset偏移量处。下面举例 复制两个顶点数组缓冲:

float vertexData[] = { ... };
glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));

我们也可以只将writetarget缓冲绑定为新的缓冲目标类型之一:

float vertexData[] = { ... };
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));

相关内容

热门资讯

熵_相对熵_散度 1 信息量 意外越大,越不可能发生,概率就越小,信息量也就...
张家界旅游攻略最佳攻略:玩透张... 张家界旅游攻略最佳攻略:玩透张家界就看这篇! 大家好!我是小李,刚从张家界回来,必须和大家分享我的...
暑假带娃玩转西北畅玩小团|青甘... ✨**带娃畅玩西北,青甘环线轻松搞定!跟着阿洁出发,体验不一样的大美风光!**✨ 我这次暑假带着孩子...
想带父母去四川旅游6天5晚要多... 想带父母去四川旅游6天5晚要多少钱?带父母去四川旅游该怎么玩?看驴友怎么玩 四川,那片充满魅力和生机...
黄山提供一站式的咨询攻略!黄山... 黄山提供一站式的咨询攻略!黄山旅行社4日游尊享版多少钱? 黄山,位于安徽省南部黄山市境内,它不仅仅是...
自驾一小时直达!在济南南部山区... 图源|小红书:荒野之鹿 当山溪漫过脚踝卷走夏日的燥热,待篝火将吉他染成橙红,所有被城市折叠的自由都会...
市区藏绝美湿地公园!日落白鹭齐... 在城市的喧嚣中,总有一些地方像隐秘的宝石,静静等待着被发现。位于市区的一处湿地公园,便是这样一片令人...
第三届衡阳市旅游发展大会主题口... 第三届衡阳市旅游发展大会主题口号、形象标识(LOGO)评选结果公布 为全力办好第三届衡阳市旅游发展大...
潮汕三天两夜旅游多少钱,潮汕三... 潮汕地区,这片充满文化底蕴与独特魅力的土地,一直以来都是众多游客向往的旅游胜地。它不仅有着悠久的历史...
人到山西好风光 青春“晋”行时... 5月27-28日,山西省文旅厅走进山东大学、中国石油大学(华东)开展进校园主题推介活动,吸引山东学子...
旅游小镇票务系统解决方案分享:... 宜良九乡旅游小镇,坐落于云南省昆明市宜良县,是一个令人心驰神往的旅游胜地。这里融合了丛林奇观、古人类...
原创 7... 近日,曾志伟和谭咏麟一起在日本旅行的消息吸引了众多网友的关注。大家纷纷羡慕他们几十年的深厚友谊,但鲜...
土耳其旅游促进和发展局连续第三... 5月27日,2025 ITB上海国际旅游交易博览会(ITB China)在上海世博展览馆盛大启幕。 ...
重庆多个水上乐园开浪!粽香里冲... 本周末 我们即将迎来端午节与儿童节的奇妙邂逅 跟节日一样让人期待的夏日限定快乐 —— 水上乐园🌊 ...
和姐妹去黄山旅游五天需要多少钱... 黄山,这座被誉为“天下第一奇山”的名山,以其奇松、怪石、云海、温泉四绝闻名于世。一直以来,它都是我心...
北京旅游五天四晚大概要多少钱?... 北京,这座古老与现代交织的城市,承载着千年的历史与文化。从宏伟壮观的故宫到繁华热闹的王府井,从静谧幽...
惠州市惠阳区淡水哪个桑拿酒店服... 在惠州市惠阳区淡水,桑拿酒店众多,每一家都宣称自己服务优质131。对于渴望在忙碌生活中寻得放松与享受...
渔湾景区打造非遗数字文旅新标杆 夜幕降临,连云港渔湾景区珍珠瀑布前,1600℃的铁水被击向夜空,瞬间化作漫天金色星雨。游客的惊叹声未...