For drawing lots of small shapes, the most efficient way I found in OpenGL was to create an array of points, and array of indices, and use glDrawElements. For example, drawing multiple rectangles for a web page.
Our current design has a MultiShape2D object that uses a vertex buffer of points, and then draws solid shapes, and then lines and points on top of the solid shapes using glDrawElements.
But for a GUI element that is changing as the cursor moves over it, refreshing is a problem.
It seems like the easiest way to draw a GUI object that is small might be to just have a render function which draws the shape – why bother to create a vbo if the numbers constantly change anyway? For example, if I created a button with a rectangle and text, and clicking on the button changes the color of the rectangle, and changes the text, then this would require updating all the values that made up those shapes. And since the objects are not huge, we might be talking about a vbo for the rectangle composed of 4 points (8 floats), another vertex buffer object for the letters with 44number of characters.
Before vertex buffer objects, opengl supported drawing arrays to the screen. I am having trouble finding the call that passes in the array. So the questions are:
- Is it better to always use vertex buffer objects even for small objects like a single rectangle?
- Is it possible to just draw an array without creating a vbo, and if so can someone point me to an example? I could use immediate mode but that is deprecated.
with a vbo, the code might look like:
void init() {
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*
vertices.size(),&vertices[0],GL_DYNAMIC_DRAW);
//Describe how information is recieved in shaders
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,(void*)0);
}
void render() {
shader->setMat4("projection",*(parentCanvas->getProjection()));
shader->setVec4("solidColor",style->getFgColor());
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
}
Consider for example, rendering a box with text on it, and highlighting a word. Rendering the box requires 4 points and a color. Rendering the words renders each letter using a texture. These require different shaders so they are separate operations. Highlighting a word with a different background color would require drawing a different rectangle.
I’m assuming the easiest and fastest way to do this would be to draw the entire rectangle, specifying a color, then drawing a second rectangle with the highlight color. The highlighted rectangle is drawn twice. Then text is drawn on top of that. We currently specify the color as a uniform attribute in the shader.
If I scale that up to hundreds of text boxes on a screen, what is the least-cost way of doing this?
I don’t just mean optimum speed, but minimizing the complexity of the code.
It’s for this reason that I was thinking that for smaller interactive GUI objects, it would be easier to just have all the code in render, no initialization, no vertex buffer objects.
Asking this question makes me realize I don’t even know how a shader works at the lowest level. Suppose I select the following vertex shader:
#version 330
layout (location = 0) in vec3 aPos; // the position variable has attribute position 0
uniform mat4 projection;
uniform vec4 solidColor;
out vec4 ourColor; // output a color to the fragment shader
//Add a uniform bool to check if to use vertColor or Solid color
void main() {
gl_Position = projection*vec4(aPos, 1.0);
ourColor = solidColor; // set ourColor to the input color we got from the vertex data
}
Can I set projection and color, draw a rectangle, then set color again and draw a different rectangle?
This is aside from the fact that it may be considered better to have a list of colors and that I shouldn’t do it.