Search code examples
glslshadersfmlblur

Is Photoshop "Motion Blur" possible with GLSL?


I'm using to make a 2D game with sprites and trying to get this effect:

enter image description here

I use Photoshop's "Motion Blur" in the example. As you can see, the effect is directional.

My game uses paperdolled sprites so it would be much easier to have this as a post effect instead of blurring every single equipment combination on every sprite.

Would it be possible to get this effect with a shader? An example would be appreciated.


Solution

  • Here I post the best result I could do in one night. I did it with shaders as you ask. I didn't implement the angles but that something not too hard.

    Here is part of the cpp file:

    ...
    if (!shader.loadFromFile("dMotionBlur_v05.frag", sf::Shader::Fragment)){
    ...
    
    window.clear(sf::Color(120,120,120));
    
    // Passing parameters to shader.
    shader.setUniform("dir", dir); //direction of blur
    shader.setUniform("nSamplesF", (float)std::atoi(argv[3])); // number of samples
    shader.setUniform("radius", (float)std::atof(argv[4]) ); //radius of blur
    
    window.draw(sprite, &shader);
    window.display();
    ...
    

    This is the fragment shader:

    uniform sampler2D u_texture;
    uniform float nSamplesF;
    uniform float radius;
    uniform vec2 dir;
    
    void main(){
        vec2 tc = gl_TexCoord[0].xy;
        float blur = radius;
        float hstep = dir.x;
        float vstep = dir.y;
        float total = 0.0;
        int nSamplesI = int(nSamplesF);
    
        vec4 sum = vec4(0.0);
    
        for (int i=1; i<=nSamplesI; i++){
            float floatI = float(i);
            float counter = nSamplesF-floatI+1.0;
    
            float p = floatI/nSamplesF;
            float tO = (p * 0.1783783784) + 0.0162162162;
            total += tO;
    
            sum += texture2D(u_texture, vec2(tc.x - counter*blur*hstep, tc.y - counter*blur*vstep)) * tO;
        }
    
        sum += texture2D(u_texture, vec2(tc.x, tc.y)) * 0.2270270270;
    
        for (int i=nSamplesI; i>=1; i--){
            float floatI = float(i);
            float counter = nSamplesF-floatI+1.0;
    
            float p = floatI/nSamplesF;
            float tO = (p * 0.1783783784) + 0.0162162162;
            total += tO;
    
            sum += texture2D(u_texture, vec2(tc.x + counter*blur*hstep, tc.y + counter*blur*vstep)) * tO;
        }
    
        gl_FragColor =  gl_Color * (sum/total);
    }
    

    I upload the entire code to my repository so you can downloaded and try. You can set x/Y direction, sample, and blur radius. X/Y directions are from 0-1. You can play with the number of samples. The blur radius is very sensitive you can start try with 0.01

    with my example would be:

    $ ./sfml-app [x(0-1)] [Y(0-1] [number of sample] [ radius blur]
    

    Some pics: