OpenGL如何填充缓冲区并读取它们
How does OpenGL fill buffers and read them back?
我使用了一个带有一堆glfloat的OpenGL缓冲作为顶点缓冲,一切都很好。glfloat的格式为[x1, y1, z1, x2, y2, z2, ...]
.
但是,在遵循本教程时,它告诉我使用glm::vec3
代替:
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
现在这段代码是有效的,我想知道OpenGL如何知道如何用glm::vec3填充缓冲区而不是GLfloats。然后我想知道,当我从缓冲区读取数据返回时,使用:
std::vector<glm::vec3> data;
glGetBufferSubData(mTarget, offset, vertexCount * sizeof(glm::vec3), &data[0]);`
这会产生一堆glm::vec3吗?所以问题是, OpenGL如何用glm::vec3
填充缓冲区,并且(如果是这样,如何)它读回来?
根据OpenGL的文档,glBufferData()
需要一个指向data
的指针(即数组,即顶点的坐标)。
让我们先看一下glm::vec3
的实现。
如果你查看glm的Github repo,你会看到,根据你的编译标志, glm::vec3
是highp_vec3
的typedef
, tvec3<float, highp>
的typedef
。
tvec3
在type_vec3.hpp中声明(包含在vec3.hpp中),类(模板)方法在type_vec3.inl中定义。
具体来说,operator[]
的定义是:
template <typename T, precision P>
GLM_FUNC_QUALIFIER T & tvec3<T, P>::operator[](typename tvec3<T, P>::length_type i)
{
assert(i >= 0 && static_cast<detail::component_count_t>(i) < detail::component_count(*this));
return (&x)[i];
}
给定这段代码,可以假设x
是包含glm::vec3
坐标的"数组"的第一个元素。但是,当返回到type_vec3.h时,发现:
union { T x, r, s; };
union { T y, g, t; };
union { T z, b, p; };
所以x
, y
和z
是单独的属性。但是由于类/结构成员的布局方式,它们可以被视为从&x
开始的单个数组。
我们现在知道,glm::vec3
(实际上是tvec3
)以连续的方式存储坐标。但是它是否也存储其他属性呢?
好吧,我们可以继续深入研究代码,或者使用一个简单的程序来给出答案:
#include <iostream>
#include <ios>
#include <glm/vec3.hpp>
int main()
{
const glm::vec3 v;
const size_t sizeof_v = sizeof(v);
const size_t sizeof_xyz = sizeof(v.x) + sizeof(v.y) + sizeof(v.z);
std::cout << "sizeof(v) : " << sizeof_v << std::endl;
std::cout << "sizeof(xyz): " << sizeof_xyz << std::endl;
std::cout << "sizeof(v) == sizeof(xyz) : " << std::boolalpha << (sizeof_v == sizeof_xyz) << std::endl;
}
在我的机器上打印:
sizeof(v) : 12
sizeof(xyz): 12
sizeof(v) == sizeof(xyz) : true
因此,glm::vec3
只存储 (x, y, z)
的坐标。
std::vector<glm::vec3> vertices;
,可以肯定地说,&vertices[0]
(在c++ 11中是vertices.data()
)所指向的数据的布局是:
vertices == [vertice1 vertice2 ...]
== [vertice1.x vertice1.y vertice1.z vertice2.x vertice2.y vertice2.z ...]
回到原来的问题——glBufferData()
的要求:当你传递&vertices[0]
时,你实际上是在传递data
的地址(即指针),正如glBufferData()
所期望的那样。同样的逻辑也适用于glGetBufferSubData()
。
glm::vec3只是一个结构体中的三个浮点数。因此,将glm::vec3的地址传递给gl函数的效果与将地址传递给float数组的第一个元素的效果相同。GLfloat只是float的一个类型定义。
同样的原理也适用于从gl中读取数据。内存中包含x个元素的glm::vec3数组相当于包含3x个元素的GLfloat (float)数组。
- 从缓冲区读取/写入文件
- 通过 char* 缓冲区读取 int 的行为是不同的,无论是正数还是负数
- 从输入缓冲区读取
- 使用平面缓冲区读取以前写入的二进制文件的数据
- OpenCL - 从缓冲区读取时CL_INVALID_VALUE
- 如何从uint8_t的缓冲区读取带符号整数,而不调用未定义或实现定义的行为
- 从 char* 缓冲区读取int32_t的惯用 cpp14 方法是什么?
- 如何有选择地从缓冲区读取数据
- 从 char 缓冲区读取 32 位变量
- 协议缓冲区-读取所有消息中通用的标头(嵌套消息)
- 为什么在我的测试程序中,从字符缓冲区读取一个int时,"std::copy"5x(!)比"
- C/C++ 从字符缓冲区读取以填充结构
- 从缓冲区读取数据
- 从缓冲区读取后获取字符串的长度
- 如何从无符号字符(8位)缓冲区读取短整数(16位)
- mmap共享缓冲区读取问题
- 实现有界缓冲区(读取器和写入器之间无块,读取器之间有块,写入器之间有块)
- 从缓冲区读取记录
- 从媒体缓冲区读取-指针算术C++语法
- 使用缓冲区读取未知大小的文件