opengllightssao

SSAO working but has a weird Red colour overlay


The ssao works but there is a weird red colour overlay due to the ssao only using the red channel of course this is shown in the image below..

Red SSAO Problem
Red SSAO Problem

However, when I do glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); the red colour goes but the ssao goes as well.

Result after doing glClear(). No SSAO anymore
Result after doing glClear(). No SSAO anymore

Here is all the code that you need...

// ------------------------------ LIGHT PASS -------------------------------- //
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shaders[LIGHT_PASS]->UseProgram();  // Bind light pass shader

    // Parse the camera position
    LightPass::Render(Content::_map->GetCamera(), Content::_map->GetCamera()->GetPosition());   

    GBuffer::Render();  // bind the gbuffer textures (includes SSAO)

    renderQuad();   // Render the screen rectangle
    // -------------------------------------------------------------------- //

Geometry Pass code..

// ----------------------------- GEOMETRY PASS ----------------------------- //
    GBuffer::Bind();    // Bind the world gbuffer frame buffer
    shaders[GEOMETRY_PASS]->UseProgram();   // Bind geometry shader
    GeometryPass::Render();     // Render geometry
    glBindFramebuffer(GL_FRAMEBUFFER, 0);   // Unbind the gbuffer
    // --------------------------------------------------------------------- //

SSAO Pass code..

static inline void Initialise(unsigned int ssao_program, unsigned int ssaoblur_program) 
    {
        program = ssao_program;
        program2 = ssaoblur_program;

        // SSAO color fbo
        glGenTextures(1, &ssaoColorBuffer);
        glBindTexture(GL_TEXTURE_2D, ssaoColorBuffer);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 1920, 1080, 0, GL_RGB, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoColorBuffer, 0);
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "SSAO Framebuffer not complete!" << std::endl;

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // blur fbo
        glGenFramebuffers(1, &ssaoBlurFBO);
        glBindFramebuffer(GL_FRAMEBUFFER, ssaoBlurFBO);

        // SSAO color buffer
        glGenTextures(1, &ssaoColorBufferBlur);
        glBindTexture(GL_TEXTURE_2D, ssaoColorBufferBlur);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 1920, 1080, 0, GL_RGB, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoColorBufferBlur, 0);
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "SSAO Framebuffer not complete!" << std::endl;

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // generates random floats between 0.0 and 1.0
        std::default_random_engine generator;

        for (unsigned int i = 0; i < 64; ++i)
        {
            glm::vec3 sample(randomFloats(generator) * 2.0 - 1.0, randomFloats(generator) * 2.0 - 1.0, randomFloats(generator));
            sample = glm::normalize(sample);
            sample *= randomFloats(generator);
            float scale = float(i) / 64.0;

            // scale samples s.t. they're more aligned to center of kernel
            scale = lerp(0.1f, 1.0f, scale * scale);
            sample *= scale;
            ssaoKernel.push_back(sample);
        }

        for (unsigned int i = 0; i < 16; i++)
        {
            glm::vec3 noise(randomFloats(generator) * 2.0 - 1.0, randomFloats(generator) * 2.0 - 1.0, 0.0f); // rotate around z-axis (in tangent space)
            ssaoNoise.push_back(noise);
        }
        glGenTextures(1, &noiseTexture);
        glBindTexture(GL_TEXTURE_2D, noiseTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        glUseProgram(ssao_program);
        glUniform1i(glGetUniformLocation(ssao_program, "gPosition"), 0); // the positions texture in the gbuffer
        glUniform1i(glGetUniformLocation(ssao_program, "gNormal"), 1); // the normals texture in the gbuffer
        glUniform1i(glGetUniformLocation(ssao_program, "texNoise"), 2); // the albedospec texture within the gbuffe

        glUseProgram(ssaoblur_program);
        glUniform1i(glGetUniformLocation(ssaoblur_program, "ssaoInput"), 0); // the positions texture in the gbuffer
    }

static inline void Render(Camera* _camera) 
    {
        // generate SSAO texture
        glBindFramebuffer(GL_FRAMEBUFFER, ssaoFBO);
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(program);

        for (unsigned int i = 0; i < 64; ++i)
            glUniform3fv(glGetUniformLocation(program, ("samples[" + std::to_string(i) + "]").c_str()), 1, glm::value_ptr(ssaoKernel[i]));

        glUniformMatrix4fv(glGetUniformLocation(program, "proj"), 1, GL_FALSE, glm::value_ptr(_camera->GetProjectionMatrix()));

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, GBuffer::GetPositions());
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, GBuffer::GetNormals());
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, noiseTexture);

        renderQuad();

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // Blur ssao texture
        glBindFramebuffer(GL_FRAMEBUFFER, ssaoBlurFBO);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(program2);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, ssaoColorBuffer);

        renderQuad();

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

GBuffer vertex shader..

#version 420 core

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 texcoord;
layout(location = 2) in vec3 normal;
layout(location = 3) in vec3 tangent;

out vec3 _texcoord;
out vec3 _normal;
out vec3 _tangent;
out vec3 _frag_pos;

uniform mat4 mod;
uniform mat4 view;
uniform mat4 proj;


void main()
{
    vec4 view_space = view * mod * vec4(position, 1.0);
    _frag_pos = view_space.xyz;
    _texcoord = texcoord;

    _normal = ((view * mod) * vec4(normal, 0.0)).xyz;
    _tangent = (mod * vec4(tangent, 0.0)).xyz;

    gl_Position = proj * view_space;
}

GBuffer fragment shader...

#version 420 core

layout(location = 0) out vec3 gPosition;    // Position texel colour
layout(location = 1) out vec3 gNormal;  // Normal texel colour
layout(location = 2) out vec4 gAlbedo;  // Albedo texel colour
layout(location = 3) out vec3 gSpecular;    // Cubemap texel colour
layout(location = 4) out vec3 gMetalness;   // Cubemap texel colour

in vec3 _texcoord;
in vec3 _normal;
in vec3 _tangent;
in vec3 _frag_pos;

uniform vec3        camera_pos;

uniform sampler2D   normal;     // Normal map
uniform sampler2D   albedo;     // Albedo and specular map
uniform sampler2D   specular;   // Specular map
uniform sampler2D   metalness;  // Metalness map

uniform samplerCube cubemap;    // Local cubemap reflection sampler


vec3 TBN()
{
    vec3 Normal = normalize(_normal);   // Optimise normal
    vec3 Tangent = normalize(_tangent);     // Optimise tangent

    vec3 Bitangent = cross(Tangent, Normal);    // Calculate bitangent
    vec3 BumpMapNormal = texture(normal, vec2(_texcoord).st).rgb;   // Assign rgb values from normal map

    BumpMapNormal = 2.0 * BumpMapNormal - vec3(1.0, 1.0, 1.0);  // normalise the normal map between -1 to 1

    mat3 TBN = mat3(Tangent, Bitangent, Normal);    // Create tangent, bitangent and normal matrix

    vec3 NewNormal;     // Create a new normal variable
    NewNormal = TBN * vec3(BumpMapNormal.r, -BumpMapNormal.g, BumpMapNormal.b);     // Flip green component for OpenGL
    NewNormal = normalize(NewNormal);   // Normalise the new normal

    return NewNormal;   // Return the newly calculated normal
}

vec4 Convolute()
{
    vec4 result = vec4(0.0);

    const float kernel[] = float[25] ( 0,1,2,1,0,
                                       1,2,3,2,1,
                                       2,3,4,3,2,
                                       1,2,3,2,1,
                                       0,1,2,1,0);

    vec2 delta = 1.0 / textureSize(albedo, 0);
    int index = 24;

    for (int j = -1; j <= 1; j++)
    {
        for (int i = -1; i <= 1; i++)
        {
            //for (int k = -1; k <= 1; k++)
            result += kernel[index--] * texture(albedo, vec2(_texcoord).st + (vec2(i, j) * delta));
        }
    }

    result /= 25.0;
    return result;
}

void main()
{
    gPosition = _frag_pos;
    gNormal = normalize(TBN());

    vec3 I = normalize(_frag_pos - camera_pos);     // Calculate eye to fragment direction
    vec3 R = reflect(I, normalize(TBN()));  // Reflect I with the vertex normal
    float M = texture(metalness, vec2(_texcoord.st)).r;

    //vec4 gaussian = Convolute();
    gAlbedo = texture(albedo, vec2(_texcoord.st));  // Assign albedo
    gSpecular = texture(specular, vec2(_texcoord.st)).rgb;  // Assign specular
    gMetalness = (texture(cubemap, R).rgb) * M;     // Assign metalness
}

light shader...

#version 420 core

out vec4 FragColor;

in vec2 _texcoord;


uniform vec3        camera_pos;
uniform sampler2D   gPosition;
uniform sampler2D   gNormal;
uniform sampler2D   gAlbedo;
uniform sampler2D   gSpecular;
uniform sampler2D   gMetalness;
uniform sampler2D   gSsao;

uniform vec3 lightPos;


void main(void)
{
    vec3 FragPos = texture(gPosition, _texcoord).rgb;
    vec3 Normal = texture(gNormal, _texcoord).rgb;
    vec3 Diffuse = texture(gAlbedo, _texcoord).rgb;
    float Emissive = texture(gAlbedo, _texcoord).a;
    vec3 Specular = texture(gAlbedo, _texcoord).rgb;
    vec3 Metalness = texture(gMetalness, _texcoord).rgb;    // Reflection pass

    float AmbientOcclusion = texture(gSsao, _texcoord).r;

    vec3 light_colour = vec3(1.0f, 0.8, 0.7);

    vec3 lighting = vec3(0.3 * Diffuse * AmbientOcclusion);
    vec3 viewDir = normalize(-FragPos);
    vec3 lightDir = normalize(lightPos - FragPos);
    vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * light_colour;    // Light colour

    vec3 halfwayDir = normalize(lightDir + viewDir);
    float spec = pow(max(dot(Normal, halfwayDir), 0.0), 32.0);
    vec3 specular = (Specular * light_colour) * spec;

    vec3 metalness = Metalness * Diffuse;

    lighting += diffuse + specular + metalness;

    FragColor = vec4(lighting, 1.0);
}

Any more code needed just ask. thanks for any help given

EDIT Problem fixed, was due to cubemap reflection, all working now


Solution

  • If a texture is looked up, and a specific texture channel is not present in the texture, then the function texture will return 0.0 for the green and blue channel and 1.0 for the alpha channel.

    This can be changed by the texture swizzle parameters GL_TEXTURE_SWIZZLE_R, GL_TEXTURE_SWIZZLE_G, GL_TEXTURE_SWIZZLE_B and GL_TEXTURE_SWIZZLE_A.

    If you want that the green and blue channel return the same value as the red channel then this can be done like this:

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED );
    

    Apply this paramters to the texture objects ssaoColorBuffer and ssaoColorBufferBlur, to solve the issue.


    See OpenGL 4.6 API Core Profile Specification; 15.2. SHADER EXECUTION; page 487]:

    When a texture lookup is performed in a fragment shader, the GL computes the filtered texture value ... and converts it to a texture base color Cb as shown in table 15.1,

    Texture Base Texture base color Internal Format    Cb              Ab
    RED                                                (Rt, 0, 0)      1
    RG                                                 (Rt, Gt, 0)     1
    RGB                                                (Rt, Gt, Bt)    1
    RGBA                                               (Rt, Gt, Bt)    At
    

    Table 15.1: Correspondence of filtered texture components to texture base components.

    followed by swizzling the components of Cb, controlled by the values of the texture parameters TEXTURE_SWIZZLE_R, TEXTURE_SWIZZLE_G, TEXTURE_SWIZZLE_B, and TEXTURE_SWIZZLE_A. If the value of TEXTURE_SWIZZLE_R is denoted by swizzler, swizzling computes the first component of Cs according to

    if (swizzler == RED)
    Cs[0] = Cb[0];
    else if (swizzler == GREEN)
    Cs[0] = Cb[1];
    else if (swizzler == BLUE)
    Cs[0] = Cb[2];
    else if (swizzler == ALPHA)
    Cs[0] = Ab;
    else if (swizzler == ZERO)
    Cs[0] = 0;
    else if (swizzler == ONE)
    Cs[0] = 1; // float or int depending on texture component type