根据OpenGL's documentation,glBufferData()需要一个指向data的指针(即一个数组,即顶点的坐标)。
我们先来看看glm::vec3的实现。
如果您查看 glm's Github repo,您会发现,取决于您的编译标志,glm::vec3 是 typedef of highp_vec3,这是 typedef of tvec3<float, highp>。
tvec3 在type_vec3.hpp 中声明(包含在vec3.hpp 中),类(模板)方法在type_vec3.inl 中定义。
特别是operator[]'s definition 是:
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 是独立的属性。但是感谢how class/struct members are laid out,它们可以被视为一个从&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()。