Code re-work: anti-aliasing.

This commit is contained in:
Joey de Vries
2017-04-20 21:30:22 +02:00
parent cd5f93211b
commit 9994831d5d
8 changed files with 270 additions and 182 deletions

View File

@@ -122,9 +122,10 @@ set(4.advanced_opengl
8.advanced_glsl_ubo 8.advanced_glsl_ubo
9.1.geometry_shader_houses 9.1.geometry_shader_houses
9.2.geometry_shader_exploding 9.2.geometry_shader_exploding
9.3.geometry_shader_normal_visualization 9.3.geometry_shader_normals
10.1.instancing_quads 10.1.instancing_quads
10.2.instancing_asteroids 10.2.asteroids
10.3.asteroids_instanced
11.anti_aliasing_offscreen 11.anti_aliasing_offscreen
) )

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main()
{
vec3 col = texture(screenTexture, TexCoords).rgb;
float grayscale = 0.2126 * col.r + 0.7152 * col.g + 0.0722 * col.b;
FragColor = vec4(vec3(grayscale), 1.0);
}

View File

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

View File

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

View File

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

View File

@@ -1,77 +1,84 @@
// 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>
// Properties #include <learnopengl/filesystem.h>
GLuint screenWidth = 800, screenHeight = 600; #include <learnopengl/shader.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>
// Function prototypes #include <iostream>
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void Do_Movement(); void processInput(GLFWwindow *window);
GLuint generateMultiSampleTexture(GLuint samples);
// 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 OpenGL options
glEnable(GL_MULTISAMPLE); // Enabled by default on some drivers, but not all so always enable to make sure
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// Setup and compile our shaders // build and compile shaders
Shader shader("anti_aliasing.vs", "anti_aliasing.frag"); // -------------------------
Shader shader("11.1.anti_aliasing.vs", "11.1.anti_aliasing.fs");
Shader screenShader("11.2.aa_post.vs", "11.2.aa_post.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 // 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,
@@ -114,132 +121,188 @@ 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
}; };
// Setup cube VAO float quadVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
GLuint cubeVAO, cubeVBO; // positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
// setup cube VAO
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, 3 * sizeof(GLfloat), (GLvoid*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindVertexArray(0); // setup screen VAO
#pragma endregion unsigned int quadVAO, quadVBO;
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, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
// Framebuffers // configure MSAA framebuffer
GLuint framebuffer; // --------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Create a multisampled color attachment texture // create a multisampled color attachment texture
GLuint textureColorBufferMultiSampled = generateMultiSampleTexture(4); unsigned int textureColorBufferMultiSampled;
glGenTextures(1, &textureColorBufferMultiSampled);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, SCR_WIDTH, SCR_HEIGHT, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
// Create a renderbuffer object for depth and stencil attachments // create a (also multisampled) renderbuffer object for depth and stencil attachments
GLuint rbo; unsigned int rbo;
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, screenWidth, screenHeight); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl; cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// configure second post-processing framebuffer
unsigned int intermediateFBO;
glGenFramebuffers(1, &intermediateFBO);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
// create a color attachment texture
unsigned int screenTexture;
glGenTextures(1, &screenTexture);
glBindTexture(GL_TEXTURE_2D, screenTexture);
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, screenTexture, 0); // we only need a color buffer
// Game loop if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
while(!glfwWindowShouldClose(window)) cout << "ERROR::FRAMEBUFFER:: Intermediate framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// shader configuration
// --------------------
shader.use();
screenShader.setInt("screenTexture", 0);
// render loop
// -----------
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);
// 1. Draw scene as normal in multisampled buffers // render
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // ------
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);
// 1. draw scene as normal in multisampled buffers
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// Set transformation matrices // Set transformation matrices
shader.Use(); shader.use();
glm::mat4 projection = glm::perspective(camera.Zoom, (GLfloat)screenWidth/(GLfloat)screenHeight, 0.1f, 1000.0f); glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 1000.0f);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); shader.setMat4("projection", projection);
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(camera.GetViewMatrix())); shader.setMat4("view", camera.GetViewMatrix());
glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(glm::mat4())); shader.setMat4("model", glm::mat4());
glBindVertexArray(cubeVAO); glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36); glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
// 2. Now blit multisampled buffer(s) to default framebuffers // 2. now blit multisampled buffer(s) to normal colorbuffer of intermediate FBO. Image is stored in screenTexture
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
// Swap the buffers // 3. now render quad with scene's visuals as its texture image
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
// Draw Screen quad
screenShader.use();
glBindVertexArray(quadVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, screenTexture); // use the now resolved color attachment as the quad's texture
glDrawArrays(GL_TRIANGLES, 0, 6);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents();
} }
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }
GLuint generateMultiSampleTexture(GLuint samples) // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{ {
GLuint texture; if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glGenTextures(1, &texture); glfwSetWindowShouldClose(window, true);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); float cameraSpeed = 2.5 * deltaTime;
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, screenWidth, screenHeight, GL_TRUE); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
return texture;
}
#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;
@@ -247,9 +310,9 @@ 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