Code re-work: Advanced OpenGL

This commit is contained in:
Joey de Vries
2017-04-19 22:05:36 +02:00
parent 4b6b4d6377
commit c763be2c08
25 changed files with 1282 additions and 1208 deletions

View File

@@ -183,7 +183,7 @@ int main()
// render // render
// ------ // ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use(); shader.use();

View File

@@ -183,7 +183,7 @@ int main()
// render // render
// ------ // ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use(); shader.use();

View File

@@ -187,7 +187,7 @@ int main()
// render // render
// ------ // ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // don't forget to clear the stencil buffer! glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // don't forget to clear the stencil buffer!
// set uniforms // set uniforms

View File

@@ -70,7 +70,6 @@ int main()
// configure global opengl state // configure global opengl state
// ----------------------------- // -----------------------------
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS); // always pass the depth test (same effect as glDisable(GL_DEPTH_TEST))
// build and compile shaders // build and compile shaders
// ------------------------- // -------------------------
@@ -183,7 +182,7 @@ int main()
// render // render
// ------ // ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

View File

@@ -70,7 +70,6 @@ int main()
// configure global opengl state // configure global opengl state
// ----------------------------- // -----------------------------
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS); // always pass the depth test (same effect as glDisable(GL_DEPTH_TEST))
// build and compile shaders // build and compile shaders
// ------------------------- // -------------------------
@@ -183,7 +182,7 @@ int main()
// render // render
// ------ // ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

View File

@@ -1,11 +1,11 @@
#version 330 core #version 330 core
in vec2 TexCoords; out vec4 FragColor;
out vec4 color; in vec2 TexCoords;
uniform sampler2D texture1; uniform sampler2D texture1;
void main() void main()
{ {
color = texture(texture1, TexCoords); FragColor = texture(texture1, TexCoords);
} }

View File

@@ -1,6 +1,6 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 texCoords; layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords; out vec2 TexCoords;
@@ -10,6 +10,6 @@ uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0f); TexCoords = aTexCoords;
TexCoords = texCoords; gl_Position = projection * view * model * vec4(aPos, 1.0);
} }

View File

@@ -1,40 +1,12 @@
#version 330 core #version 330 core
in vec2 TexCoords; out vec4 FragColor;
out vec4 color; in vec2 TexCoords;
uniform sampler2D screenTexture; uniform sampler2D screenTexture;
const float offset = 1.0 / 300;
void main() void main()
{ {
vec2 offsets[9] = vec2[]( vec3 col = texture(screenTexture, TexCoords).rgb;
vec2(-offset, offset), // top-left FragColor = vec4(col, 1.0);
vec2(0.0f, offset), // top-center
vec2(offset, offset), // top-right
vec2(-offset, 0.0f), // center-left
vec2(0.0f, 0.0f), // center-center
vec2(offset, 0.0f), // center-right
vec2(-offset, -offset), // bottom-left
vec2(0.0f, -offset), // bottom-center
vec2(offset, -offset) // bottom-right
);
float kernel[9] = float[](
-1, -1, -1,
-1, 9, -1,
-1, -1, -1
);
vec3 sampleTex[9];
for(int i = 0; i < 9; i++)
{
sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i]));
}
vec3 col;
for(int i = 0; i < 9; i++)
col += sampleTex[i] * kernel[i];
color = vec4(col, 1.0);
} }

View File

@@ -1,11 +1,11 @@
#version 330 core #version 330 core
layout (location = 0) in vec2 position; layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 texCoords; layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords; out vec2 TexCoords;
void main() void main()
{ {
gl_Position = vec4(position.x, position.y, 0.0f, 1.0f); TexCoords = aTexCoords;
TexCoords = texCoords; gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
} }

View File

@@ -1,87 +1,85 @@
// Std. Includes #include <glad/glad.h>
#include <string>
#include <algorithm>
using namespace std;
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadTexture(GLchar const * path, GLboolean alpha = false); void processInput(GLFWwindow *window);
GLuint generateAttachmentTexture(GLboolean depth, GLboolean stencil); unsigned int loadTexture(const char *path);
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024]; float lastX = (float)SCR_WIDTH / 2.0;
GLfloat lastX = 400, lastY = 300; float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true; bool firstMouse = true;
GLfloat deltaTime = 0.0f; // timing
GLfloat lastFrame = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, screenWidth, screenHeight); // -----------------------------
glEnable(GL_DEPTH_TEST);
// Setup some OpenGL options // build and compile shaders
glDepthFunc(GL_LESS); // -------------------------
Shader shader("5.1.framebuffers.vs", "5.1.framebuffers.fs");
Shader screenShader("5.1.framebuffers_screen.vs", "5.1.framebuffers_screen.fs");
// Setup and compile our shaders // set up vertex data (and buffer(s)) and configure vertex attributes
Shader shader("framebuffers.vs", "framebuffers.frag"); // ------------------------------------------------------------------
Shader screenShader("framebuffers_screen.vs", "framebuffers_screen.frag"); float cubeVertices[] = {
// positions // texture Coords
#pragma region "object_initialization"
// Set the object data (buffers, vertex attributes)
GLfloat cubeVertices[] = {
// Positions // Texture Coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
@@ -124,18 +122,18 @@ int main()
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
}; };
GLfloat floorVertices[] = { float planeVertices[] = {
// Positions // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat) // positions // texture Coords
5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, 5.0f, 0.0f, 0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, -5.0f, 2.0f, 2.0f 5.0f, -0.5f, -5.0f, 2.0f, 2.0f
}; };
GLfloat quadVertices[] = { // Vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// Positions // TexCoords // positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f,
@@ -144,242 +142,202 @@ int main()
1.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f 1.0f, 1.0f, 1.0f, 1.0f
}; };
// cube VAO
// Setup cube VAO unsigned int cubeVAO, cubeVBO;
GLuint cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // plane VAO
// Setup plane VAO unsigned int planeVAO, planeVBO;
GLuint floorVAO, floorVBO; glGenVertexArrays(1, &planeVAO);
glGenVertexArrays(1, &floorVAO); glGenBuffers(1, &planeVBO);
glGenBuffers(1, &floorVBO); glBindVertexArray(planeVAO);
glBindVertexArray(floorVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ARRAY_BUFFER, floorVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), &floorVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // screen quad VAO
// Setup screen VAO unsigned int quadVAO, quadVBO;
GLuint quadVAO, quadVBO;
glGenVertexArrays(1, &quadVAO); glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO); glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO); glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindVertexArray(0);
// Load textures // load textures
GLuint cubeTexture = loadTexture(FileSystem::getPath("resources/textures/container.jpg").c_str()); // -------------
GLuint floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str()); unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str());
#pragma endregion unsigned int floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str());
// Framebuffers // shader configuration
GLuint framebuffer; // --------------------
shader.use();
shader.setInt("texture1", 0);
screenShader.use();
screenShader.setInt("screenTexture", 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Create a color attachment texture // create a color attachment texture
GLuint textureColorbuffer = generateAttachmentTexture(false, false); unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
// Create a renderbuffer object for depth and stencil attachment (we won't be sampling these) // create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
GLuint rbo; unsigned int rbo;
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); // Use a single renderbuffer object for both a depth AND stencil buffer. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // use a single renderbuffer object for both a depth AND stencil buffer.
glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // Now actually attach it // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
// Now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl; cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// draw as wireframe
// Draw as wireframe
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Game loop // render loop
while(!glfwWindowShouldClose(window)) // -----------
while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
///////////////////////////////////////////////////// // render
// Bind to framebuffer and draw to color texture // ------
// as we normally would. // bind to framebuffer and draw scene as we normally would to color texture
// //////////////////////////////////////////////////
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Clear all attached buffers glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We're not using stencil buffer so why bother with clearing?
glEnable(GL_DEPTH_TEST); // make sure we clear the framebuffer's content
// Set uniforms glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
shader.Use(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use();
glm::mat4 model; glm::mat4 model;
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); shader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); shader.setMat4("projection", projection);
// cubes
// Floor
glBindVertexArray(floorVAO);
glBindTexture(GL_TEXTURE_2D, floorTexture);
model = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// Cubes
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture); glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); // floor
glBindVertexArray(planeVAO);
///////////////////////////////////////////////////// glBindTexture(GL_TEXTURE_2D, floorTexture);
// Bind to default framebuffer again and draw the shader.setMat4("model", glm::mat4());
// quad plane with attched screen texture.
// //////////////////////////////////////////////////
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear all relevant buffers
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); // We don't care about depth information when rendering a single quad
// Draw Screen
screenShader.Use();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // Use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0); glBindVertexArray(0);
// now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
// clear all relevant buffers
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
glClear(GL_COLOR_BUFFER_BIT);
// Swap the buffers screenShader.use();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
// Clean up // optional: de-allocate all resources once they've outlived their purpose:
glDeleteFramebuffers(1, &framebuffer); // ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &planeVAO);
glDeleteVertexArrays(1, &quadVAO);
glDeleteBuffers(1, &cubeVBO);
glDeleteBuffers(1, &planeVBO);
glDeleteBuffers(1, &quadVBO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
// This function loads a texture from file. Note: texture loading functions like these are usually // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio). // ---------------------------------------------------------------------------------------------------------
// For learning purposes we'll just define it as a utility function. void processInput(GLFWwindow *window)
GLuint loadTexture(GLchar const * path, GLboolean alpha)
{ {
//Generate texture ID and load texture data if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
GLuint textureID; glfwSetWindowShouldClose(window, true);
glGenTextures(1, &textureID);
int width,height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, alpha ? SOIL_LOAD_RGBA : SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, alpha ? GL_RGBA : GL_RGB, width, height, 0, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Parameters float cameraSpeed = 2.5 * deltaTime;
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT ); // Use GL_MIRRORED_REPEAT to prevent white borders. Due to interpolation it takes value from next repeat if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
// Generates a texture that is suited for attachments to a framebuffer
GLuint generateAttachmentTexture(GLboolean depth, GLboolean stencil)
{
// What enum to use?
GLenum attachment_type;
if(!depth && !stencil)
attachment_type = GL_RGB;
else if(depth && !stencil)
attachment_type = GL_DEPTH_COMPONENT;
else if(!depth && stencil)
attachment_type = GL_STENCIL_INDEX;
//Generate texture ID and load texture data
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
if(!depth && !stencil)
glTexImage2D(GL_TEXTURE_2D, 0, attachment_type, screenWidth, screenHeight, 0, attachment_type, GL_UNSIGNED_BYTE, NULL);
else // Using both a stencil and depth test, needs special format arguments
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, screenWidth, screenHeight, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
return textureID;
}
#pragma region "User input"
// Moves/alters the camera positions based on user input
void Do_Movement()
{
// Camera controls
if(keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if(keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if(keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if(keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
} }
// Is called whenever a key is pressed/released via GLFW // glfw: whenever the window size changed (by OS or user resize) this callback function executes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) // ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // make sure the viewport matches the new window dimensions; note that width and
glfwSetWindowShouldClose(window, GL_TRUE); // height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
if(action == GLFW_PRESS)
keys[key] = true;
else if(action == GLFW_RELEASE)
keys[key] = false;
} }
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if(firstMouse) if (firstMouse)
{ {
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
@@ -387,9 +345,48 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
#pragma endregion // utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}

View File

@@ -1,87 +1,85 @@
// Std. Includes #include <glad/glad.h>
#include <string>
#include <algorithm>
using namespace std;
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadTexture(GLchar const * path, GLboolean alpha = false); void processInput(GLFWwindow *window);
GLuint generateAttachmentTexture(GLboolean depth, GLboolean stencil); unsigned int loadTexture(const char *path);
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024]; float lastX = (float)SCR_WIDTH / 2.0;
GLfloat lastX = 400, lastY = 300; float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true; bool firstMouse = true;
GLfloat deltaTime = 0.0f; // timing
GLfloat lastFrame = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, screenWidth, screenHeight); // -----------------------------
glEnable(GL_DEPTH_TEST);
// Setup some OpenGL options // build and compile shaders
glDepthFunc(GL_LESS); // -------------------------
Shader shader("5.1.framebuffers.vs", "5.1.framebuffers.fs");
Shader screenShader("5.1.framebuffers_screen.vs", "5.1.framebuffers_screen.fs");
// Setup and compile our shaders // set up vertex data (and buffer(s)) and configure vertex attributes
Shader shader("framebuffers.vs", "framebuffers.frag"); // ------------------------------------------------------------------
Shader screenShader("framebuffers_screen.vs", "framebuffers_screen.frag"); float cubeVertices[] = {
// positions // texture Coords
#pragma region "object_initialization"
// Set the object data (buffers, vertex attributes)
GLfloat cubeVertices[] = {
// Positions // Texture Coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
@@ -124,262 +122,256 @@ int main()
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
}; };
GLfloat floorVertices[] = { float planeVertices[] = {
// Positions // Texture Coords (note we set these higher than 1 that together with GL_REPEAT as texture wrapping mode will cause the floor texture to repeat) // positions // texture Coords
5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, 5.0f, 0.0f, 0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, 5.0f, 2.0f, 0.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f,
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f,
5.0f, -0.5f, -5.0f, 2.0f, 2.0f 5.0f, -0.5f, -5.0f, 2.0f, 2.0f
}; };
GLfloat quadVertices[] = { // Vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates. NOTE that this plane is now much smaller and at the top of the screen
// Positions // TexCoords // positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f, -0.3f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, -0.3f, 0.7f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.3f, 0.7f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, -0.3f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.3f, 0.7f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f 0.3f, 1.0f, 1.0f, 1.0f
}; };
// cube VAO
// Setup cube VAO unsigned int cubeVAO, cubeVBO;
GLuint cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // plane VAO
// Setup plane VAO unsigned int planeVAO, planeVBO;
GLuint floorVAO, floorVBO; glGenVertexArrays(1, &planeVAO);
glGenVertexArrays(1, &floorVAO); glGenBuffers(1, &planeVBO);
glGenBuffers(1, &floorVBO); glBindVertexArray(planeVAO);
glBindVertexArray(floorVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBindBuffer(GL_ARRAY_BUFFER, floorVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(floorVertices), &floorVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // screen quad VAO
// Setup screen VAO unsigned int quadVAO, quadVBO;
GLuint quadVAO, quadVBO;
glGenVertexArrays(1, &quadVAO); glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO); glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO); glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glBindVertexArray(0);
// Load textures // load textures
GLuint cubeTexture = loadTexture(FileSystem::getPath("resources/textures/container.jpg").c_str()); // -------------
GLuint floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str()); unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str());
#pragma endregion unsigned int floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str());
// Framebuffers // shader configuration
GLuint framebuffer; // --------------------
shader.use();
shader.setInt("texture1", 0);
screenShader.use();
screenShader.setInt("screenTexture", 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Create a color attachment texture // create a color attachment texture
GLuint textureColorbuffer = generateAttachmentTexture(false, false); unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
// Create a renderbuffer object for depth and stencil attachment (we won't be sampling these) // create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
GLuint rbo; unsigned int rbo;
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); // Use a single renderbuffer object for both a depth AND stencil buffer. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // use a single renderbuffer object for both a depth AND stencil buffer.
glBindRenderbuffer(GL_RENDERBUFFER, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // Now actually attach it // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
// Now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl; cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// draw as wireframe
// Draw as wireframe
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Game loop // render loop
while(!glfwWindowShouldClose(window)) // -----------
while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
///////////////////////////////////////////////////// // first render pass: mirror texture.
// Bind to framebuffer and draw to color texture // bind to framebuffer and draw to color texture as we normally
// as we normally would. // would, but with the view camera reversed.
// ////////////////////////////////////////////////// // bind to framebuffer and draw scene as we normally would to color texture
// ------------------------------------------------------------------------
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Clear all attached buffers glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
// make sure we clear the framebuffer's content
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We're not using stencil buffer so why bother with clearing? glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); shader.use();
// Set uniforms
shader.Use();
glm::mat4 model; glm::mat4 model;
camera.Yaw += 180.0f; // rotate the camera's yaw 180 degrees around
camera.Pitch += 180.0f; // rotate the camera's pitch 180 degrees around
camera.ProcessMouseMovement(0, 0, false); // call this to make sure it updates its camera vectors, note that we disable pitch constrains for this specific case (otherwise we can't reverse camera's pitch values)
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); camera.Yaw -= 180.0f; // reset it back to its original orientation
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); camera.Pitch -= 180.0f;
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); camera.ProcessMouseMovement(0, 0, true);
glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
// Floor shader.setMat4("view", view);
glBindVertexArray(floorVAO); shader.setMat4("projection", projection);
glBindTexture(GL_TEXTURE_2D, floorTexture); // cubes
model = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// Cubes
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture); glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f)); model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); // floor
glBindVertexArray(planeVAO);
///////////////////////////////////////////////////// glBindTexture(GL_TEXTURE_2D, floorTexture);
// Bind to default framebuffer again and draw the shader.setMat4("model", glm::mat4());
// quad plane with attched screen texture.
// //////////////////////////////////////////////////
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear all relevant buffers
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST); // We don't care about depth information when rendering a single quad
// Draw Screen
screenShader.Use();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // Use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6); glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0); glBindVertexArray(0);
// second render pass: draw as normal
// ----------------------------------
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Swap the buffers glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
model = glm::mat4();
view = camera.GetViewMatrix();
shader.setMat4("view", view);
// cubes
glBindVertexArray(cubeVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
shader.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
// floor
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, floorTexture);
shader.setMat4("model", glm::mat4());
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
// now draw the mirror quad with screen texture
// --------------------------------------------
glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
screenShader.use();
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // use the color attachment texture as the texture of the quad plane
glDrawArrays(GL_TRIANGLES, 0, 6);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
// Clean up // optional: de-allocate all resources once they've outlived their purpose:
glDeleteFramebuffers(1, &framebuffer); // ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &planeVAO);
glDeleteVertexArrays(1, &quadVAO);
glDeleteBuffers(1, &cubeVBO);
glDeleteBuffers(1, &planeVBO);
glDeleteBuffers(1, &quadVBO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
// This function loads a texture from file. Note: texture loading functions like these are usually // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio). // ---------------------------------------------------------------------------------------------------------
// For learning purposes we'll just define it as a utility function. void processInput(GLFWwindow *window)
GLuint loadTexture(GLchar const * path, GLboolean alpha)
{ {
//Generate texture ID and load texture data if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
GLuint textureID; glfwSetWindowShouldClose(window, true);
glGenTextures(1, &textureID);
int width,height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, alpha ? SOIL_LOAD_RGBA : SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, alpha ? GL_RGBA : GL_RGB, width, height, 0, alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Parameters float cameraSpeed = 2.5 * deltaTime;
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT ); // Use GL_MIRRORED_REPEAT to prevent white borders. Due to interpolation it takes value from next repeat if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, alpha ? GL_CLAMP_TO_EDGE : GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
// Generates a texture that is suited for attachments to a framebuffer
GLuint generateAttachmentTexture(GLboolean depth, GLboolean stencil)
{
// What enum to use?
GLenum attachment_type;
if(!depth && !stencil)
attachment_type = GL_RGB;
else if(depth && !stencil)
attachment_type = GL_DEPTH_COMPONENT;
else if(!depth && stencil)
attachment_type = GL_STENCIL_INDEX;
//Generate texture ID and load texture data
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
if(!depth && !stencil)
glTexImage2D(GL_TEXTURE_2D, 0, attachment_type, screenWidth, screenHeight, 0, attachment_type, GL_UNSIGNED_BYTE, NULL);
else // Using both a stencil and depth test, needs special format arguments
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, screenWidth, screenHeight, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
return textureID;
}
#pragma region "User input"
// Moves/alters the camera positions based on user input
void Do_Movement()
{
// Camera controls
if(keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if(keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if(keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if(keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
} }
// Is called whenever a key is pressed/released via GLFW // glfw: whenever the window size changed (by OS or user resize) this callback function executes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) // ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // make sure the viewport matches the new window dimensions; note that width and
glfwSetWindowShouldClose(window, GL_TRUE); // height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
if(action == GLFW_PRESS)
keys[key] = true;
else if(action == GLFW_RELEASE)
keys[key] = false;
} }
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if(firstMouse) if (firstMouse)
{ {
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
@@ -387,9 +379,48 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
#pragma endregion // utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}

View File

@@ -1,14 +1,11 @@
#version 330 core #version 330 core
in vec3 Normal; out vec4 FragColor;
in vec3 Position;
out vec4 color;
uniform vec3 cameraPos; in vec2 TexCoords;
uniform samplerCube skybox;
uniform sampler2D texture1;
void main() void main()
{ {
vec3 I = normalize(Position - cameraPos); FragColor = texture(texture1, TexCoords);
vec3 R = reflect(I, normalize(Normal));
color = texture(skybox, R);
} }

View File

@@ -1,9 +1,8 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 normal; layout (location = 1) in vec2 aTexCoords;
out vec3 Normal; out vec2 TexCoords;
out vec3 Position;
uniform mat4 model; uniform mat4 model;
uniform mat4 view; uniform mat4 view;
@@ -11,7 +10,6 @@ uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0f); TexCoords = aTexCoords;
Normal = mat3(transpose(inverse(model))) * normal; gl_Position = projection * view * model * vec4(aPos, 1.0f);
Position = vec3(model * vec4(position, 1.0f));
} }

View File

@@ -1,10 +1,11 @@
#version 330 core #version 330 core
out vec4 FragColor;
in vec3 TexCoords; in vec3 TexCoords;
out vec4 color;
uniform samplerCube skybox; uniform samplerCube skybox;
void main() void main()
{ {
color = texture(skybox, TexCoords); FragColor = texture(skybox, TexCoords);
} }

View File

@@ -1,14 +1,14 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 aPos;
out vec3 TexCoords; out vec3 TexCoords;
uniform mat4 projection; uniform mat4 projection;
uniform mat4 view; uniform mat4 view;
void main() void main()
{ {
vec4 pos = projection * view * vec4(position, 1.0); TexCoords = aPos;
vec4 pos = projection * view * vec4(aPos, 1.0);
gl_Position = pos.xyww; gl_Position = pos.xyww;
TexCoords = position;
} }

View File

@@ -1,356 +1,312 @@
// Std. Includes #include <glad/glad.h>
#include <string>
#include <algorithm>
using namespace std;
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadTexture(GLchar const * path); void processInput(GLFWwindow *window);
GLuint loadCubemap(std::vector<std::string> faces); unsigned int loadTexture(const char *path);
unsigned int loadCubemap(vector<std::string> faces);
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024]; float lastX = (float)SCR_WIDTH / 2.0;
GLfloat lastX = 400, lastY = 300; float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true; bool firstMouse = true;
GLfloat deltaTime = 0.0f; // timing
GLfloat lastFrame = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, screenWidth, screenHeight); // -----------------------------
// Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Setup and compile our shaders // build and compile shaders
Shader shader("cubemaps.vs", "cubemaps.frag"); // -------------------------
Shader skyboxShader("skybox.vs", "skybox.frag"); Shader shader("6.1.cubemaps.vs", "6.1.cubemaps.fs");
Shader skyboxShader("6.1.skybox.vs", "6.1.skybox.fs");
#pragma region "object_initialization" // set up vertex data (and buffer(s)) and configure vertex attributes
// Set the object data (buffers, vertex attributes) // ------------------------------------------------------------------
GLfloat cubeVertices[] = { float cubeVertices[] = {
// Positions // Normals // positions // texture Coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
}; };
GLfloat skyboxVertices[] = { float skyboxVertices[] = {
// Positions // positions
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f 1.0f, -1.0f, 1.0f
}; };
// Setup cube VAO // cube VAO
GLuint cubeVAO, cubeVBO; unsigned int cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // skybox VAO
// Setup skybox VAO unsigned int skyboxVAO, skyboxVBO;
GLuint skyboxVAO, skyboxVBO;
glGenVertexArrays(1, &skyboxVAO); glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO); glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO); glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO); glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
#pragma endregion // load textures
// -------------
unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str());
// Cubemap (Skybox) vector<std::string> faces
std::vector<std::string> faces; {
faces.push_back(FileSystem::getPath("resources/textures/skybox/right.jpg")); FileSystem::getPath("resources/textures/skybox/right.jpg"),
faces.push_back(FileSystem::getPath("resources/textures/skybox/left.jpg")); FileSystem::getPath("resources/textures/skybox/left.jpg"),
faces.push_back(FileSystem::getPath("resources/textures/skybox/top.jpg")); FileSystem::getPath("resources/textures/skybox/top.jpg"),
faces.push_back(FileSystem::getPath("resources/textures/skybox/bottom.jpg")); FileSystem::getPath("resources/textures/skybox/bottom.jpg"),
faces.push_back(FileSystem::getPath("resources/textures/skybox/back.jpg")); FileSystem::getPath("resources/textures/skybox/back.jpg"),
faces.push_back(FileSystem::getPath("resources/textures/skybox/front.jpg")); FileSystem::getPath("resources/textures/skybox/front.jpg")
GLuint skyboxTexture = loadCubemap(faces); };
unsigned int cubemapTexture = loadCubemap(faces);
// Draw as wireframe // shader configuration
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // --------------------
shader.use();
shader.setInt("texture1", 0);
// Game loop skyboxShader.use();
skyboxShader.setInt("skybox", 0);
// render loop
// -----------
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
// Clear buffers // render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw scene as normal
// Draw scene as normal shader.use();
shader.Use();
glm::mat4 model; glm::mat4 model;
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth / (float)screenHeight, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); shader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); shader.setMat4("projection", projection);
glUniform3f(glGetUniformLocation(shader.Program, "cameraPos"), camera.Position.x, camera.Position.y, camera.Position.z); // cubes
// Cubes
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeTexture);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); glBindVertexArray(0);
// Draw skybox as last // draw skybox as last
glDepthFunc(GL_LEQUAL); // Change depth function so depth test passes when values are equal to depth buffer's content glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when values are equal to depth buffer's content
skyboxShader.Use(); skyboxShader.use();
view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // Remove any translation component of the view matrix view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // remove translation from the view matrix
glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); skyboxShader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); skyboxShader.setMat4("projection", projection);
// skybox cube // skybox cube
glBindVertexArray(skyboxVAO); glBindVertexArray(skyboxVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); glBindVertexArray(0);
glDepthFunc(GL_LESS); // Set depth function back to default glDepthFunc(GL_LESS); // set depth function back to default
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// Swap the buffers // -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &skyboxVAO);
glDeleteBuffers(1, &cubeVBO);
glDeleteBuffers(1, &skyboxVAO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
// Loads a cubemap texture from 6 individual texture faces // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// Order should be: // ---------------------------------------------------------------------------------------------------------
// +X (right) void processInput(GLFWwindow *window)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)? (CHECK THIS)
// -Z (back)?
GLuint loadCubemap(std::vector<std::string> faces)
{ {
GLuint textureID; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glGenTextures(1, &textureID); glfwSetWindowShouldClose(window, true);
glActiveTexture(GL_TEXTURE0);
int width, height; float cameraSpeed = 2.5 * deltaTime;
unsigned char* image; if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
for (GLuint i = 0; i < faces.size(); i++)
{
image = SOIL_load_image(faces[i].c_str(), &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return textureID;
}
// This function loads a texture from file. Note: texture loading functions like these are usually
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio).
// For learning purposes we'll just define it as a utility function.
GLuint loadTexture(GLchar const * path)
{
//Generate texture ID and load texture data
GLuint textureID;
glGenTextures(1, &textureID);
int width, height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
#pragma region "User input"
// Moves/alters the camera positions based on user input
void Do_Movement()
{
// Camera controls
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
} }
// Is called whenever a key is pressed/released via GLFW // glfw: whenever the window size changed (by OS or user resize) this callback function executes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) // ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // make sure the viewport matches the new window dimensions; note that width and
glfwSetWindowShouldClose(window, GL_TRUE); // height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
} }
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if (firstMouse) if (firstMouse)
@@ -360,8 +316,8 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
@@ -369,9 +325,87 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
#pragma endregion // utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
// loads a cubemap texture from 6 individual texture faces
// order:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
// -------------------------------------------------------
unsigned int loadCubemap(vector<std::string> faces)
{
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrComponents;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrComponents, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}

View File

@@ -1,7 +1,8 @@
#version 330 core #version 330 core
out vec4 FragColor;
in vec3 Normal; in vec3 Normal;
in vec3 Position; in vec3 Position;
out vec4 color;
uniform vec3 cameraPos; uniform vec3 cameraPos;
uniform samplerCube skybox; uniform samplerCube skybox;
@@ -10,5 +11,5 @@ void main()
{ {
vec3 I = normalize(Position - cameraPos); vec3 I = normalize(Position - cameraPos);
vec3 R = reflect(I, normalize(Normal)); vec3 R = reflect(I, normalize(Normal));
color = texture(skybox, R); FragColor = vec4(texture(skybox, R).rgb, 1.0);
} }

View File

@@ -1,6 +1,6 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 normal; layout (location = 1) in vec3 aNormal;
out vec3 Normal; out vec3 Normal;
out vec3 Position; out vec3 Position;
@@ -11,7 +11,7 @@ uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0f); Normal = mat3(transpose(inverse(model))) * aNormal;
Normal = mat3(transpose(inverse(model))) * normal; Position = vec3(model * vec4(aPos, 1.0));
Position = vec3(model * vec4(position, 1.0f)); gl_Position = projection * view * model * vec4(aPos, 1.0);
} }

View File

@@ -1,356 +1,311 @@
// Std. Includes #include <glad/glad.h>
#include <string>
#include <algorithm>
using namespace std;
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
#include <learnopengl/filesystem.h> #include <learnopengl/filesystem.h>
#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
GLuint loadTexture(GLchar const * path); void processInput(GLFWwindow *window);
GLuint loadCubemap(std::vector<std::string> faces); unsigned int loadTexture(const char *path);
unsigned int loadCubemap(vector<std::string> faces);
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024]; float lastX = (float)SCR_WIDTH / 2.0;
GLfloat lastX = 400, lastY = 300; float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true; bool firstMouse = true;
GLfloat deltaTime = 0.0f; // timing
GLfloat lastFrame = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, screenWidth, screenHeight); // -----------------------------
// Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Setup and compile our shaders // build and compile shaders
Shader shader("cubemaps.vs", "cubemaps.frag"); // -------------------------
Shader skyboxShader("skybox.vs", "skybox.frag"); Shader shader("6.2.cubemaps.vs", "6.2.cubemaps.fs");
Shader skyboxShader("6.1.skybox.vs", "6.1.skybox.fs");
#pragma region "object_initialization" // set up vertex data (and buffer(s)) and configure vertex attributes
// Set the object data (buffers, vertex attributes) // ------------------------------------------------------------------
GLfloat cubeVertices[] = { float cubeVertices[] = {
// Positions // Normals // positions // normals
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
}; };
GLfloat skyboxVertices[] = { float skyboxVertices[] = {
// Positions // positions
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f 1.0f, -1.0f, 1.0f
}; };
// Setup cube VAO // cube VAO
GLuint cubeVAO, cubeVBO; unsigned int cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glBindVertexArray(0); // skybox VAO
// Setup skybox VAO unsigned int skyboxVAO, skyboxVBO;
GLuint skyboxVAO, skyboxVBO;
glGenVertexArrays(1, &skyboxVAO); glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO); glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO); glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO); glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
#pragma endregion // load textures
// -------------
vector<std::string> faces
{
FileSystem::getPath("resources/textures/skybox/right.jpg"),
FileSystem::getPath("resources/textures/skybox/left.jpg"),
FileSystem::getPath("resources/textures/skybox/top.jpg"),
FileSystem::getPath("resources/textures/skybox/bottom.jpg"),
FileSystem::getPath("resources/textures/skybox/back.jpg"),
FileSystem::getPath("resources/textures/skybox/front.jpg")
};
unsigned int cubemapTexture = loadCubemap(faces);
// Cubemap (Skybox) // shader configuration
std::vector<std::string> faces; // --------------------
faces.push_back(FileSystem::getPath("resources/textures/skybox/right.jpg")); shader.use();
faces.push_back(FileSystem::getPath("resources/textures/skybox/left.jpg")); shader.setInt("skybox", 0);
faces.push_back(FileSystem::getPath("resources/textures/skybox/top.jpg"));
faces.push_back(FileSystem::getPath("resources/textures/skybox/bottom.jpg"));
faces.push_back(FileSystem::getPath("resources/textures/skybox/back.jpg"));
faces.push_back(FileSystem::getPath("resources/textures/skybox/front.jpg"));
GLuint skyboxTexture = loadCubemap(faces);
// Draw as wireframe skyboxShader.use();
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); skyboxShader.setInt("skybox", 0);
// Game loop // render loop
// -----------
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
// Clear buffers // render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw scene as normal
// Draw scene as normal shader.use();
shader.Use();
glm::mat4 model; glm::mat4 model;
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth / (float)screenHeight, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shader.setMat4("model", model);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); shader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); shader.setMat4("projection", projection);
glUniform3f(glGetUniformLocation(shader.Program, "cameraPos"), camera.Position.x, camera.Position.y, camera.Position.z); shader.setVec3("cameraPos", camera.Position);
// Cubes // cubes
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); glBindVertexArray(0);
// Draw skybox as last // draw skybox as last
glDepthFunc(GL_LEQUAL); // Change depth function so depth test passes when values are equal to depth buffer's content glDepthFunc(GL_LEQUAL); // change depth function so depth test passes when values are equal to depth buffer's content
skyboxShader.Use(); skyboxShader.use();
view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // Remove any translation component of the view matrix view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // remove translation from the view matrix
glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); skyboxShader.setMat4("view", view);
glUniformMatrix4fv(glGetUniformLocation(skyboxShader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); skyboxShader.setMat4("projection", projection);
// skybox cube // skybox cube
glBindVertexArray(skyboxVAO); glBindVertexArray(skyboxVAO);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0); glBindVertexArray(0);
glDepthFunc(GL_LESS); // Set depth function back to default glDepthFunc(GL_LESS); // set depth function back to default
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// Swap the buffers // -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &skyboxVAO);
glDeleteBuffers(1, &cubeVBO);
glDeleteBuffers(1, &skyboxVAO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
// Loads a cubemap texture from 6 individual texture faces // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// Order should be: // ---------------------------------------------------------------------------------------------------------
// +X (right) void processInput(GLFWwindow *window)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)? (CHECK THIS)
// -Z (back)?
GLuint loadCubemap(std::vector<std::string> faces)
{ {
GLuint textureID; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glGenTextures(1, &textureID); glfwSetWindowShouldClose(window, true);
glActiveTexture(GL_TEXTURE0);
int width, height; float cameraSpeed = 2.5 * deltaTime;
unsigned char* image; if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
for (GLuint i = 0; i < faces.size(); i++)
{
image = SOIL_load_image(faces[i].c_str(), &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return textureID;
}
// This function loads a texture from file. Note: texture loading functions like these are usually
// managed by a 'Resource Manager' that manages all resources (like textures, models, audio).
// For learning purposes we'll just define it as a utility function.
GLuint loadTexture(GLchar const * path)
{
//Generate texture ID and load texture data
GLuint textureID;
glGenTextures(1, &textureID);
int width, height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
// Parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
return textureID;
}
#pragma region "User input"
// Moves/alters the camera positions based on user input
void Do_Movement()
{
// Camera controls
if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if (keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if (keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if (keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
} }
// Is called whenever a key is pressed/released via GLFW // glfw: whenever the window size changed (by OS or user resize) this callback function executes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) // ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // make sure the viewport matches the new window dimensions; note that width and
glfwSetWindowShouldClose(window, GL_TRUE); // height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
} }
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if (firstMouse) if (firstMouse)
@@ -360,8 +315,8 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
@@ -369,9 +324,87 @@ void mouse_callback(GLFWwindow* window, double xpos, double ypos)
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
#pragma endregion // utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
// loads a cubemap texture from 6 individual texture faces
// order:
// +X (right)
// -X (left)
// +Y (top)
// -Y (bottom)
// +Z (front)
// -Z (back)
// -------------------------------------------------------
unsigned int loadCubemap(vector<std::string> faces)
{
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrComponents;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrComponents, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}

View File

@@ -1,5 +1,5 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 aPos;
layout (std140) uniform Matrices layout (std140) uniform Matrices
{ {
@@ -10,5 +10,5 @@ uniform mat4 model;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0); gl_Position = projection * view * model * vec4(aPos, 1.0);
} }

View File

@@ -1,7 +1,7 @@
#version 330 core #version 330 core
out vec4 color; out vec4 FragColor;
void main() void main()
{ {
color = vec4(0.0, 0.0, 1.0, 1.0); FragColor = vec4(0.0, 0.0, 1.0, 1.0);
} }

View File

@@ -1,7 +1,7 @@
#version 330 core #version 330 core
out vec4 color; out vec4 FragColor;
void main() void main()
{ {
color = vec4(0.0, 1.0, 0.0, 1.0); FragColor = vec4(0.0, 1.0, 0.0, 1.0);
} }

View File

@@ -1,7 +1,7 @@
#version 330 core #version 330 core
out vec4 color; out vec4 FragColor;
void main() void main()
{ {
color = vec4(1.0, 0.0, 0.0, 1.0); FragColor = vec4(1.0, 0.0, 0.0, 1.0);
} }

View File

@@ -1,7 +1,7 @@
#version 330 core #version 330 core
out vec4 color; out vec4 FragColor;
void main() void main()
{ {
color = vec4(1.0, 1.0, 0.0, 1.0); FragColor = vec4(1.0, 1.0, 0.0, 1.0);
} }

View File

@@ -1,84 +1,90 @@
// GLEW #include <glad/glad.h>
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h>
// GL includes
#include <learnopengl/shader.h>
#include <learnopengl/camera.h>
// GLM Mathemtics
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// Other Libs #include <learnopengl/filesystem.h>
#include <SOIL.h> #include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Properties #include <iostream>
GLuint screenWidth = 800, screenHeight = 600;
// Function prototypes void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void Do_Movement(); void processInput(GLFWwindow *window);
// Camera // settings
const unsigned int SCR_WIDTH = 1280;
const unsigned int SCR_HEIGHT = 720;
// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
bool keys[1024]; float lastX = (float)SCR_WIDTH / 2.0;
GLfloat lastX = 400, lastY = 300; float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true; bool firstMouse = true;
GLfloat deltaTime = 0.0f; // timing
GLfloat lastFrame = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f;
// The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // glfw: initialize and configure
// ------------------------------
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed // glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (window == NULL)
// Set the required callback functions {
glfwSetKeyCallback(window, key_callback); std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
// Options // tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // glad: load all OpenGL function pointers
glewExperimental = GL_TRUE; // ---------------------------------------
glewInit(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// Define the viewport dimensions // configure global opengl state
glViewport(0, 0, screenWidth, screenHeight); // -----------------------------
// Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// Setup and compile our shaders // build and compile shaders
Shader shaderRed("uniform_buffers.vs", "red.frag"); // -------------------------
Shader shaderGreen("uniform_buffers.vs", "green.frag"); Shader shaderRed("8.advanced_glsl.vs", "8.red.fs");
Shader shaderBlue("uniform_buffers.vs", "blue.frag"); Shader shaderGreen("8.advanced_glsl.vs", "8.green.fs");
Shader shaderYellow("uniform_buffers.vs", "yellow.frag"); Shader shaderBlue("8.advanced_glsl.vs", "8.blue.fs");
Shader shaderYellow("8.advanced_glsl.vs", "8.yellow.fs");
#pragma region "object_initialization" // set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
GLfloat cubeVertices[] = { float cubeVertices[] = {
// positions
-0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
@@ -95,11 +101,11 @@ int main()
-0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f,
0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f,
@@ -109,154 +115,160 @@ int main()
-0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, 0.5f
}; };
// cube VAO
// Setup cube VAO unsigned int cubeVAO, cubeVBO;
GLuint cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO); glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO); glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0);
#pragma endregion // configure a uniform buffer object
// ---------------------------------
// Create a uniform buffer object // first. We get the relevant block indices
// First. We get the relevant block indices unsigned int uniformBlockIndexRed = glGetUniformBlockIndex(shaderRed.ID, "Matrices");
GLuint uniformBlockIndexRed = glGetUniformBlockIndex(shaderRed.Program, "Matrices"); unsigned int uniformBlockIndexGreen = glGetUniformBlockIndex(shaderGreen.ID, "Matrices");
GLuint uniformBlockIndexGreen = glGetUniformBlockIndex(shaderGreen.Program, "Matrices"); unsigned int uniformBlockIndexBlue = glGetUniformBlockIndex(shaderBlue.ID, "Matrices");
GLuint uniformBlockIndexBlue = glGetUniformBlockIndex(shaderBlue.Program, "Matrices"); unsigned int uniformBlockIndexYellow = glGetUniformBlockIndex(shaderYellow.ID, "Matrices");
GLuint uniformBlockIndexYellow = glGetUniformBlockIndex(shaderYellow.Program, "Matrices"); // then we link each shader's uniform block to this uniform binding point
// Then we link each shader's uniform block to this uniform binding point glUniformBlockBinding(shaderRed.ID, uniformBlockIndexRed, 0);
glUniformBlockBinding(shaderRed.Program, uniformBlockIndexRed, 0); glUniformBlockBinding(shaderGreen.ID, uniformBlockIndexGreen, 0);
glUniformBlockBinding(shaderGreen.Program, uniformBlockIndexGreen, 0); glUniformBlockBinding(shaderBlue.ID, uniformBlockIndexBlue, 0);
glUniformBlockBinding(shaderBlue.Program, uniformBlockIndexBlue, 0); glUniformBlockBinding(shaderYellow.ID, uniformBlockIndexYellow, 0);
glUniformBlockBinding(shaderYellow.Program, uniformBlockIndexYellow, 0);
// Now actually create the buffer // Now actually create the buffer
GLuint uboMatrices; unsigned int uboMatrices;
glGenBuffers(1, &uboMatrices); glGenBuffers(1, &uboMatrices);
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW); glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
// Define the range of the buffer that links to a uniform binding point // define the range of the buffer that links to a uniform binding point
glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4)); glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4));
// Store the projection matrix (we only have to do this once) (note: we're not using zoom anymore by changing the FoV. We only create the projection matrix once now) // store the projection matrix (we only do this once now) (note: we're not using zoom anymore by changing the FoV)
glm::mat4 projection = glm::perspective(45.0f, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(45.0f, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection)); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
// render loop
// Game loop // -----------
while(!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Set frame time // per-frame time logic
GLfloat currentFrame = glfwGetTime(); // --------------------
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame; lastFrame = currentFrame;
// Check and call events // input
glfwPollEvents(); // -----
Do_Movement(); processInput(window);
// Clear buffers // render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set the view and projection matrix in the uniform block - we only have to do this once per loop iteration. // set the view and projection matrix in the uniform block - we only have to do this once per loop iteration.
glm::mat4 view = camera.GetViewMatrix(); glm::mat4 view = camera.GetViewMatrix();
glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices); glBindBuffer(GL_UNIFORM_BUFFER, uboMatrices);
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view)); glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
// Draw 4 cubes // draw 4 cubes
// RED // RED
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
shaderRed.Use(); shaderRed.use();
glm::mat4 model; glm::mat4 model;
model = glm::translate(model, glm::vec3(-0.75f, 0.75f, 0.0f)); // Move top-left model = glm::translate(model, glm::vec3(-0.75f, 0.75f, 0.0f)); // move top-left
glUniformMatrix4fv(glGetUniformLocation(shaderRed.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shaderRed.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
// GREEN // GREEN
shaderGreen.Use(); shaderGreen.use();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(0.75f, 0.75f, 0.0f)); // Move top-right model = glm::translate(model, glm::vec3(0.75f, 0.75f, 0.0f)); // move top-right
glUniformMatrix4fv(glGetUniformLocation(shaderGreen.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shaderGreen.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
// BLUE
shaderBlue.Use();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-0.75f, -0.75f, 0.0f)); // Move bottom-left
glUniformMatrix4fv(glGetUniformLocation(shaderBlue.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
// YELLOW // YELLOW
shaderYellow.Use(); shaderYellow.use();
model = glm::mat4(); model = glm::mat4();
model = glm::translate(model, glm::vec3(0.75f, -0.75f, 0.0f)); // Move bottom-right model = glm::translate(model, glm::vec3(-0.75f, -0.75f, 0.0f)); // move bottom-left
glUniformMatrix4fv(glGetUniformLocation(shaderYellow.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); shaderYellow.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
// BLUE
shaderBlue.use();
model = glm::mat4();
model = glm::translate(model, glm::vec3(0.75f, -0.75f, 0.0f)); // move bottom-right
shaderBlue.setMat4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
// Swap the buffers // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &cubeVAO);
glDeleteBuffers(1, &cubeVBO);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
#pragma region "User input"
// Moves/alters the camera positions based on user input // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void Do_Movement() // ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{ {
// Camera controls if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
if(keys[GLFW_KEY_W]) glfwSetWindowShouldClose(window, true);
float cameraSpeed = 2.5 * deltaTime;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if(keys[GLFW_KEY_S]) if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if(keys[GLFW_KEY_A]) if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if(keys[GLFW_KEY_D]) if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
} }
// Is called whenever a key is pressed/released via GLFW // glfw: whenever the window size changed (by OS or user resize) this callback function executes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) // ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) // make sure the viewport matches the new window dimensions; note that width and
glfwSetWindowShouldClose(window, GL_TRUE); // height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
if(action == GLFW_PRESS)
keys[key] = true;
else if(action == GLFW_RELEASE)
keys[key] = false;
} }
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos) void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{ {
if(firstMouse) if (firstMouse)
{ {
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
firstMouse = false; firstMouse = false;
} }
GLfloat xoffset = xpos - lastX; float xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
#pragma endregion