Intermediatesdl3
Intermediate

Using OpenGL Shaders with SDL3: Blur Effect Example

Learn how to use OpenGL shaders with SDL3 by creating a blur effect on an image. This tutorial uses GLEW, stb_image, and SDL3 for rendering.

Prerequisites / Tools :
  • SDL3, SDL3_Image
Nicolas Perdu
Written by Nicolas PerduSoftware engineer

Hello World with SDL3

Vertex shader

Create a new file with the following vertex shader: vertex_shader.glsl

#version 450

layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoord;

layout (location = 0) out vec2 TexCoord;

void main() {
    TexCoord = aTexCoord;
    gl_Position = vec4(aPos, 0.0, 1.0);
}

Fragment shader

Create a file for the fragment shader: blur_shader.glsl

#version 330 core

out vec4 FragColor;
in vec2 TexCoord;

uniform sampler2D screenTexture;
uniform vec2 resolution;
uniform float blurRadius;

void main() {
    vec2 tex_offset = 1.0 / resolution; // Size of one texel
    vec4 color = vec4(0.0);
    float weight_sum = 0.0;
    float weights[5] = float[](0.227, 0.194, 0.121, 0.054, 0.016);
    
    for (int i = -2; i <= 2; i++) {
        for (int j = -2; j <= 2; j++) {
            vec2 offset = vec2(i, j) * tex_offset * blurRadius;
            color += texture(screenTexture, TexCoord + offset) * weights[abs(i)] * weights[abs(j)];
            weight_sum += weights[abs(i)] * weights[abs(j)];
        }
    }
    FragColor = color / weight_sum;
}

The image file

You can download it here: lettuce.png

The CMakeList.txt file

You will need to download glew and stb_image as dependencies for the program.
Here is the CMakeList.txt for mac os, with little changes you can adapt it to linux or windows.

cmake_minimum_required(VERSION 3.10)
project(SDL3_Blur_Shader)

# Enable C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find SDL3 package
find_package(SDL3 REQUIRED)

# Find OpenGL
find_package(OpenGL REQUIRED)

set(GLEW_INCLUDE_DIR "/usr/local/include")
set(GLEW_LIBRARY "/usr/local/lib/libGLEW.dylib")

set(STB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include)
include_directories(${STB_INCLUDE_DIR})

include_directories(${SDL3_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR})

# Add executable
add_executable(blur_shader main.cpp)

# Link libraries
target_link_libraries(blur_shader 
    ${SDL3_LIBRARIES} 
    ${OPENGL_LIBRARIES} 
    ${GLEW_LIBRARY}
)

The main file

#include <SDL3/SDL.h>
#include <GL/glew.h>
#include <iostream>
#include <fstream>
#include <sstream>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

void CheckShaderCompilation(GLuint shader, const char* type) {
    GLint success;
    GLchar infoLog[1024];
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(shader, 1024, NULL, infoLog);
        std::cerr << "Shader Compilation Error (" << type << "): " << infoLog << std::endl;
    }
}

void CheckShaderLinking(GLuint program) {
    GLint success;
    GLchar infoLog[1024];
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(program, 1024, NULL, infoLog);
        std::cerr << "Shader Linking Error: " << infoLog << std::endl;
    }
}

GLuint LoadShader(const char* vertexPath, const char* fragmentPath) {
    std::ifstream vShaderFile(vertexPath);
    std::ifstream fShaderFile(fragmentPath);
    std::stringstream vShaderStream, fShaderStream;
    vShaderStream << vShaderFile.rdbuf();
    fShaderStream << fShaderFile.rdbuf();
    std::string vShaderCode = vShaderStream.str();
    std::string fShaderCode = fShaderStream.str();
    const char* vShaderSource = vShaderCode.c_str();
    const char* fShaderSource = fShaderCode.c_str();

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vShaderSource, NULL);
    glCompileShader(vertexShader);
    CheckShaderCompilation(vertexShader, "VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fShaderSource, NULL);
    glCompileShader(fragmentShader);
    CheckShaderCompilation(fragmentShader, "FRAGMENT");

    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    CheckShaderLinking(shaderProgram);

    glDeleteShader(vertexShader);

The full project : Use OpenGL shaders with SDL3

You can download the full project - Use OpenGL shaders with SDL3:

Need another OS ? => Windows, Mac, Linux