I'm trying to pass a structure to a simple GLSL vetrex shader. Here's how the structure look like on the C++ side:
struct Vertex
{
float position[3];
char boneIndex[4];
float weights[4];
float normals[3];
float textureCords[2];
};
Is it possible to pass array of this vertex to the vertex shader without creating a separate array for each component?
Can I do something like this:
#version 330 core
uniform mat4 MVP;
layout(location = 0) in struct Vertex
{
vec3 position;
uint boneIndex;
vec4 weights;
vec3 normals;
vec2 textureCords;
} vertex;
out vec2 UV;
void main()
{
gl_Position = MVP * vec4(vertex.position, 1.0f);
UV = vertex.textureCords;
}
(Dont mind that not all of the components are in use, it's just for the example.)
And if I can, how can I pass the data to it from the C++ side using the glVertexAttribPointer() function? (According to my understanding you can pass only 1,2,3,4 to the size parameter).
Is it the even the right way to do things? I'm a beginner in OpenGL programming so if you have an answer please don't hesitate to include obvious details.
I ended up doing something like this:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); //float position[3]
glVertexAttribPointer(1, 1, GL_INT, GL_FALSE, 12, (void*)0); //char boneIndex[4]
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 16, (void*)0); //float weights[4]
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 32, (void*)0); //float normals[3]
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 44, (void*)0); //float textureCords[2]
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indiceBuffer);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void*)0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
On the C++ size, and on the GLSL vertex shader:
#version 330 core
uniform mat4 MVP;
layout(location = 0) in vec3 position;
layout(location = 1) in int boneIndex;
layout(location = 2) in vec4 weight;
layout(location = 3) in vec3 normal;
layout(location = 4) in vec2 UVCords;
out vec2 UV;
void main()
{
gl_Position = MVP * vec4(position, 1.0f);
UV = UVCords;
}
But it still won't work, the model wont render correctly
The method you've used to transfer the interleaved data is correct (that is, using glVertexAttribPointer
, however, your last two parameters are incorrect).
The penultimate is the stride
(which is the same for every item in the struct, and should be the size of the struct), and the last is the offset
, which should be different for each element (as they are at different offsets in the struct itself).
Also it is best not to use constants here, but instead, use the sizeof()
operator, to make your code as platform independent as possible.
Here's what it should look like:
glVertexAttribPointer(
0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr
); //float position[3]
glVertexAttribIPointer(
1, 1, GL_INT, GL_FALSE, sizeof(Vertex),
std::reinterpret_cast<void *>(offsetof(Vertex, boneIndex))
); //char boneIndex[4]
glVertexAttribPointer(
2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
std::reinterpret_cast<void *>(offsetof(Vertex, weights))
); //float weights[4]
glVertexAttribPointer(
3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
std::reinterpret_cast<void *>(offsetof(Vertex, normals))
); //float normals[3]
glVertexAttribPointer(
4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
std::reinterpret_cast<void *>(offsetof(Vertex, textureCoords))
); //float textureCoords[2]
Also, you should probably ensure that your Vertex
struct is not packed to fit into a nice word boundary. This is done by using #pragma pack(0)
, if your compiler supports it. (Remember to reset this after after your struct, because otherwise the compiler will use this directive throughout the rest of the compilation process, and all your aggregate data structures will be structured in a way that doesn't yield to the best possible fit with regards to world alignment.), here's what that looks like:
#pragma pack(push, 0)
struct Vertex {
float position[3];
char boneIndex[4];
float weights[4],
normals[4],
textureCoords[2];
};
#pragma pack(pop)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With