-
Notifications
You must be signed in to change notification settings - Fork 5
Custom Shaders And Post Processing Effects
Custom shaders or post-processing effects have the same API. You have to write a fragment shader and load it. I made them to be more or less compatible with each other. The only difference between a post-process shader and a normal shader is that the normal shader is also expected to take into account colors and texture coordinates. This is because when doing the post process, the entire screen and the entire texture will be used. So I made the redundant attributes for a post-process shader have default values, so you can use a normal shader for a post-processing effect.
Default Shader:
#version 130
precision highp float;
out vec4 color;
in vec2 v_positions; //the positions are in NDC [-1, 1], not used here
in vec2 v_texture; //the positions are in texture space
in vec4 v_color; //the color sent by the user, can be different per vertex.
uniform sampler2D u_sampler;
void main()
{
color = texture2D(u_sampler, v_texture) * v_color;
}
This is the shader
#version 330
precision highp float;
out vec4 color;
in vec2 v_texture;
uniform sampler2D u_sampler;
uniform int u_strength = 10;
void main()
{
color = texture2D(u_sampler, v_texture).rgba;
color.rgb *= u_strength;
color.rgb = floor(color.rgb);
color.rgb /= u_strength;
}
This is the code
#include <glad/glad.h>
#include <glfw/glfw3.h>
#include "gl2d/gl2d.h"
int main()
{
// Initialize GLFW
glfwInit();
GLFWwindow *window = glfwCreateWindow(840, 640, "Window", nullptr, nullptr);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)(glfwGetProcAddress));
// Initialize gl2d
gl2d::init();
gl2d::Renderer2D renderer;
renderer.create();
// Load resources example
//gl2d::Font font(RESOURCES_PATH "roboto_black.ttf");
gl2d::Texture texture(RESOURCES_PATH "test.jpg");
gl2d::ShaderProgram colorShader = gl2d::createShaderFromFile(RESOURCES_PATH "removeColors.frag");
GLuint u_strength = glGetUniformLocation(colorShader.id, "u_strength");
//just for example
gl2d::ShaderProgram defaultShader = gl2d::createShaderFromFile(RESOURCES_PATH "defaultRenderShader.frag");
// Main loop
while (!glfwWindowShouldClose(window))
{
//very important, don't forget to call renderer.updateWindowMetrics,
//this is probably the thing that I forget most often
int w = 0; int h = 0;
glfwGetWindowSize(window, &w, &h);
renderer.updateWindowMetrics(w, h);
// Handle input and update
// Clear screen
renderer.clearScreen({0.1, 0.2, 0.6, 1});
// Render objects
renderer.renderRectangle({100, 100, 100, 100}, texture);
//flush everything before
renderer.flush();
//IT'S NOT GOOD TO CHANGE THE SHADER TOO MANY TIMES
//IF YOU NEED TO RENDER AN EFFECT FOR 100 OBJECTS FOR EXAMPLE,
//RENDER ALL OF THE NORMAL OBJECTS THAN THE EFFECTS OBJECTS, OR SOMETHING SIMILAR.
//IF THE NUMBER OF FLUSHES OR SHADER BINDS IS INSIDE A BIG LOOP THAT WILL QUICKLY
//KILL YOUR FPS. IF IT IS A SENSIBLE NUMBER LIKE 20 THERE IS NO PROBLEM.
renderer.pushShader(colorShader);
//custom unfiorm
colorShader.bind();
glUniform1i(u_strength, 5);
renderer.renderRectangle({300, 100, 100, 100},
texture);
renderer.flush();
renderer.popShader();
// Add more rendering here...
// Flush renderer (dump your rendering into the screen)
renderer.flush();
// Swap buffers and poll events
glfwSwapBuffers(window);
glfwPollEvents();
}
//cleanup if you want, no need for it here tho.
return 0;
}
Note that you can pass custom uniforms to your shader. Note that I have used pushShader() and popShader() to easily specify the current shader that I want to use Note that it is not good to change your shader too many times per frame.
Result: