简体   繁体   中英

How to create a blur shader

I am following the following shader to create a blur.

OpenGL es 2.0 Gaussian blur on triangle

First i generate framebuffers.

glGenTextures(2, texObj);
    glGenFramebuffers(2, fbObj);
    glActiveTexture(GL_TEXTURE0);
    for (int i = 0; i < 2; i++)
    {
        glBindTexture(GL_TEXTURE_2D, texObj[i]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glGenerateMipmap(GL_TEXTURE_2D);
        glBindFramebuffer(GL_FRAMEBUFFER, fbObj[i]);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texObj[i], 0);
        GLuint renderbuffer;
        glGenRenderbuffers(1, &renderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 1920, 1080);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);

    }
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

Than i follow these steps.

    // first create a image of the scene
    GLint drawFrameBuffer;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &drawFrameBuffer);    
    glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);  
    ResourceManager::GetShader("BasicShader").Use();
    //ResourceManager::GetShader("BasicShader").SetInteger("UseColorMap", false);
    glDisable(GL_DEPTH_TEST);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT );
    geom->draw();   
    
    
    // Set the Blur in X direction
    glBindFramebuffer(GL_FRAMEBUFFER, fbObj[1]);
    ResourceManager::GetShader("shaderTest").Use();
    // Set the blur shader properties
    ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
    ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
    ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(1.0, 0.0));
    ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));   
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glBindTexture(GL_TEXTURE_2D, texObj[0]);
    glGenerateMipmap(GL_TEXTURE_2D);
    drawFullScreenQuad();


    // Set the Blur in Y direction
    glBindFramebuffer(GL_FRAMEBUFFER, fbObj[0]);
    ResourceManager::GetShader("shaderTest").Use();
    // Set the blur shader properties
    ResourceManager::GetShader("shaderTest").SetFloat("u_sigma", intensity);
    ResourceManager::GetShader("shaderTest").SetFloat("u_radius", blur);
    ResourceManager::GetShader("shaderTest").SetVector2f("u_dir", glm::vec2(0.0, 1.0));
    ResourceManager::GetShader("shaderTest").SetVector2f("u_textureSize", glm::vec2(1920.0, 1080.0));
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glBindTexture(GL_TEXTURE_2D, texObj[1]);
    glGenerateMipmap(GL_TEXTURE_2D);
    drawFullScreenQuad();

    
    // Render the result to full screen.
    glBindFramebuffer(GL_FRAMEBUFFER, drawFrameBuffer); 
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glActiveTexture(GL_TEXTURE0);
    ResourceManager::GetShader("Screen").Use();
    glBindTexture(GL_TEXTURE_2D, texObj[0]);    
    glGenerateMipmap(GL_TEXTURE_2D);
    drawFullScreenQuad();
    ResourceManager::GetShader("BasicShader").Use();

These are the shaders.

#version 430 core
layout (location = 0) in vec2 aPos;
out vec2 pos;

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

////////////////////////////////////////////////////////////////////////////////////////////////////////

#version 330 core
out vec4 FragColor;
in vec2 pos;

// texture sampler
uniform sampler2D u_texture;
uniform vec2      u_textureSize;
uniform float     u_sigma;
uniform float     u_radius;
uniform vec2      u_dir;

float CalcGauss( float x, float sigma)
{
   if( sigma <= 0.0 )
    return 0.0;
return exp( -(x * x) / ( 2.0 * sigma)) / ( 2.0 * 3.14157 * sigma);

}

void main()
{
    vec2 texC     = pos.st * 0.5 + 0.5;
    vec4 texCol   = texture2D( u_texture, texC );
    vec4 gaussCol = vec4( texCol.rgb, 1.0 );
    vec2 step     = u_dir / u_textureSize;
    float weight;
    for ( int i = 1; i <= 16; ++ i )
    {
        weight = CalcGauss( float(i) / 16.0, u_sigma * 0.5 );
        if ( weight < 1.0/255.0 )
            break;
        texCol    = texture2D( u_texture, texC + u_radius * step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
        texCol    = texture2D( u_texture, texC - u_radius * step * float(i) );
        gaussCol += vec4( texCol.rgb * weight, weight );
    }
    
   gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
   FragColor = vec4( gaussCol.rgb , 1.0 );

}

When the value for u_radius and u_sigma is 1 than the blur is smooth.

在此处输入图片说明

when u_sigma is 10 and u_radius is 30 than the blur looks like this.

在此处输入图片说明

Since that example is using webgl and i am using Opengl would the results vary ?

The new image after values given by Rabbid76.

在此处输入图片说明

In the implementation of the shader, the value for sigma has to be in range [0.0, 1.0]. A radius of 30 seems to be to large. Start with u_sigma = 0.5 and u_radius = 10 .


The the shader effect still looks wrong, because the computation of the alpha channel is wrong.
You have copied the shader form a WebGL . WebGL by default uses premultiplied alpha , but your desktop application does not. See Straight versus premultiplied .
Skip the division of the weighted sum of the color channels by the weighted sum of the alpha channel:

gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );

gaussCol.rgb = clamp(gaussCol.rgb, 0.0, 1.0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM