The code used in the demonstration below was used to create a OpenGL window with a triangular prism object.
The demonstration was created using the resources available at https://learnopengl.com/
The code requires the GLFW, GLAD and glm libraries as dependencies, see the “Hello Triangle” example from the Learn OpenGL website for more details on how to obtain the source files and link the libraries to C++ Compilers in Microsoft Visual Studio.
The code allows for use of the arrow keys to be pressed individually to allow the point of view to be rotated 90 degrees from the initial point of view in the direction the button has been held. However, only one button pressed is registered at a time as part of this code (as of Version 1.0).
The demonstration was created in order to understand and show how to utilise OpenGL using C++ to generate Graphics Windows and Objects with changes to the shape type/colour, introduction of limited interactive actions (Arrow Keys, Escape Key) and the generation of custom shaders for graphics objects.
This code was created to use OpenGL 4.60 hence the use of
#version 460 core
Version 1.0 of the code is included below (Version 2.0: work in progress):
#include <GLAD/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
int WindowWidth = 1920;
int WindowHeight = 1080;
// Vertex Shader Position and Colour using OpenGL version 4.6
const char* vertexShaderSource = "#version 460 core\n"
"layout (location=0) in vec3 aPos;\n"
"layout (location=1) in vec3 aColor;\n"
"out vec3 ourColor;\n"
"uniform mat4 projection;\n"
"uniform mat4 view;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
"gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
"ourColor = aColor;\n"
"}\0";
// Vertex Shader Passing Colour Data to Fragment Shader using OpenGL version 4.6
const char* fragmentShaderSource = "#version 460 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(ourColor, 1.0);\n" // Fragment Colour - RGB values and alpha (transparency)
"}\0";
void framebuffer_size_callback(GLFWwindow* window, int width, int height) // Function Callback to respond to user
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) // Function to close window when the Escape Key is pressed.
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
float *camrotation(GLFWwindow* window) // Function to obtain camera rotation and upward direction for lookAt function from User Key Presses.
{
float camrot[6]{-1,0,0,0,1,0};
int index = 0;
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
camrot[index + 1] = 1;
camrot[index] = 0;
camrot[index + 4] = 0;
camrot[index + 3] = 1;
}
else {
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
camrot[index + 1] = -1;
camrot[index] = 0;
camrot[index + 4] = 0;
camrot[index + 3] = -1;
}
else {
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
camrot[index + 2] = -1;
camrot[index] = 0;
}
else {
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
camrot[index + 2] = 1;
camrot[index] = 0;
}
}
}
}
return camrot;
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE); // MAC OS X Only see original Note on Learn OpenGL.
GLFWwindow* window = glfwCreateWindow(WindowWidth, WindowHeight, "Triangular Prism", NULL, NULL);
if (window == NULL)
{
std::cout << "FailedtocreateGLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "FailedtoinitializeGLAD" << std::endl;
return -1;
}
glViewport(0, 0, WindowWidth, WindowHeight);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// Initialise Vertex Shader
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Compile Vertex Shader
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Check for successful compile of Vertex Shader
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Initialise Fragment Shader
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
// Compile Fragment Shader
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for successful compile of Fragment Shader
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
glEnable(GL_DEPTH_TEST);
// Initialise Shader Program
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
// Link Vertex and Fragment Shaders as Part of Program
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Check for successful Linking of Shader Program
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Define the use of new Shader Program
glUseProgram(shaderProgram);
// Delete Vertex and Fragment Shaders which are now linked under Shader Program and no longer needed
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)WindowWidth / (float)WindowHeight, 0.1f, 100.0f);
unsigned int projectionLoc = glGetUniformLocation(shaderProgram, "projection");
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
// render loop
while (!glfwWindowShouldClose(window))
{
// input
processInput(window);
// rendering commands here
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // Background Window Colour - RGB values and alpha (transparency)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Triangular Prism using Element Buffer Object - Position and Colour
float vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, // top right - Red and Green set to maximum value.
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom right - Red and Green set to minimum value.
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left - Red and Blue set to minimum value.
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, // top left - Red and Green set to maximum value.
0.0f, 0.5f, -0.86603f, 0.0f, 1.0f, 1.0f, // upper back - Green and Blue set to maximum value.
0.0f, -0.5f, -0.86603f, 0.0f, 0.0f, 0.0f // bottom back - Green and Blue set to minimum value.
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first triangle
1, 2, 3, // second triangle
4, 5, 0, // third triangle
5, 1, 0, // fourth triangle
3, 2, 4, // fifth triangle
2, 5, 4, // sixth triangle
0, 4, 3, // seventh triangle
1, 5, 2 // eighth triangle
};
/* Indices describes the triangles created from the vertices.
First and Second Triangle used to create the first rectangular face of the triangular prism.
Third and Fourth Triangle used to create the second rectangular face.
Fifth and Sixth Triangle used to create the third rectangular face.
Seventh Triangle used to create top triangular face.
Eighth Triangle used to create bottom triangular face.
*/
// Initialise Vertex Buffer Object - VBO
unsigned int VBO;
glGenBuffers(1, &VBO);
// Initialise Vertex Array Object - VAO
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// Initialise Element Buffer Object - EBO
unsigned int EBO;
glGenBuffers(1, &EBO);
// Bind VAO and VBO for attribute changes
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Bind EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//1. then set the vertex attributes pointers
//1a. position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//1a. color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//2. use our shader program when we want to render an object
glUseProgram(shaderProgram);
//2a. call function to determine if key pressed has changed the camera rotation.
float *campoint;
campoint = camrotation(window);
float camrot[6] = { -1,0,0,0,1,0 };
for (int index = 0; index < 6; index++) {
camrot[index] = *(campoint + index);
}
glm::mat4 view = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first
float radius = 5.0f;
float camX = camrot[0]*radius;
float camY = camrot[1]*radius;
float camZ = camrot[2]*radius;
float upX = camrot[3];
float upY = camrot[4];
float upZ = camrot[5];
view = glm::lookAt(glm::vec3(camX, camY, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(upX, upY, upZ));
unsigned int viewLoc = glGetUniformLocation(shaderProgram, "view");
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glm::mat4 model = glm::mat4(1.0f);
unsigned int modelLoc = glGetUniformLocation(shaderProgram, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(VAO);
//3. now draw the object
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Draw Shape as Line Drawing
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, 0);
// check and call events and swap the buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}


Leave a comment