OpenGL如何填充缓冲区并将其读回?

for*_*ars 0 c++ opengl buffer glm-math

我正在使用一个带有一堆GLfloats的OpenGL缓冲区作为顶点缓冲区,一切都很顺利.GLfloats的格式是[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);
Run Code Online (Sandbox Code Playgroud)

现在这段代码是有效的,我想知道OpenGL如何知道如何用glm :: vec3而不是GLfloats填充缓冲区.然后我想知道,当我从缓冲区读回数据时,使用:

std::vector<glm::vec3> data;
glGetBufferSubData(mTarget, offset, vertexCount * sizeof(glm::vec3), &data[0]);`
Run Code Online (Sandbox Code Playgroud)

这会产生一堆glm :: vec3吗?所以问题是,OpenGL如何填充缓冲区glm::vec3,并且它(如果是这样,如何)读取缓冲区?

mad*_*uri 5

根据OpenGL的文档,glBufferData()需要一个指向data(即数组,即顶点坐标)的指针.

我们先来看看它glm::vec3的实现.

如果你看看GLM的GitHub库,你会发现,这取决于你的编译标志,glm::vec3typedefhighp_vec3这是typedeftvec3<float, highp>.

tvec3type_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];
}
Run Code Online (Sandbox Code Playgroud)

给定这段代码,可以假设这x是包含坐标的"数组"的第一个元素glm::vec3.但是,当我们回到type_vec3.h时,我们发现:

union { T x, r, s; };
union { T y, g, t; };
union { T z, b, p; };
Run Code Online (Sandbox Code Playgroud)

所以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;
}
Run Code Online (Sandbox Code Playgroud)

在我的机器上打印哪些:

sizeof(v)  : 12
sizeof(xyz): 12
sizeof(v) == sizeof(xyz) : true
Run Code Online (Sandbox Code Playgroud)

因此,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 ...]
Run Code Online (Sandbox Code Playgroud)

回到原始问题 - glBufferData()的要求:当你通过&vertices[0]时,实际上正在传递地址(即指针)data,正如预期的那样glBufferData().同样的逻辑适用于glGetBufferSubData().