• Advertisement
Sign in to follow this  

strange ssao results

This topic is 2235 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I'm trying to implement the ssao effect, I've followed this tutorial: john-chapman.net - SSAO Tutorial

I get strange results as you can see in the screenshot. I also added the screenshot about the random seed texture.

so here's the host code:

setting up ssao random normal vector seed texture

const unsigned int noise_size = 4 * 4;
GLfloat* tmp_noise_data = new GLfloat[noise_size * 3]; //rgb, 4 * 4 pixels

for(unsigned int c = 0; c < noise_size; c++)
{
mymath::vec3f tmp_noise(objs::get()->get_random_num(-1.0f, 1.0f),
objs::get()->get_random_num(-1.0f, 1.0f),
0.0f);
objs::get()->mm.normalize_vec3f(tmp_noise);
tmp_noise_data[c * 3 + 0] = tmp_noise[0];
tmp_noise_data[c * 3 + 1] = tmp_noise[1];
tmp_noise_data[c * 3 + 2] = tmp_noise[2];
}

noise.create(); //create seed texture
noise.valid = true; //make sure we can work with it manually
noise.bind();
noise.width = sqrt(noise_size);
noise.height = noise.width;
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); //I set this to repeat as suggested in the tutorial
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB16F, ( GLsizei )noise.width, ( GLsizei )noise.height, 0, GL_RGBA, GL_FLOAT, tmp_noise_data ); //16f is enough precision for now

delete [] tmp_noise_data; //free raw data
tmp_noise_data = 0;


rendering ssao

glDisable( GL_DEPTH_TEST );
ssao->bind(); //bind ssao shader
noise.bind(); //bind the noise texture
ssao->pass_m4x4( objs::get()->ppl.get_projection_matrix(), "m4_p" );
ssao->pass_m4x4( objs::get()->ppl.get_model_view_matrix(), "m4_mv" );
ssao->pass_int( 0, "texture0" );
ssao->pass_int( 6, "texture6" );
ssao->pass_int( 7, "texture7" );
quad.render(); //render full-screen quad
ssao->unbind();
glEnable( GL_DEPTH_TEST );


the ssao vertex shader

#version 410
uniform mat4 m4_p, m4_mv;
in vec4 v4_vertex;
in vec2 v2_texture;
out vec2 v2_texture_coords;
out vec4 position;
out mat4 m4_proj;
void main()
{
m4_proj = m4_p;
v2_texture_coords = v2_texture;
position = m4_mv * v4_vertex;
gl_Position = m4_p * position;
}


the ssao pixel shader

#version 410
const float near = -1.0f; //used for depth reconstruction
const float far = -10000.0f;
const vec3 kernel[] = //the sampling kernel with 5x5 = 25 size
{
vec3(-0.00103941, 0.000803076, 0.00239354),
vec3(0.0624198, -0.0471239, 0.0542364),
vec3(0.00735433, -0.00505503, 0.00412747),
vec3(0.0883644, -0.0320721, 0.0241384),
vec3(0.00196805, 0.00204465, 0.0015872),
vec3(-0.0310556, -0.0356432, 0.0226177),
vec3(-0.00230654, -0.00555261, 0.0184322),
vec3(0.0256147, -0.0240642, 0.0578872),
vec3(-0.000863887, -0.103631, 0.10127),
vec3(-0.00663655, -0.048656, 0.0355283),
vec3(0.0990913, -0.0717796, 0.119121),
vec3(0.109437, 0.101326, 0.175118),
vec3(-0.261048, -0.0553236, 0.10301),
vec3(-0.0643752, -0.0714881, 0.0584595),
vec3(-0.00503261, 0.0364912, 0.0627584),
vec3(0.213038, -0.299639, 0.0043761),
vec3(0.00891424, -0.0924902, 0.0267256),
vec3(-0.0779569, -0.0850778, 0.0491574),
vec3(0.553357, 0.319116, 0.18019),
vec3(0.483033, 0.217492, 0.256035),
vec3(0.191972, 0.384143, 0.0412749),
vec3(0.459643, 0.455858, 0.0723233),
vec3(0.48474, -0.0748084, 0.297224),
vec3(0.117749, 0.30441, 0.343222),
vec3(-0.425826, -0.408802, 0.00103611)
};
const vec2 noise_scale = vec2(1280.0 / 4.0, 720.0 / 4.0); //I set this according to the turorial
const int kernel_size = 25; //kernel size is 25 right?
const float radius = 30.0; //a random radius, not sure if this is the right value for this
uniform sampler2D texture0; //4x4 noise texture
uniform sampler2D texture6; //normal buffer
uniform sampler2D texture7; //depth buffer
in vec2 v2_texture_coords;
in vec4 position; //view-space position of the full-screen quad
in mat4 m4_proj; //projection matrix
out vec4 v4_color; //outgoing color
vec3 decode_normals_spheremap(vec4 n) //this is the function for normal reconstruction from spheremap projection
{
vec4 nn = n * vec4(2.0, 2.0, 0.0, 0.0) + vec4(-1.0, -1.0, 1.0, -1.0);
float l = dot(nn.xyz, -nn.xyw);
nn.z = l;
nn.xy *= sqrt(l);
return nn.xyz * 2.0 + vec3(0.0, 0.0, -1.0);
}
vec3 decode_linear_depth(vec4 linear_depth, vec4 in_position) //this is the function for depth reconstruction from linear depth
{
return vec3(in_position.xy * (far / in_position.z), far) * linear_depth.x;
}
void main()
{
vec3 raw_depth = decode_linear_depth(texture(texture7, v2_texture_coords), position); //this holds viewspace depth
vec3 raw_normal = decode_normals_spheremap(texture(texture6, v2_texture_coords)); //this holds viewspace normals
vec3 random_vector = normalize(texture(texture0, v2_texture_coords * noise_scale).xyz * 2.0 - 1.0); //this is done according to the tutorial
vec3 tangent = normalize(random_vector - raw_normal * dot(random_vector, raw_normal));
vec3 bitangent = cross(raw_normal, tangent);
mat3 tbn = mat3(tangent, bitangent, raw_normal);
float occlusion = 0.0;
for(int c = 0; c < kernel_size; c++)
{
vec3 asample = tbn * kernel[c];
asample = asample * radius + raw_depth;
vec4 offset = vec4(asample, 1.0);
offset = m4_proj * offset; //convert offset to screen space (from view space) so that we can sample the depth texture at uv
offset.xy /= offset.w;
offset.xy = offset.xy * 0.5 + 0.5;
float sample_depth = texture(texture7, offset.xy).r;

//range checking as in the tutorial
float range_check = abs(raw_depth.z - sample_depth) < radius ? 1.0 : 0.0;
occlusion += (sample_depth <= asample.z ? 1.0 : 0.0) * range_check;
}
occlusion = 1.0 - (occlusion / kernel_size);
v4_color = vec4(vec3(occlusion), 1.0);
}


the seed texture looks rather odd to me, which could cause that strange pattern in the ssao screenshot...
Any idea what am I doing wrong?

Best regards,
Yours3!f

Share this post


Link to post
Share on other sites
Advertisement
ok so I tried to rewrite the ssao shader, and this time I tried to implement the ssao from here:
http://codeflow.org/...ient-occlusion/
because I found the source self-explanatory. (as opposed to the john chapman tutorial which I honestly didn't really understand)

so I tried to check each variable against the webgl app, and it seems like that I get difference of the occluder depth and the sample depth wrong. See the screenshots of the nice ssao looking difference, and my screenshot.

so here's the ssao shader:
#version 410

uniform sampler2D texture6; //normal buffer
uniform sampler2D texture7; //depth buffer
uniform sampler2D texture0; //random buffer
uniform float radius, far, depth_bias, singularity, strength;
uniform int sample_count, pattern_size;

in vec2 v2_texture_coords;
in mat4 m4_proj;
in vec4 position;

out vec4 v4_color;

vec3 decode_normals_spheremap(vec4 n)
{
vec4 nn = n * vec4(2.0, 2.0, 0.0, 0.0) + vec4(-1.0, -1.0, 1.0, -1.0);
float l = dot(nn.xyz, -nn.xyw);
nn.z = l;
nn.xy *= sqrt(l);
return nn.xyz * 2.0 + vec3(0.0, 0.0, -1.0);
}

vec3 decode_linear_depth(vec4 linear_depth, vec4 in_position)
{
return vec3(in_position.xy * (far / in_position.z), far) * linear_depth.x;
}

vec3 get_sample(int i)
{
vec2 mod_coord = mod(floor(gl_FragCoord.xy), pattern_size);
float y = ((mod_coord.x + mod_coord.y * pattern_size) + 0.5) / (pattern_size * pattern_size);
float x = (float(i) + 0.5) / float(sample_count);
return texture(texture0, vec2(x, y)).xyz;
}

void main()
{
//get normal encoded in spheremap projection
vec3 raw_normal = vec3(texture(texture6, v2_texture_coords).xy, 0.0);

//if its the background (skybox) then don't do anything
if(length(raw_normal) == 0.0)
{
v4_color = vec4(0.0);
return;
}

//decode normal
raw_normal = decode_normals_spheremap(vec4(raw_normal, 0.0));

//get view-space depth (or eye space)
vec3 raw_depth = decode_linear_depth(texture(texture7, v2_texture_coords), position);

//this will accumulate occlusion
float occlusion = 0.0;

//calculate occlusion
for(int c = 0; c < sample_count; c++)
{
//get random normal vector (already normalized)
vec3 random_vec = get_sample(c);
//if the angle between the normal and the random vector is 90
//degress then dont do anything, else multiply by radius
random_vec *= sign(dot(random_vec, raw_normal)) * radius;

//set view-space sampling position
vec3 sample_position = raw_depth + random_vec;
//transform into clip space by mult. by projection matrix
vec4 projs_sample_pos = m4_proj * vec4(sample_position, 1.0);
//get normalized device coordinates by w division and transform it into texture coordinates
//-1.0 ... 1.0 --> 0.0 ... 1.0
vec2 sample_tex_coord = ((projs_sample_pos / projs_sample_pos.w).xy + 1.0) * 0.5;

//grab depth values
float sample_depth = sample_position.z;
//linear depth * far = depth
float occluder_depth = texture(texture7, sample_tex_coord).x * far + depth_bias;

float difference = abs(occluder_depth - sample_depth);
float occluded = occluder_depth > sample_depth ? 1.0 : 0.0;
//singularity check is needed to ensure we dont place occlusion
//on objects that have depth discontinuity
float distance_term = difference < singularity ? 1.0 : 0.0;
//check if the surface random vector points away from the surface
//else dont do occlusion
float lambert = max(0.0, dot(random_vec, raw_normal));

occlusion += lambert * distance_term * occluded * strength;
}

//normalize occlusion by dividing by samples and clamp between 0 and 1
occlusion = clamp(occlusion / float(sample_count), 0.0, 1.0);
//since most occluded is 1 and least is 0 we need to reverse this
v4_color = vec4(1.0 - occlusion);
}


Best regards,
Yours3!f

Share this post


Link to post
Share on other sites
omg finally solved it... as I suspected the ssao shader is correct. The problem was that when I store the depth values into my framebuffer I divided with -10000 instead of -1000 (far plane distance), which caused the depth reconstruction to fail.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement