I was using an OpenGL buffer with a bunch of GLfloats as a vertex buffer and all was well. The format of the GLfloats being [x1, y1, z1, x2, y2, z2, ...]
.
But then, while following this tutorial, it tells me to use glm::vec3
instead:
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);
Now this code is valid, and I wonder how would OpenGL know how to fill in the buffer with glm::vec3 instead of GLfloats. Then I wonder, when I read the data back from the buffer, using:
std::vector<glm::vec3> data;
glGetBufferSubData(mTarget, offset, vertexCount * sizeof(glm::vec3), &data[0]);`
Will this make a bunch of glm::vec3? So the question is, how does OpenGL fill buffers with glm::vec3
, and does (and if so, how does) it read it back?
According to OpenGL's documentation,
glBufferData()
needs a pointer to thedata
(i.e. an array, i.e. the coordinates of the vertices).Let's first have a look at
glm::vec3
's implementation.If you check out glm's Github repo, you'll see that, depending on your compilation flags,
glm::vec3
is atypedef
ofhighp_vec3
which is atypedef
oftvec3<float, highp>
.tvec3
is declared in type_vec3.hpp (included by vec3.hpp) and the class (template) methods are defined in type_vec3.inl.In particular,
operator[]
's definition is:Given that piece of code, one would assume that
x
is the first element of the "array" containing the coordinates ofglm::vec3
. However, when we go back to type_vec3.h, we find:So
x
,y
andz
are separate attributes. But thanks to how class/struct members are laid out, they can be viewed as a single array starting from&x
.We know now, that
glm::vec3
(actuallytvec3
) stores the coordinates in a contiguous manner. But does it also store other attributes ?Well, we can continue to dive into the code, or use a simple program to give us the answer:
Which prints, on my machine:
Therefore,
glm::vec3
stores only the(x, y, z)
coordinates.Now, if we create a
std::vector<glm::vec3> vertices;
, it is safe to say that the layout of the data pointed by&vertices[0]
(which, in C++11 isvertices.data()
) is:Going back to the original issue --
glBufferData()
's requirements: when you pass&vertices[0]
you are actually passing the address (i.e. pointer) of thedata
, just as expected byglBufferData()
. The same logic applies toglGetBufferSubData()
.glm::vec3 is just three floats in a struct. So passing the adress of a glm::vec3 to gl function effectively does the same thing as passing the adress to the first element of a float array. GLfloat is just a typedef of float btw.
The same principle apply when reading data from gl. An array of x elements of glm::vec3 in memory is equivalent to an array of GLfloat (float) with 3x elements.