I am new to modern OpenGL VBO/VAO and I struggle with one thing: I have coded a RectangleAsset based on this tutorial, but I am not sure how to move information about texture UVs to the RactangleAssetInstance (my rectangles can have different textures).
Do I have to create new VAO for it or can I just pass the UVs by some other means? Or add second VBO for UVs? And most imporantly: what would be best practice solving this?
struct RectangleAsset {
GLuint VBO;
GLuint VAO;
};
struct RectangleAssetInstance { //this is actually more complex class in my code
RectangleAsset rect; //but tried to extract the most imporatant code
glm::mat4 transform;
Texture * texture;
void UpdateTransform(int,int,int,int);
private:
int x,y,width,height;
};
and function loading the RectangleAsset:
void GUIRenderer::init()
{
image = new Program ("vs.glsl", "fs.glsl");
glGenVertexArrays(1, &rect.VAO);
glBindVertexArray(rect.VAO);
glGenBuffers(1, &rect.VBO);
glBindBuffer(GL_ARRAY_BUFFER, rect.VAO);
GLfloat vertexData[] = {
// X Y Z U V
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(image->attrib("vert"));
glVertexAttribPointer(image->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), NULL);
glEnableVertexAttribArray(image->attrib("vertTexCoord"));
glVertexAttribPointer(image->attrib("vertTexCoord"), 2, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
}
NOTE: I plan to use RectangleAssetInstances only at one place, in one std::vector for GUI rendering(non-static gui). Might it be good idea to merge all rectangles in one VBO and VAO (and re-create it whenever UIElement is added/removed)?
Any advices learning best practices with OpenGL are welcomed.
VAOs store both the format of input data and the location that that input data is sourced from. This is actually two separate concepts. If you want to change where the UVs come from you must call glVertexAttribPointer again. This call would look something like glVertexAttribPointer(uvLoc, GL_FLOAT, false, sizeof(float) * 5, (const GLvoid*)(sizeof(float) * 3))
Note that this will NOT change the VBO that your position information is coming from.
Now you mentioned that you wanted to do this because your rectangle instances may have different textures. You need not change the UVs in order to make this happen. In general positions, UVs, and normals are all part of the mesh and you only need one copy of them. To change the texture just call glActiveTexture(GL_TEXTURE0 + i)
followed by glBindTexture(GL_TEXTURE_2D, tex)
and then set the sampler uniform in your shader to use the correct image unit with glUniform1i(samplerLoc, i)
There is also the ARB_vertex_attrib_binding extension, which became core in OpenGL 4.3. This allows you to separate attribute layout from data location. The article at the OpenGL wiki provides information on how to do this, but again it is probably better to author all the textures for a given mesh using the same UVs.
In regards to your question about merging everything into one VAO and VBO: If you only want rectangles than this is not necessary, since you can get any kind of rectangle you would like using an affine transform with non-uniform scaling component. Thus you only need one VAO and one VBO in total, and there is no need to merge anything.