Jump to content
  • Advertisement
Sign in to follow this  
Yours3!f

strange ssao results

This topic is 2412 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
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!