Introduction
I have recently developed interest in graphics and game develpoment, learning these new things is always fun. I have been learning OpenGL and GLSL for a while now, and I have found some great resources to learn from. I will be sharing them here, so that you can also learn from them.
Challenge
Firstly I faced a challenge in setting up OpenGL and GLSL in clion, which i primarily use for C/C++ development. I could not find any good resources and still face this challenge. I will update this log if I find a solution.
Vscode
Facing challenge in clion, I decided to use VSCode for OpenGL and GLSL development. I found a great video on youtube by Codeus Channel, which explains how to setup OpenGL and GLSL in VSCode. I have linked the video below.
Youtube video by Codeus Channel:
Workaround to run multiple files
Here the task.json
file shared in the tutorial works only for one file which is main.cpp
but I wanted to run any file I wanted just by selecting run on that particular file. Unfortunately I did not find any solution for this, but I found a workaround. I just edit the task.json
file and change the file name to the file I want to run.
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe build active file",
"command": "C:/mingw64/bin/g++.exe",
"args": [
"-g",
"-std=c++17",
"-I${workspaceFolder}/include",
"-L${workspaceFolder}/lib",
"${workspaceFolder}/src/matrixplanet.cpp", //change this
"${workspaceFolder}/src/glad.c",
"-lglfw3dll",
"-o",
"${workspaceFolder}/cutable.exe"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: C:/mingw64/bin/g++.exe"
}
]
}
How to run multiple files
Here "${workspaceFolder}/src/matrixplanet.cpp",
is the line which runs the particular file.
instead of matrixplanet.cpp
I can run any file I want, just by changing the file name.
Where to put the files
I put all my files in the src
folder, and I can run any file I want just by changing it in the task.json
file.
Learning
Here are some things I have learned so far.
1. Basic skeleton in OpenGL
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace std;
int main()
{
GLFWwindow* window;
if (!glfwInit())
{
cout << "Failed to initialize GLFW" << endl;
return -1;
}
window = glfwCreateWindow(640, 480, "Hello World", 0, 0);
if (!window)
{
cout << "Failed to create window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << endl;
return -1;
}
// render loop
while (!glfwWindowShouldClose(window))
{
glClearColor(1.0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
}
The tutorials I followed, some of them did not use glad
and even without using it their code ran. But I got errors if I did not use glad
so just by adding glad
I was able to run the code.
Note
Also if I had to render anything that should go after the glad load
function, otherwise it would not render.
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << endl;
return -1;
}
// render
2. Toggle color of the window each frame.
😋 this was a fun thing to do, basic though as compared to other things I did.
bool toggle = false;
// render loop
while (!glfwWindowShouldClose(window))
{
if(toggle)
{
glClearColor(1.0,0,0,0);
}
else
{
glClearColor(0,1.0,0,0);
}
toggle = !toggle;
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
This just made the screen go crazy with red and green color change each frame.
3. Drawing a Triangle
glBegin(GL_TRIANGLES);
glColor3f(1.f,0.f,0.f);
glVertex3f(-0.6f,-0.4f,0.0f);
glColor3f(0.f, 1.f, 0.f);
glVertex3f(0.6f,-0.4f,0.0f);
glColor3f(0.f, 0.f, 1.f);
glVertex3f(0.f,0.6f,0.0f);
glEnd();
With this I learned how to draw a triangle, and how to set the color of the triangle. I also learned that the color of the triangle is set by the last glColor3f
function. So if I want to set the color of the triangle I should set it before the glVertex3f
function. I also learned we can created circles with triangles too! 😋 In the next learning I will be drawing a circle with triangles.
4. Drawing a Circle with steps
Outside of the main function, I set the steps and step angle.
If we have less steps the circle will not be smooth, and if we have more steps the circle will be smooth but it will take more time to render. You can set less steps and see how the triangle form a complete circle.
const int steps = 50;
const float stepAngle = 3.1415926f * 2.f / steps;
float xPos = 0; float yPos = 0; float radius = 1.0f;
// render loop
while (!glfwWindowShouldClose(window))
{
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT);
float xCenter = 0.0f;
float yCenter = 0.0f;
float radius = 1.f;
float rx = xCenter;
float ry = yCenter-radius;
for (int i=0;i<=steps;i++) {
float angle = stepAngle*i;
float newRx = radius*sinf(angle);
float newRy = -radius*cosf(angle);
glBegin(GL_TRIANGLES);
glColor3f(0.f,0.75f,0.f);
glVertex3f(0.f,0.f,0.f);
glVertex3f(rx,ry,0.f);
glVertex3f(newRx,newRy,0.f);
glEnd();
rx = newRx;
ry = newRy;
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
Here I have used the sinf
and cosf
functions to calculate the x and y position of the triangle. I have used the glBegin
and glEnd
functions to draw the triangle. I have also used the glVertex3f
function to set the position of the triangle. I have also used the glColor3f
function to set the color of the triangle.
Note
I forgot to <=
in the for loop
for (int i=0;i<=steps;i++)
instead i did was i < steps
which caused the circle to not complete. I was stuck on this for a while, but then I figured out the problem.
5. Drawing solar system
Made a reusable function to draw a circle.
const int steps = 100;
void drawCircle(float red, float green, float blue){
float radius = 1.;
const float angle = 2.0f * 3.1416f / steps;
float oldX = 0; float oldY = 0;
for (int i = 0; i <= steps; i++) {
float newX = radius * sin(i * angle);
float newY = radius * cos(i * angle);
glColor3f(red, green, blue);
glBegin(GL_TRIANGLES);
glVertex3f(0.f, 0.f, 0.f);
glVertex3f(oldX, oldY, 0.f);
glVertex3f(newX, newY, 0.f);
glEnd();
oldX = newX;
oldY = newY;
}
}
And used GL_MODELVIEW
to draw the planets.
the glPushMatrix
and glPopMatrix
functions are used to save the current state of the matrix and restore it later. This is used to draw the moon around the earth.
If I did not use the glPushMatrix
and glPopMatrix
the earth would go 5 points up in a loop hence we could not see the earth and moon rotating.
The {}
are used to create a scope, so that the glPushMatrix
and glPopMatrix
functions are used only for the earth and moon.
I scaled down the moon and earth to make it look like a solar system. Also created a separate variable for the angle of the moon, so that it rotates much faster around the earth.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(0.1, 0.1, 1);
float angle = 0;
float angleMoon = 0;
// render loop
while (!glfwWindowShouldClose(window))
{
angle += 1;
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
// sun
drawCircle(0, 1, 0);
{
// earth
glPushMatrix();
glRotatef(angle, 0, 0, 1);
glTranslatef(0,5,0);
glScalef(0.5, 0.5, 1);
drawCircle(0, 0.3, 1);
{
// moon
glPushMatrix();
glRotatef(angleMoon, 0, 0, 1);
glTranslatef(0, 2, 0);
glScalef(0.3, 0.3, 1);
drawCircle(0.5, 0.5, 0.5);
glPopMatrix();
angleMoon += 5;
}
glPopMatrix();
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
6. Trying shaders
I learned how sharders are set for the vertex and fragment. I also learned how to set the color of the triangle in the fragment shader.
I tried creating a cube with two triangles giving both different colors.
7. Drawing a texture rectangle sprite
// vertex shader source
const GLchar* vertex120 = R"END(
#version 120
attribute vec3 inPosition;
attribute vec2 inUvs;
varying vec2 outUvs;
uniform mat4 matrix;
void main()
{
outUvs = inUvs;
gl_Position = matrix * vec4(inPosition,1.f);
}
)END";
// fragment shader source
const GLchar* raster120 = R"END(
#version 120
uniform vec2 res;
uniform float time;
varying vec2 outUvs;
uniform sampler2D tex; // 1st texture slot by default
void main()
{
gl_FragColor = texture2D(tex, outUvs);
}
)END";
I assigned the raster120
framgment shader to the shader fragrment and also the vertex120
vertex shader to the shader vertex.
and then created a shader created a shader program to attach both of them to the shader program.
// ------------- VERTEX SHADER
source = vertex120;
GLuint shaderVertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shaderVertex,1,&source,0);
glCompileShader(shaderVertex);
glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &compilationStatus);
if (compilationStatus == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderVertex, sizeof(messages), 0, &messages[0]); std::cout << messages;
exit(1);
}
// ---------- FRAGMENT SHADER
source = raster120;
GLuint shaderFragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shaderFragment,1,&source,0);
glCompileShader(shaderFragment);
glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &compilationStatus);
if (compilationStatus == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderFragment, sizeof(messages), 0, &messages[0]); std::cout << messages;
exit(1);
}
// ------------- SHADER PROGRAM
GLint linkStatus;
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram,shaderVertex);
glAttachShader(shaderProgram,shaderFragment);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram,GL_LINK_STATUS,&linkStatus);
if (linkStatus == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(shaderProgram,sizeof(messages),0,&messages[0]);
std::cout << messages;
exit(1);
}
glUseProgram(shaderProgram);
I then created vbo’s and uvs, added pixel texture and ran the shader program.
8. Loading a bmp texture
I tried adding a bmp texture to a simple rectangle to just show the entire texture. I learned how to load a bmp texture and how to set it to the rectangle.
Error I faced
I faced an error while loading the texture, the texture was not loading and the application did not run. I am still stuck on this maybe because opengl is sensitive to the bitmap format. I requires 32 bit bmp format. I will update this log if I find a solution.
9. Cube with shared and Unique vertices.
Shared Vertex Cube (8 vertices):
I learned how to create a cube with shared vertices and unique vertices. I also learned how to set the color of the cube in the fragment shader.
The cube is made up of 8 vertices, and each vertex is shared by 3 faces. The cube is made up of 6 faces, and each face is made up of 2 triangles. The cube is made up of 12 triangles.
3-------2
/| /|
/ | / |
7-------6 |
| | | |
| 0----|--1
| / | /
4-------5
- Vertices are shared among faces.
- Vertex 2 is part of the front, right, and top faces.
- Coloring Vertex 2 one color will affect all three faces.
- Colors will be interpolated between shared vertices, mixing at edges.
Unique Vertex Cube (24 vertices):
Front Face Vertices (4 unique):
3'------2'
/ /
/ /
4'------1'
Right Face Vertices (4 unique):
2''-----6'
/ /
/ /
1''------5'
Top Face Vertices (4 unique):
6''-----2'''
/ /
/ /
5''------1'''
- Each face has 4 unique vertices, not shared with other faces.
- Vertex 2 is replicated three times (2’, 2”, 2''') for the front, right, and top faces.
- Each instance of Vertex 2 can have a different color, giving each face a unique color.
- No color interpolation between faces; each face is a solid color.
Github Repo
I have created a github repo for this project, you can check it out here. Github