2015-10-10 49 views
0

我使用OpenGL缓冲区和一大堆GLfloats作为顶点缓冲区,一切都很好。 GLfloats的格式为[x1, y1, z1, x2, y2, z2, ...]OpenGL如何填充缓冲区并将其读回?

但随后,在遵循this tutorial,它告诉我使用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填充缓冲区,并且(如果是的话,它是怎样)将其读回的?

回答

5

根据OpenGL's documentationglBufferData()需要的指针data(即一个阵列,即顶点的坐标)。

我们先来看看glm::vec3的实现。

如果检查出glm's Github repo,你会看到,取决于你的编译标志glm::vec3typedef of highp_vec3这是一个typedef of tvec3<float, highp>

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

所以xyz单独的属性。但是由于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()的要求:正如预期glBufferData()当你通过&vertices[0]你实际上传递data的地址(即指针)。同样的逻辑适用于glGetBufferSubData()

+0

太棒了!这非常有帮助。就像奖金一样,你可以将“任何东西”传递给OpenGL缓冲区吗?说一个类的实例的数组。我在猜测,当你将数据读回来时,它不是很好用,还是会呢? – fordcars

+0

这取决于什么GL反对你_ [绑定](https://www.opengl.org/sdk/docs/man3/xhtml/glBindBuffer.xml)_来。但以我的经验,如果你要上传的顶点,你将不得不使用本教程中提到的方法(即将原料阵列或GLM :: VEC3等等...基本上,'x的连续结构,所以如果你创建了一个自定义类,它只有**'x,y,z'的定义,就像'glm'(或者一个大小为3的数组)一样,你应该好好传递一个向量,包含大量的实例 – 865719

+1

@fordcars:好了,GL缓冲对象只是与特定大小的内存一个连续的区域所以,你可以把你喜欢的任何东西,也可以读回不过,如果你打算。使用缓冲液作为OpenGL本身输入,则需要mathc一些限制,这取决于正在使用的缓冲液的类型。顶点属性可以是某些数据类型的1至4维向量,和顶点数组需要与进行布局在连续的元素之间保持连续的不断变化,把对象的实例放在那里可能会起作用,但是你可能会浪费一些内存。 – derhass

1

glm :: vec3只是一个结构中的三个浮点数。因此,将glm :: vec3的地址有效地传递给gl函数与将地址传递给float数组的第一个元素相同。 GLfloat只是float btw的一个typedef。

从gl读取数据时适用同样的原理。内存中glm :: vec3的x元素数组相当于具有3x元素的GLfloat(float)数组。