GLFWwindow* window;
int initWindow() {
if(!glfwInit()) {
std::cerr << "Failed to initialize GLFW\n";
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // FOR MAC
window = glfwCreateWindow(800, 400, "Title", NULL ,NULL);
if(window == NULL) {
fprintf(stderr, "Failed to open GLFW window.\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
return 0;
}
We will draw a square using two triangles.
float vertices[] = {
// First triangle
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
// Second triangle
-0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
To store data in the GPU memory, we need:-
Vertex Buffer Object (VBO)
Vertex Array Object (VAO)
Create identifier for our VAO and VBO
GLuint VAO, VBO;
Create VAO and VBO
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
Send our data to the buffer
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
Tell openGL how to how to interpret our data
glVertexAttribPointer(
0, // Attribute index
3, // Number of components (x,y,z)
GL_FLOAT, // Type of data
GL_FALSE, // Not normalized
3 * sizeof(float), // Stride (distance between consecutive vertex positions)
(void*)0 // Offset (start at beginning of the array)
);
glEnableVertexAttribArray(0);
Unbind to avoid unintentional changes
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
We will use the given function that loads and compiles shader.
GLuint shaderProgram = LoadShaders( "vertexShader.glsl", "fragmentShader.glsl" );
Vertex shader
#version 330 core
layout(location = 0) in vec3 aPos;
void main() {
gl_Position = vec4(aPos, 1.0);
}
Fragment shader
#version 330 core
out vec4 FragColor;
void main() {
// White color for all fragments
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
Let’s add some color
float colors[] = {
// First triangle (R, G, B)
1.0f, 0.0f, 0.0f, // Red
0.0f, 1.0f, 0.0f, // Green
0.0f, 0.0f, 1.0f, // Blue
// Second triangle
1.0f, 1.0f, 0.0f, // Yellow
0.0f, 1.0f, 1.0f, // Cyan
1.0f, 0.0f, 1.0f // Magenta
};
We need to create multiple buffers for the VAO
We have an additional VBO
GLuint VAO, VBO_verts, VBO_colors;
Create our buffers
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO_verts);
glGenBuffers(1, &VBO_colors);
Send data to our buffers
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO_verts);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO_colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),(void*)0);
glEnableVertexAttribArray(1);
Use color in shader
Vertex shader
#version 330 core
layout(location = 0) in vec3 aPos; // position
layout(location = 1) in vec3 aColor; // color
out vec3 ourColor; // pass to fragment shader
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
}
Fragment Shader
#version 330 core
in vec3 ourColor; // from vertex shader
out vec4 FragColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
We are repeating vertices. For a large mesh, it would result in a lot of wasted memory.
float vertices[] = {
// Bottom-left
-0.5f, -0.5f, 0.0f,
// Bottom-right
0.5f, -0.5f, 0.0f,
// Top-right
0.5f, 0.5f, 0.0f,
// Top-left
-0.5f, 0.5f, 0.0f
};
float colors[] = {
// Bottom-left (red)
1.0f, 0.0f, 0.0f,
// Bottom-right (green)
0.0f, 1.0f, 0.0f,
// Top-right (blue)
0.0f, 0.0f, 1.0f,
// Top-left (yellow)
1.0f, 1.0f, 0.0f
};
unsigned int indices[] = {
0, 1, 2, // first triangle
2, 3, 0 // second triangle
};
We create an additional buffer for indexes.
GLuint VAO, VBO_verts, VBO_colors, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO_verts);
glGenBuffers(1, &VBO_colors);
glGenBuffers(1, &EBO);
Send index data to our buffer.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
Now to draw indexed data we use:-
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);