SSAO |靠近表面时,屏幕边缘变暗

时间:2018-09-09 19:14:19

标签: c++ opengl glsl

Problem 我的SSAO实施存在问题。每当我靠近表面时,屏幕的边缘就会变暗,这会导致性能大幅下降。

据我所知,噪声纹理上可能发生变暗。但是我尝试将位置纹理更改为GL_REPEAT,GL_CLAMP_TO_EDGE,但它仍然不能减少问题。

有什么想法吗?这是代码。

gPosition设置

// The attachment is added in as follows 
    new FboAttachment(width, height, GL_RGB16F, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0, false, true)

// attachment is created like this
    // This function will create an fbo attachment
        inline void Create()
        {
            // Generate a texture and sets its data and information
            glGenTextures(1, &_texture);    // Generate the colour texture
            glBindTexture(GL_TEXTURE_2D, _texture);     // Bind the texture map
            glTexImage2D(GL_TEXTURE_2D, 0, _internal_format, _width, _height, 0, _format, _type, 0);    // Store the texture data to a buffer
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   // Set the linear filter for min
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _mipmapping == true ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);   // Set the linear filter for mag

            /*
            * If border clamping is enabled then set the border colour (mainly used for shadow mapping to remove peter panning)
            */
            if (_border_clamping)
            {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
                GLfloat border[4] = { 1,0,0,0 };
                glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
            }

            /*
            * If mipmapping enabled then generate mipmaps for this FBO texture. 
            */
            if (_mipmapping)
            {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); // set the minimum texture mip level
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); // set the maximum texture mip level
                glGenerateMipmap(GL_TEXTURE_2D); // generate a mipmap for the shadowmap
            }

            // Send this generated texture to the framebufferobject
            glFramebufferTexture2D(GL_FRAMEBUFFER, _attachment, GL_TEXTURE_2D, _texture, 0);        // Assign the texture to the frame buffer as an attachment

            // Check for any problems with the frame buffer object
            if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                std::cout << "Error : FBO Could not be created!" << std::endl;
        }

SSAO设置

// Initialise the post effect
    inline void Create(std::vector<GLuint> shader_programs, size_t width, size_t height, GLuint sample_res)
    {
        _shader_programs = shader_programs;     // Assign shader pointers
        _sample_res = sample_res;   // Assign sample resolution value

        _rect = new Rect((double)width, (double)height, 1.0f, true);

        // Create two frame buffers, one for ssao colour and another for ssao blur
        _fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
        _fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
        //////////////////////////////////////////////////////////////////////////////////////////////////////////

        std::uniform_real_distribution<GLfloat> rand_floats(0.0f, 1.0f);    // Generate random floats between 0.0 and 1.0
        std::default_random_engine rand_generator;  // A generator for randomising floats

        // Create temp iterator var
        for (unsigned int i = 0; i < 64; ++i)   // Iterate through each sample...
        {
            glm::vec3 sample(rand_floats(rand_generator) * 2.0f - 1.0f, 
                             rand_floats(rand_generator) * 2.0f - 1.0f, 
                             rand_floats(rand_generator)); // the third parameter was wrong on this line

            sample = glm::normalize(sample);    // Normalise the sample
            sample *= rand_floats(rand_generator);  // Seed the randomisation

            float scale = (float)i / 64.0f; // Get pixel position in NDC about the resolution size

            scale = Math::lerpf(0.1f, 1.0f, scale * scale);     // Interpolate the scale
            sample *= scale;    // Scale the s and t values

            _ssao_kernals.push_back(sample);    // Assign sample to the kernal array

            _u_samples.push_back(glGetUniformLocation(shader_programs[0], ("samples[" + std::to_string(i) + "]").c_str()));     // Get each sample uniform location
        }

        // generate noise texture
        for (unsigned int i = 0; i < 16; i++)
        {
            glm::vec3 noise(rand_floats(rand_generator) * 2.0 - 1.0, rand_floats(rand_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(_shader_programs[0]);  // Use the first shader pass
        glUniform1i(glGetUniformLocation(shader_programs[0], "gPosition"), 0); // The positions texture in the gbuffer
        glUniform1i(glGetUniformLocation(shader_programs[0], "gNormal"), 1); // The normals texture in the gbuffer
        glUniform1i(glGetUniformLocation(shader_programs[0], "texNoise"), 2); // The albedospec texture in the gbuffer

        _u_projection = glGetUniformLocation(shader_programs[0], "proj");   // Get projection uniform

        glUseProgram(_shader_programs[1]);  // Use the second shader pass
        glUniform1i(glGetUniformLocation(shader_programs[1], "ssaoInput"), 0); // the positions texture in the gbuffer
    }

SSAO绑定

inline virtual void Render()
    {
        _fbos[0]->Bind(); // bind ssao texture

        glClear(GL_COLOR_BUFFER_BIT); // clear colour data on the screen

        glUseProgram(_shader_programs[0]); // Use the first shader pass

        for (unsigned int i = 0; i < SSAO_SAMPLE_RESOLUTION; ++i)   // For each ssao sample...
            glUniform3fv(_u_samples[i], 1, glm::value_ptr(_ssao_kernals[i]));   // Assign kernal uniform data

        glUniformMatrix4fv(_u_projection, 1, GL_FALSE, glm::value_ptr(Content::_map->GetCamera()->GetProjectionMatrix()));  // Assign camera projection uniform data

        glActiveTexture(GL_TEXTURE0);   // Set active texture to index 0
        glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[0]->_texture);    // Bind positions
        glActiveTexture(GL_TEXTURE1);   // Set active texture to index 1
        glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[1]->_texture);    // Bind normals
        glActiveTexture(GL_TEXTURE2);   // Set active texture to index 2
        glBindTexture(GL_TEXTURE_2D, noiseTexture); // Bind the noise texture

        _screen_rect->Render(1);        // Render to screen rectangle

        _fbos[0]->Unbind();


        // Blur ssao texture
        _fbos[1]->Bind();

        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(_shader_programs[1]);  // Use the second shader pass

        glActiveTexture(GL_TEXTURE0);   // Bind active texture to index 0
        glBindTexture(GL_TEXTURE_2D, _fbos[0]->GetAttachments()[0]->_texture);  // Bind the final colour

        _screen_rect->Render(1);        // Render to screen rectangle

        _fbos[1]->Unbind();
    }

SSAO片段着色器

#version 330 core

out float FragColor;

in vec2 _texcoord;

uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D texNoise;

uniform vec3 samples[64];

int kernelSize = 64;
float radius = 0.5;
float bias = 0.025;

const vec2 noiseScale = vec2(1920.0 / 4.0, 1080.0 / 4.0); 

uniform mat4 proj;

void main()
{    
    vec3 fragPos = texture(gPosition, _texcoord).xyz;
    vec3 normal = normalize(texture(gNormal, _texcoord).rgb);
    vec3 randomVec = normalize(texture(texNoise, _texcoord * noiseScale).xyz);

    vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
    vec3 bitangent = cross(normal, tangent);
    mat3 TBN = mat3(tangent, bitangent, normal);

    float occlusion = 0.0;
    for(int i = 0; i < kernelSize; ++i)
    {
        // get sample position
        vec3 sample = TBN * samples[i]; // from tangent to view-space
        sample = fragPos + sample * radius; 

        // project sample position (to sample texture) (to get position on screen/texture)
        vec4 offset = vec4(sample, 1.0);
        offset = proj * offset; // from view to clip-space
        offset.xyz /= offset.w; // perspective divide
        offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0

        // get sample depth
        float sampleDepth = texture(gPosition, offset.xy).z; // get depth value of kernel sample

        // range check & accumulate
        float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
        occlusion += (sampleDepth >= sample.z + bias ? 1.0 : 0.0) * rangeCheck;           
    }

    occlusion = 1.0 - (occlusion / kernelSize);  
    FragColor = pow(occlusion, 5.0);
}

这个问题可能是什么原因?

问题已解决 GL_CLAMP_TO_EDGE修复了它

0 个答案:

没有答案