У меня проблема с моей реализацией SSAO. Всякий раз, когда я приближаюсь к поверхности, края экрана кажутся темнее, и это приводит к значительному падению производительности.
Насколько мне известно, на текстуре шума может происходить затемнение. Но я попытался изменить текстуру позиций на GL_REPEAT, GL_CLAMP_TO_EDGE, и это все еще не уменьшает проблему.
Есть идеи? Вот код ..
Настройка местоположения
// 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 Binding
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 исправил это