New tutorial code

New tutorial code
This commit is contained in:
Joey de Vries
2015-06-20 11:55:58 +02:00
parent c4c3221de9
commit 635309ef0b
15 changed files with 885 additions and 388 deletions

View File

@@ -116,7 +116,7 @@ int main()
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// Render normal-mapped quad // Render normal-mapped quad
glm::mat4 model; glm::mat4 model;
model = glm::rotate(model, (GLfloat)glfwGetTime() * -10, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); // Rotates the quad to show parallax mapping works in all directions //model = glm::rotate(model, (GLfloat)glfwGetTime() * -10, glm::normalize(glm::vec3(1.0, 0.0, 1.0))); // Rotates the quad to show parallax mapping works in all directions
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniform3fv(glGetUniformLocation(shader.Program, "lightPos"), 1, &lightPos[0]); glUniform3fv(glGetUniformLocation(shader.Program, "lightPos"), 1, &lightPos[0]);
glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]); glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]);
@@ -282,9 +282,9 @@ void Do_Movement()
// Change parallax height scale // Change parallax height scale
if (keys[GLFW_KEY_Q]) if (keys[GLFW_KEY_Q])
height_scale -= 0.001; height_scale -= 0.05 * deltaTime;
else if (keys[GLFW_KEY_E]) else if (keys[GLFW_KEY_E])
height_scale += 0.001; height_scale += 0.05 * deltaTime;
// Enable/disable parallax mapping // Enable/disable parallax mapping
if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE]) if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE])

View File

@@ -22,8 +22,8 @@ vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
// return texCoords - viewDir.xy * (height * height_scale); // return texCoords - viewDir.xy * (height * height_scale);
// number of depth layers // number of depth layers
const float minLayers = 10; const float minLayers = 8;
const float maxLayers = 20; const float maxLayers = 32;
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir))); float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));
// calculate the size of each layer // calculate the size of each layer
float layerDepth = 1.0 / numLayers; float layerDepth = 1.0 / numLayers;

View File

@@ -1,6 +1,3 @@
// Std. Includes
#include <string>
// GLEW // GLEW
#define GLEW_STATIC #define GLEW_STATIC
#include <GL/glew.h> #include <GL/glew.h>
@@ -21,7 +18,7 @@
#include <SOIL.h> #include <SOIL.h>
// Properties // Properties
GLuint screenWidth = 800, screenHeight = 600; const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600;
// Function prototypes // Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
@@ -29,16 +26,24 @@ 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 Do_Movement();
GLuint loadTexture(GLchar* path); GLuint loadTexture(GLchar* path);
void RenderScene(Shader &shader);
void RenderCube();
void RenderQuad();
// Camera // Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
bool keys[1024];
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
// Delta
GLfloat deltaTime = 0.0f; GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f; GLfloat lastFrame = 0.0f;
// Options
GLboolean hdr = true; // Change with 'Space'
GLfloat exposure = 1.0f; // Change with Q and E
// Global variables
GLuint woodTexture;
// The MAIN function, from here we start our application and run our Game loop // The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
@@ -49,7 +54,7 @@ int main()
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
// Set the required callback functions // Set the required callback functions
@@ -65,103 +70,59 @@ int main()
glewInit(); glewInit();
// Define the viewport dimensions // Define the viewport dimensions
glViewport(0, 0, screenWidth, screenHeight); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
// Setup some OpenGL options // Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_ALWAYS); // Set to always pass the depth test (same effect as glDisable(GL_DEPTH_TEST))
// Setup and compile our shaders // Setup and compile our shaders
Shader shader("depth_testing.vs", "depth_testing.frag"); Shader shader("lighting.vs", "lighting.frag");
Shader hdrShader("hdr.vs", "hdr.frag");
#pragma region "object_initialization" // Light sources
// Set the object data (buffers, vertex attributes) // - Positions
GLfloat cubeVertices[] = { std::vector<glm::vec3> lightPositions;
// Positions // Texture Coords lightPositions.push_back(glm::vec3(0.0f, 0.0f, 49.5f)); // back light
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, lightPositions.push_back(glm::vec3(-1.4f, -1.9f, 9.0f));
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, lightPositions.push_back(glm::vec3(0.0f, -1.8f, 4.0f));
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, lightPositions.push_back(glm::vec3(0.8f, -1.7f, 6.0f));
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // - Colors
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, std::vector<glm::vec3> lightColors;
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f));
lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f));
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f));
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f));
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 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.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 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.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, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 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.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.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, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.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, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
GLfloat 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)
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, 2.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, 2.0f, 2.0f
};
// Setup cube VAO
GLuint cubeVAO, cubeVBO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
// Setup plane VAO
GLuint planeVAO, planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
// Load textures // Load textures
GLuint cubeTexture = loadTexture("../../../resources/textures/marble.jpg"); woodTexture = loadTexture("../../../resources/textures/wood.png");
GLuint floorTexture = loadTexture("../../../resources/textures/metal.png");
#pragma endregion // Set up floating point framebuffer to render scene to
GLuint hdrFBO;
glGenFramebuffers(1, &hdrFBO);
// - Create floating point color buffer
GLuint colorBuffer;
glGenTextures(1, &colorBuffer);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// - Create depth buffer (renderbuffer)
GLuint rboDepth;
glGenRenderbuffers(1, &rboDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT);
// - Attach buffers
glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
// Game loop // Game loop
while(!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Set frame time // Set frame time
GLfloat currentFrame = glfwGetTime(); GLfloat currentFrame = glfwGetTime();
@@ -172,35 +133,43 @@ int main()
glfwPollEvents(); glfwPollEvents();
Do_Movement(); Do_Movement();
// Clear the colorbuffer // 1. Render scene into floating point framebuffer
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 model;
shader.Use();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, woodTexture);
// - set lighting uniforms
for (GLuint i = 0; i < lightPositions.size(); i++)
{
glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]);
glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]);
}
glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]);
// - render tunnel
model = glm::mat4();
model = glm::translate(model, glm::vec3(0.0f, 0.0f, 25.0));
model = glm::scale(model, glm::vec3(5.0f, 5.0f, 55.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniform1i(glGetUniformLocation(shader.Program, "inverse_normals"), GL_TRUE);
RenderCube();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 2. Now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
hdrShader.Use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glUniform1i(glGetUniformLocation(hdrShader.Program, "hdr"), hdr);
glUniform1f(glGetUniformLocation(hdrShader.Program, "exposure"), exposure);
RenderQuad();
// Draw objects std::cout << "exposure: " << exposure << std::endl;
shader.Use();
glm::mat4 model;
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// Cubes
glBindVertexArray(cubeVAO);
glBindTexture(GL_TEXTURE_2D, cubeTexture); // We omit the glActiveTexture part since TEXTURE0 is already the default active texture unit. (sampler used in fragment is set to 0 as well as default)
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
// Floor
glBindVertexArray(planeVAO);
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);
// Swap the buffers // Swap the buffers
glfwSwapBuffers(window); glfwSwapBuffers(window);
@@ -210,63 +179,189 @@ int main()
return 0; return 0;
} }
// RenderQuad() Renders a 1x1 quad in NDC, best used for framebuffer color targets
// and post-processing effects.
GLuint quadVAO = 0;
GLuint quadVBO;
void RenderQuad()
{
if (quadVAO == 0)
{
GLfloat quadVertices[] = {
// Positions // Texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
// Setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
// RenderCube() Renders a 1x1 3D cube in NDC.
GLuint cubeVAO = 0;
GLuint cubeVBO = 0;
void RenderCube()
{
// Initialize (if necessary)
if (cubeVAO == 0)
{
GLfloat vertices[] = {
// Back face
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // Bottom-left
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,// top-left
// Front face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
// Left face
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
// Right face
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
// Bottom face
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
// Top face
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
};
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO);
// Fill buffer
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Link vertex attributes
glBindVertexArray(cubeVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
// Render Cube
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
}
// This function loads a texture from file. Note: texture loading functions like these are usually // 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). // 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. // For learning purposes we'll just define it as a utility function.
GLuint loadTexture(GLchar* path) GLuint loadTexture(GLchar* path)
{ {
//Generate texture ID and load texture data // Generate texture ID and load texture data
GLuint textureID; GLuint textureID;
glGenTextures(1, &textureID); glGenTextures(1, &textureID);
int width,height; int width, height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID // Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID); glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
// Parameters // Parameters
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); 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_WRAP_T, GL_REPEAT);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image); SOIL_free_image_data(image);
return textureID; return textureID;
} }
#pragma region "User input" bool keys[1024];
bool keysPressed[1024];
// Moves/alters the camera positions based on user input // Moves/alters the camera positions based on user input
void Do_Movement() void Do_Movement()
{ {
// Camera controls // Camera controls
if(keys[GLFW_KEY_W]) if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if(keys[GLFW_KEY_S]) if (keys[GLFW_KEY_S])
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if(keys[GLFW_KEY_A]) if (keys[GLFW_KEY_A])
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if(keys[GLFW_KEY_D]) if (keys[GLFW_KEY_D])
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE])
{
hdr = !hdr;
keysPressed[GLFW_KEY_SPACE] = true;
}
// Change parallax height scale
if (keys[GLFW_KEY_Q])
exposure -= 0.5 * deltaTime;
else if (keys[GLFW_KEY_E])
exposure += 0.5 * deltaTime;
} }
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
// Is called whenever a key is pressed/released via GLFW // Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{ {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE); glfwSetWindowShouldClose(window, GL_TRUE);
if(action == GLFW_PRESS) if (key >= 0 && key <= 1024)
keys[key] = true; {
else if(action == GLFW_RELEASE) if (action == GLFW_PRESS)
keys[key] = false; keys[key] = true;
else if (action == GLFW_RELEASE)
{
keys[key] = false;
keysPressed[key] = false;
}
}
} }
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;
@@ -286,5 +381,3 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
camera.ProcessMouseScroll(yoffset); camera.ProcessMouseScroll(yoffset);
} }
#pragma endregion

View File

@@ -1,16 +1,28 @@
#version 330 core #version 330 core
out vec4 color; out vec4 color;
in vec2 TexCoords;
float LinearizeDepth(float depth) // Note that this ranges from [0,1] instead of up to 'far plane distance' since we divide by 'far' uniform sampler2D hdrBuffer;
{ uniform bool hdr;
float near = 0.1; uniform float exposure;
float far = 100.0;
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * near) / (far + near - z * (far - near));
}
void main() void main()
{ {
float depth = LinearizeDepth(gl_FragCoord.z); const float gamma = 2.2;
color = vec4(vec3(depth), 1.0f); vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
if(hdr)
{
// reinhard
// vec3 result = hdrColor / (hdrColor + vec3(1.0));
// exposure
vec3 result = vec3(1.0) - exp(-hdrColor * exposure);
// also gamma correct while we're at it
result = pow(result, vec3(1.0 / gamma));
color = vec4(result, 1.0f);
}
else
{
vec3 result = pow(hdrColor, vec3(1.0 / gamma));
color = vec4(result, 1.0);
}
} }

View File

@@ -4,12 +4,8 @@ layout (location = 1) in vec2 texCoords;
out vec2 TexCoords; out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0f); gl_Position = vec4(position, 1.0f);
TexCoords = texCoords; TexCoords = texCoords;
} }

View File

@@ -0,0 +1,41 @@
#version 330 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
struct Light {
vec3 Position;
vec3 Color;
};
uniform Light lights[16];
uniform sampler2D diffuseTexture;
uniform vec3 viewPos;
void main()
{
vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
vec3 normal = normalize(fs_in.Normal);
// Ambient
vec3 ambient = 0.0 * color;
// Lighting
vec3 lighting = vec3(0.0f);
for(int i = 0; i < 16; i++)
{
// Diffuse
vec3 lightDir = normalize(lights[i].Position - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = lights[i].Color * diff * color;
vec3 result = diffuse;
// Attenuation (use quadratic as we have gamma correction)
float distance = length(fs_in.FragPos - lights[i].Position);
result *= 1.0 / (distance * distance);
lighting += result;
}
FragColor = vec4(ambient + lighting, 1.0f);
}

View File

@@ -0,0 +1,28 @@
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform bool inverse_normals;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vs_out.FragPos = vec3(model * vec4(position, 1.0));
vs_out.TexCoords = texCoords;
vec3 n = inverse_normals ? -normal : normal;
mat3 normalMatrix = transpose(inverse(mat3(model)));
vs_out.Normal = normalize(normalMatrix * n);
}

View File

@@ -1,6 +1,3 @@
// Std. Includes
#include <string>
// GLEW // GLEW
#define GLEW_STATIC #define GLEW_STATIC
#include <GL/glew.h> #include <GL/glew.h>
@@ -21,7 +18,7 @@
#include <SOIL.h> #include <SOIL.h>
// Properties // Properties
GLuint screenWidth = 800, screenHeight = 600; const GLuint SCR_WIDTH = 800, SCR_HEIGHT = 600;
// Function prototypes // Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
@@ -29,185 +26,361 @@ 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 Do_Movement();
GLuint loadTexture(GLchar* path); GLuint loadTexture(GLchar* path);
void RenderScene(Shader &shader);
void RenderCube();
void RenderQuad();
// Camera // Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
bool keys[1024];
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
// Delta
GLfloat deltaTime = 0.0f; GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f; GLfloat lastFrame = 0.0f;
// Options
GLboolean bloom = true; // Change with 'Space'
GLfloat exposure = 1.0f; // Change with Q and E
// The MAIN function, from here we start our application and run our Game loop // The MAIN function, from here we start our application and run our Game loop
int main() int main()
{ {
// Init GLFW // Init GLFW
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); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", nullptr, nullptr); // Windowed GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
// Set the required callback functions // Set the required callback functions
glfwSetKeyCallback(window, key_callback); glfwSetKeyCallback(window, key_callback);
glfwSetCursorPosCallback(window, mouse_callback); glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback); glfwSetScrollCallback(window, scroll_callback);
// Options // Options
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Initialize GLEW to setup the OpenGL Function pointers // Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE; glewExperimental = GL_TRUE;
glewInit(); glewInit();
// Define the viewport dimensions // Define the viewport dimensions
glViewport(0, 0, screenWidth, screenHeight); glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
// Setup some OpenGL options // Setup some OpenGL options
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_ALWAYS); // Set to always pass the depth test (same effect as glDisable(GL_DEPTH_TEST))
// Setup and compile our shaders // Setup and compile our shaders
Shader shader("depth_testing.vs", "depth_testing.frag"); Shader shader("bloom.vs", "bloom.frag");
Shader shaderLight("bloom.vs", "light_box.frag");
Shader shaderBlur("blur.vs", "blur.frag");
Shader shaderBloomFinal("bloom_final.vs", "bloom_final.frag");
#pragma region "object_initialization" // Set samplers
// Set the object data (buffers, vertex attributes) shaderBloomFinal.Use();
GLfloat cubeVertices[] = { glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "scene"), 0);
// Positions // Texture Coords glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "bloomBlur"), 1);
-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, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // Light sources
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // - Positions
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, std::vector<glm::vec3> lightPositions;
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, lightPositions.push_back(glm::vec3(0.0f, 0.5f, 1.5f)); // back light
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, lightPositions.push_back(glm::vec3(-4.0f, 0.5f, -3.0f));
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, lightPositions.push_back(glm::vec3(3.0f, 0.5f, 1.0f));
lightPositions.push_back(glm::vec3(-.8f, 2.4f, -1.0f));
// - Colors
std::vector<glm::vec3> lightColors;
lightColors.push_back(glm::vec3(5.0f, 5.0f, 5.0f));
lightColors.push_back(glm::vec3(5.5f, 0.0f, 0.0f));
lightColors.push_back(glm::vec3(0.0f, 0.0f, 15.0f));
lightColors.push_back(glm::vec3(0.0f, 1.5f, 0.0f));
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // Load textures
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, GLuint woodTexture = loadTexture("../../../resources/textures/wood.png");
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, GLuint containerTexture = loadTexture("../../../resources/textures/container2.png");
-0.5f, -0.5f, -0.5f, 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.5f, 0.5f, 0.5f, 1.0f, 0.0f, // Set up floating point framebuffer to render scene to
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, GLuint hdrFBO;
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, glGenFramebuffers(1, &hdrFBO);
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // - Create 2 floating point color buffers (1 for normal rendering, other for brightness treshold values)
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, GLuint colorBuffers[2];
glGenTextures(2, colorBuffers);
for (GLuint i = 0; i < 2; i++)
{
glBindTexture(GL_TEXTURE_2D, colorBuffers[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // We clamp to the edge as the blur filter would otherwise sample repeated texture values!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// attach texture to framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, colorBuffers[i], 0);
}
// - Create and attach depth buffer (renderbuffer)
GLuint rboDepth;
glGenRenderbuffers(1, &rboDepth);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
// - Tell OpenGL which color attachments we'll use (of this framebuffer) for rendering
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, attachments);
// - Finally check if framebuffer is complete
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // Ping pong framebuffer for blurring
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, GLuint pingpongFBO[2];
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, GLuint pingpongColorbuffers[2];
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, glGenFramebuffers(2, pingpongFBO);
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, glGenTextures(2, pingpongColorbuffers);
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, for (GLuint i = 0; i < 2; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]);
glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // We clamp to the edge as the blur filter would otherwise sample repeated texture values!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongColorbuffers[i], 0);
// Also check if framebuffers are complete (no need for depth buffer)
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Framebuffer not complete!" << std::endl;
}
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
0.5f, 0.5f, -0.5f, 1.0f, 1.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, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
GLfloat 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)
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, 2.0f,
5.0f, -0.5f, 5.0f, 2.0f, 0.0f, // Game loop
-5.0f, -0.5f, -5.0f, 0.0f, 2.0f, while (!glfwWindowShouldClose(window))
5.0f, -0.5f, -5.0f, 2.0f, 2.0f {
}; // Set frame time
// Setup cube VAO GLfloat currentFrame = glfwGetTime();
GLuint cubeVAO, cubeVBO; deltaTime = currentFrame - lastFrame;
glGenVertexArrays(1, &cubeVAO); lastFrame = currentFrame;
glGenBuffers(1, &cubeVBO);
glBindVertexArray(cubeVAO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
// Setup plane VAO
GLuint planeVAO, planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glBindVertexArray(0);
// Load textures // Check and call events
GLuint cubeTexture = loadTexture("../../../resources/textures/marble.jpg"); glfwPollEvents();
GLuint floorTexture = loadTexture("../../../resources/textures/metal.png"); Do_Movement();
#pragma endregion
// Game loop // 1. Render scene into floating point framebuffer
while(!glfwWindowShouldClose(window)) glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
{ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set frame time glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)SCR_WIDTH / (GLfloat)SCR_HEIGHT, 0.1f, 100.0f);
GLfloat currentFrame = glfwGetTime(); glm::mat4 view = camera.GetViewMatrix();
deltaTime = currentFrame - lastFrame; glm::mat4 model;
lastFrame = currentFrame; shader.Use();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, woodTexture);
// - set lighting uniforms
for (GLuint i = 0; i < lightPositions.size(); i++)
{
glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Position").c_str()), 1, &lightPositions[i][0]);
glUniform3fv(glGetUniformLocation(shader.Program, ("lights[" + std::to_string(i) + "].Color").c_str()), 1, &lightColors[i][0]);
}
glUniform3fv(glGetUniformLocation(shader.Program, "viewPos"), 1, &camera.Position[0]);
// - create one large cube that acts as the floor
model = glm::mat4();
model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0));
model = glm::scale(model, glm::vec3(25.0f, 1.0f, 25.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
// - then create multiple cubes as the scenery
glBindTexture(GL_TEXTURE_2D, containerTexture);
model = glm::mat4();
model = glm::translate(model, glm::vec3(0.0f, 1.5f, 0.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 1.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-1.0f, -1.0f, 2.0));
model = glm::rotate(model, 60.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0)));
model = glm::scale(model, glm::vec3(2.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(0.0f, 2.7f, 4.0));
model = glm::rotate(model, 23.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0)));
model = glm::scale(model, glm::vec3(2.5));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-2.0f, 1.0f, -3.0));
model = glm::rotate(model, 124.0f, glm::normalize(glm::vec3(1.0, 0.0, 1.0)));
model = glm::scale(model, glm::vec3(2.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
RenderCube();
model = glm::mat4();
model = glm::translate(model, glm::vec3(-3.0f, 0.0f, 0.0));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
RenderCube();
// - finally show all the light sources as bright cubes
shaderLight.Use();
glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
// Check and call events for (GLuint i = 0; i < lightPositions.size(); i++)
glfwPollEvents(); {
Do_Movement(); model = glm::mat4();
model = glm::translate(model, glm::vec3(lightPositions[i]));
model = glm::scale(model, glm::vec3(0.5f));
glUniformMatrix4fv(glGetUniformLocation(shaderLight.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniform3fv(glGetUniformLocation(shaderLight.Program, "lightColor"), 1, &lightColors[i][0]);
RenderCube();
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Clear the colorbuffer // 2. Blur bright fragments w/ two-pass Gaussian Blur
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); GLboolean horizontal = true, first_iteration = true;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLuint amount = 10;
shaderBlur.Use();
for (GLuint i = 0; i < amount; i++)
{
glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]);
glUniform1i(glGetUniformLocation(shaderBlur.Program, "horizontal"), horizontal);
glBindTexture(GL_TEXTURE_2D, first_iteration ? colorBuffers[1] : pingpongColorbuffers[!horizontal]); // bind texture of other framebuffer (or scene if first iteration)
RenderQuad();
horizontal = !horizontal;
if (first_iteration)
first_iteration = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Draw objects // 2. Now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range
shader.Use(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 model; shaderBloomFinal.Use();
glm::mat4 view = camera.GetViewMatrix(); glActiveTexture(GL_TEXTURE0);
glm::mat4 projection = glm::perspective(camera.Zoom, (float)screenWidth/(float)screenHeight, 0.1f, 100.0f); glBindTexture(GL_TEXTURE_2D, colorBuffers[0]);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view)); //glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glActiveTexture(GL_TEXTURE1);
// Cubes glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]);
glBindVertexArray(cubeVAO); glUniform1i(glGetUniformLocation(shaderBloomFinal.Program, "bloom"), bloom);
glBindTexture(GL_TEXTURE_2D, cubeTexture); // We omit the glActiveTexture part since TEXTURE0 is already the default active texture unit. (sampler used in fragment is set to 0 as well as default) glUniform1f(glGetUniformLocation(shaderBloomFinal.Program, "exposure"), exposure);
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f)); RenderQuad();
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
model = glm::mat4();
model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLES, 0, 36);
// Floor
glBindVertexArray(planeVAO);
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);
// Swap the buffers // Swap the buffers
glfwSwapBuffers(window); glfwSwapBuffers(window);
} }
glfwTerminate(); glfwTerminate();
return 0; return 0;
}
// RenderQuad() Renders a 1x1 quad in NDC, best used for framebuffer color targets
// and post-processing effects.
GLuint quadVAO = 0;
GLuint quadVBO;
void RenderQuad()
{
if (quadVAO == 0)
{
GLfloat quadVertices[] = {
// Positions // Texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
// Setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
}
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
// RenderCube() Renders a 1x1 3D cube in NDC.
GLuint cubeVAO = 0;
GLuint cubeVBO = 0;
void RenderCube()
{
// Initialize (if necessary)
if (cubeVAO == 0)
{
GLfloat vertices[] = {
// Back face
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // Bottom-left
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,// top-left
// Front face
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
// Left face
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
// Right face
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
// Bottom face
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,// bottom-left
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
// Top face
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,// top-left
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
};
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &cubeVBO);
// Fill buffer
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Link vertex attributes
glBindVertexArray(cubeVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
// Render Cube
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
} }
// This function loads a texture from file. Note: texture loading functions like these are usually // This function loads a texture from file. Note: texture loading functions like these are usually
@@ -215,76 +388,94 @@ int main()
// For learning purposes we'll just define it as a utility function. // For learning purposes we'll just define it as a utility function.
GLuint loadTexture(GLchar* path) GLuint loadTexture(GLchar* path)
{ {
//Generate texture ID and load texture data // Generate texture ID and load texture data
GLuint textureID; GLuint textureID;
glGenTextures(1, &textureID); glGenTextures(1, &textureID);
int width,height; int width, height;
unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB); unsigned char* image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
// Assign texture to ID // Assign texture to ID
glBindTexture(GL_TEXTURE_2D, textureID); glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
// Parameters // Parameters
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); 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_WRAP_T, GL_REPEAT);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image); SOIL_free_image_data(image);
return textureID; return textureID;
} }
#pragma region "User input" bool keys[1024];
bool keysPressed[1024];
// Moves/alters the camera positions based on user input // Moves/alters the camera positions based on user input
void Do_Movement() void Do_Movement()
{ {
// Camera controls // Camera controls
if(keys[GLFW_KEY_W]) if (keys[GLFW_KEY_W])
camera.ProcessKeyboard(FORWARD, deltaTime); camera.ProcessKeyboard(FORWARD, deltaTime);
if(keys[GLFW_KEY_S]) if (keys[GLFW_KEY_S])
camera.ProcessKeyboard(BACKWARD, deltaTime); camera.ProcessKeyboard(BACKWARD, deltaTime);
if(keys[GLFW_KEY_A]) if (keys[GLFW_KEY_A])
camera.ProcessKeyboard(LEFT, deltaTime); camera.ProcessKeyboard(LEFT, deltaTime);
if(keys[GLFW_KEY_D]) if (keys[GLFW_KEY_D])
camera.ProcessKeyboard(RIGHT, deltaTime); camera.ProcessKeyboard(RIGHT, deltaTime);
if (keys[GLFW_KEY_SPACE] && !keysPressed[GLFW_KEY_SPACE])
{
bloom = !bloom;
keysPressed[GLFW_KEY_SPACE] = true;
}
// Change parallax height scale
if (keys[GLFW_KEY_Q])
exposure -= 0.5 * deltaTime;
else if (keys[GLFW_KEY_E])
exposure += 0.5 * deltaTime;
} }
GLfloat lastX = 400, lastY = 300;
bool firstMouse = true;
// Is called whenever a key is pressed/released via GLFW // Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{ {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE); glfwSetWindowShouldClose(window, GL_TRUE);
if(action == GLFW_PRESS) if (key >= 0 && key <= 1024)
keys[key] = true; {
else if(action == GLFW_RELEASE) if (action == GLFW_PRESS)
keys[key] = false; keys[key] = true;
else if (action == GLFW_RELEASE)
{
keys[key] = false;
keysPressed[key] = false;
}
}
} }
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; GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos; GLfloat yoffset = lastY - ypos;
lastX = xpos; lastX = xpos;
lastY = ypos; lastY = ypos;
camera.ProcessMouseMovement(xoffset, yoffset); camera.ProcessMouseMovement(xoffset, yoffset);
} }
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

View File

@@ -1,16 +1,49 @@
#version 330 core #version 330 core
out vec4 color; layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 BrightColor;
float LinearizeDepth(float depth) // Note that this ranges from [0,1] instead of up to 'far plane distance' since we divide by 'far' in VS_OUT {
{ vec3 FragPos;
float near = 0.1; vec3 Normal;
float far = 100.0; vec2 TexCoords;
float z = depth * 2.0 - 1.0; // Back to NDC } fs_in;
return (2.0 * near) / (far + near - z * (far - near));
} struct Light {
vec3 Position;
vec3 Color;
};
uniform Light lights[4];
uniform sampler2D diffuseTexture;
uniform vec3 viewPos;
void main() void main()
{ {
float depth = LinearizeDepth(gl_FragCoord.z); vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
color = vec4(vec3(depth), 1.0f); vec3 normal = normalize(fs_in.Normal);
// Ambient
vec3 ambient = 0.0 * color;
// Lighting
vec3 lighting = vec3(0.0f);
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
for(int i = 0; i < 4; i++)
{
// Diffuse
vec3 lightDir = normalize(lights[i].Position - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 result = lights[i].Color * diff * color;
// Attenuation (use quadratic as we have gamma correction)
float distance = length(fs_in.FragPos - lights[i].Position);
result *= 1.0 / (distance * distance);
lighting += result;
}
vec3 result = ambient + lighting;
// Check whether result is higher than some threshold, if so, output as bloom threshold color
float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 1.0)
BrightColor = vec4(result, 1.0);
// else
// BloomColor = vec4(0.0, 0.0, 0.0, 1.0);
FragColor = vec4(result, 1.0f);
} }

View File

@@ -1,15 +1,24 @@
#version 330 core #version 330 core
layout (location = 0) in vec3 position; layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoords; layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
out vec2 TexCoords; out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} vs_out;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection; uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() void main()
{ {
gl_Position = projection * view * model * vec4(position, 1.0f); gl_Position = projection * view * model * vec4(position, 1.0f);
TexCoords = texCoords; vs_out.FragPos = vec3(model * vec4(position, 1.0));
vs_out.TexCoords = texCoords;
mat3 normalMatrix = transpose(inverse(mat3(model)));
vs_out.Normal = normalize(normalMatrix * normal);
} }

View File

@@ -0,0 +1,22 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D scene;
uniform sampler2D bloomBlur;
uniform bool bloom;
uniform float exposure;
void main()
{
const float gamma = 2.2;
vec3 hdrColor = texture(scene, TexCoords).rgb;
vec3 bloomColor = texture(bloomBlur, TexCoords).rgb;
if(bloom)
hdrColor += bloomColor; // additive blending
// tone mapping
vec3 result = vec3(1.0) - exp(-hdrColor * exposure);
// also gamma correct while we're at it
result = pow(result, vec3(1.0 / gamma));
FragColor = vec4(result, 1.0f);
}

View File

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

View File

@@ -0,0 +1,31 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D image;
uniform bool horizontal;
uniform float weight[5] = float[] (0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162);
void main()
{
vec2 tex_offset = 1.0 / textureSize(image, 0); // gets size of single texel
vec3 result = texture(image, TexCoords).rgb * weight[0];
if(horizontal)
{
for(int i = 1; i < 5; ++i)
{
result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
}
}
else
{
for(int i = 1; i < 5; ++i)
{
result += texture(image, TexCoords + vec2(0.0, tex_offset.y * i)).rgb * weight[i];
result += texture(image, TexCoords - vec2(0.0, tex_offset.y * i)).rgb * weight[i];
}
}
FragColor = vec4(result, 1.0);
}

View File

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

View File

@@ -0,0 +1,19 @@
#version 330 core
layout (location = 0) out vec4 FragColor;
layout (location = 1) out vec4 BrightColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
uniform vec3 lightColor;
void main()
{
FragColor = vec4(lightColor, 1.0);
float brightness = dot(FragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 1.0)
BrightColor = vec4(FragColor.rgb, 1.0);
}