Its been a while but i still cant make my implementation of ssao to work anyhow:
So basically i use ssao with a world space approach that means
after drawing gbuffer i dont use screen space apptoach to find occlusion but rather i decompose fragment original position, apply rotation (kernel sample) to fragment normal and multiple that by some factor (11 cm truth to be told), and check whenever sample translated by this position has lower value than tested fragment
(everything is calculated in worldspace rather than in screen space)
Yet i get this:
weird thing is that within each object i see some weird swirl at the center of each face like what the hell? how?
[Spoiler]
void DrawNormalsToFBO()
{
InitiateFBODraw(&normalfbo);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
ACTUAL_MODEL.LoadIdentity();
writenormal_shader.Enable();
FPP_CAM->SetView();
//gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, 1.0f, 0.1f, 10000.0f);
gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, lcASPECT, 0.1f, 10000.0f);
mat4 MVP = (ACTUAL_MODEL * ACTUAL_VIEW) * ACTUAL_PROJECTION;
writenormal_shader.SendMVPtoShader(MVP);
writenormal_shader.SendWorldMatrixtoShader( ACTUAL_MODEL );
model3f * p = map->models;
while ( p!=0)
{
p->DrawSimpleModel(&writenormal_shader);
p = ((model3f*)p->next);
}
writenormal_shader.Disable();
normalfbo.unbind();
}
void DrawTangentsToFBO()
{
InitiateFBODraw(&tangentfbo);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
ACTUAL_MODEL.LoadIdentity();
writetangent_shader.Enable();
FPP_CAM->SetView();
//gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, 1.0f, 0.1f, 10000.0f);
gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, lcASPECT, 0.1f, 10000.0f);
mat4 MVP = (ACTUAL_MODEL * ACTUAL_VIEW) * ACTUAL_PROJECTION;
writetangent_shader.SendMVPtoShader(MVP);
writetangent_shader.SendWorldMatrixtoShader( ACTUAL_MODEL );
model3f * p = map->models;
while ( p!=0)
{
p->DrawSimpleModel(&writetangent_shader);
p = ((model3f*)p->next);
}
writetangent_shader.Disable();
tangentfbo.unbind();
}
void WriteDepthToFBO()
{
// InitiateDepthWriteFBODraw();
InitiateFBODraw(&depthfbo);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
ClearDepth();
WriteDepth();
depthfbo.unbind();
}
where i call these
void CalculaceTangentData() //Put that into color component
{
for (int i=0; i < FaceLength; i++)
{
int index = VBO_BE[i].INDEX_START;
int len = VBO_BE[i].length;
for (int v=index; v < index+len; v++)
{
int next;
if (v == index+len-1) next = index;
else next = v+1;
AOS[v].c = Normalize(vectorAB(AOS[v].v, AOS[next].v));
}
}
// SendToGPU();
}
void CalcNormals(){}
[/Spoiler]
and so on the thing is i write normals to 24 bit uchar texture
where i use the formula color = normal*0.5+0.5;
and then decompose it in a shader by
tangent or normal = texture2D(coord).xyz*2.0-1.0;
only depth component has 32 bit precision
and i write depth map as a distance from camera to fragment (no fancy matrix multiplications) just distance between eye and fragment and store it as 4 8 bit values (as one pixel)
so basically i create a set of models (scene) calculate all revelant data as: normals tangents
then during rendering stage i draw everything
first to texture that stores normals
then to texture that stores tangents
then to texture that stores depth
and here is how i produce kernel samples
for (int i=0; i < 64; i++)
{
float iter = float(i)/64.0;
float acoord = 160.0;
float xc = (10.0+iter*acoord)*imopi;
kernsamples[i] = Normalize(vec3(sin(xc), RandFloat()*2.0-1.0, cos(xc)));
}
they are facing z+ from right(x+) to left (x-) with random y (top down value)
and then i apply lets call it ssao
void DrawSSAO()
{
FPP_CAM->SetView();
WriteDepthToFBO();
DrawNormalsToFBO();
DrawTangentsToFBO();
FPP_CAM->SetView();
ACTUAL_MODEL.LoadIdentity();
gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, lcASPECT, 0.1f, 10000.0f);
mat4 MVP = (ACTUAL_MODEL * ACTUAL_VIEW) * ACTUAL_PROJECTION;
InitiateFBODraw(&ssaofbo);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
gluPerspectiveA(ACTUAL_PROJECTION, 90.0f, lcASPECT, 0.1f, 10000.0f);
ssao_shader.Enable();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthfbo.FBO_TEX);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, normalfbo.FBO_TEX);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, tangentfbo.FBO_TEX);
ssao_shader.Send1I("depthtex", 0);
ssao_shader.Send1I("normaltex", 1);
ssao_shader.Send1I("tangenttex", 2);
ssao_shader.Send1F("z_near", 0.1);
ssao_shader.Send1F("z_far", 10000.0);
ssao_shader.Send1F("fov", 90.0);
ssao_shader.Send1F("aspect", lcASPECT);
ssao_shader.Send3F("campos", FPP_CAM->pos);
ssao_shader.Send3F("front_vec", FPP_CAM->ReturnFrontVector());
ssao_shader.Send3F("dirX", FPP_CAM->ReturnRightVector());
ssao_shader.Send3F("dirY", FPP_CAM->ReturnUpVector());
ssao_shader.SendMVPtoShader(MVP);
for ( int i=0; i < 64; i++)
ssao_shader.Send3F("samples["+IntToStr(i)+"]", kernsamples[i]);
DrawFullScrQuad(&ssao_shader);
ssao_shader.Disable();
ssaofbo.unbind();
//when you call unbind it automatically binds main framebuffer
glViewport(0, 0, int ( rSCREEN_WIDTH ), int ( rSCREEN_HEIGHT ));
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
//now drae fullscreen quad with ssao texture to display it on the screen
ssao_mask.Enable();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ssaofbo.FBO_TEX);
ssao_mask.Send1I("ssaotex", 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
DrawFullScrQuad(&ssao_mask);
glDisable(GL_BLEND);
ssao_mask.Disable();
}
And the frag shader
precision highp float;
uniform vec4 MVP1;
uniform vec4 MVP2;
uniform vec4 MVP3;
uniform vec4 MVP4;
float dp43(vec4 matrow, vec3 p)
{
return ( (matrow.x*p.x) + (matrow.y*p.y) + (matrow.z*p.z) + matrow.w );
}
float dp33(vec3 matrow, vec3 p)
{
return matrow.x*p.x + matrow.y*p.y + matrow.z*p.z;
}
vec3 vectorAB( vec3 A, vec3 B)
{
return B-A;
}
const float imopi = 0.01745329251; //pi / 180.0 RAD_2_DEG
uniform vec3 dirX; //RIGHT VIEW VECTOR
uniform vec3 dirY; //UP VIEW VECTOR
uniform vec3 front_vec; //FRONT VIEW VECTOR
uniform float fov;
uniform float z_near;
uniform float z_far;
uniform float aspect;
uniform vec3 campos;
const int MAX_KERNEL_SIZE = 64;
uniform sampler2D depthtex;
uniform sampler2D normaltex;
uniform sampler2D tangenttex;
uniform vec3 samples[64];
varying vec2 TexCoord; //position of the fragment on the screen range 0..1
highp float getDepth(highp vec2 pos)
{
highp vec4 packedZValue = texture2D(depthtex, pos);
const highp vec4 bitShifts = vec4(1.0 / (256.0 * 256.0 * 256.0),
1.0 / (256.0 * 256.0),
1.0 / 256.0,
1.0);
highp float shadow = dot(packedZValue , bitShifts);
return shadow;
}
vec3 getNormal(vec2 pos)
{
vec4 tn = texture2D(normaltex, pos);
return tn.xyz * 2.0 - 1.0;
}
vec3 getTangent(vec2 pos)
{
vec4 tn = texture2D(tangenttex, pos);
return tn.xyz * 2.0 - 1.0;
}
vec3 GetDirectionFromScreen(vec3 pos, float depth, vec2 coord)
{
float a = fov / 2.0;
float cotangent = 1.0 / tan( a * imopi );
float ax = z_near / cotangent;
float screen_w = 2.0*ax;
float screen_h = screen_w;
screen_w = screen_w * aspect;
float scr_coord_x = coord.x;
float scr_coord_y = coord.y;
vec3 dir = front_vec;
//move to lower left corner of the near screen
vec3 start_pos = (pos + dir * z_near) + (-dirX * (screen_w / 2.0)) + (-dirY * (screen_h/2.0));
vec3 start = start_pos + (dirX * (screen_w * scr_coord_x)) + (dirY * (screen_h * scr_coord_y));
return normalize( vectorAB(pos, start) );
}
const float ssao_range = 30.0;
void main()
{
float sample_depth = getDepth(TexCoord);
vec3 sample_pos = campos + GetDirectionFromScreen(campos, sample_depth, TexCoord)*sample_depth;
vec3 sample_normal = getNormal(TexCoord);
vec3 sample_tangent = getTangent(TexCoord);
vec3 sample_binormal = normalize(cross(sample_normal*100.0, sample_tangent*100.0));
//compute rotation matrix
/*
vec3 tbn1 = vec3(sample_tangent.x, sample_binormal.x, sample_normal.x);
vec3 tbn2 = vec3(sample_tangent.y, sample_binormal.y, sample_normal.y);
vec3 tbn3 = vec3(sample_tangent.z, sample_binormal.z, sample_normal.z);
*/
vec3 tbn1 = vec3(sample_tangent.x, sample_tangent.y, sample_tangent.z);
vec3 tbn2 = vec3(sample_binormal.x, sample_binormal.y, sample_binormal.z);
vec3 tbn3 = vec3(sample_normal.x, sample_normal.y, sample_normal.z);
float AO = 0.0;
for (int i = 0 ; i < MAX_KERNEL_SIZE ; i++)
{
vec3 rot_sample_dir;
rot_sample_dir.x = dp33(tbn1, samples[i]);
rot_sample_dir.y = dp33(tbn2, samples[i]);
rot_sample_dir.z = dp33(tbn3, samples[i]);
vec3 kernel_pos = sample_pos + rot_sample_dir*30.0;
vec4 vertexClip;
vertexClip.x = -dp43(MVP1, kernel_pos);
vertexClip.y = dp43(MVP2, kernel_pos);
vertexClip.z = dp43(MVP3, kernel_pos);
vertexClip.w = dp43(MVP4, kernel_pos);
vertexClip = vertexClip / vertexClip.w;
vertexClip = vertexClip*0.5 + 0.5;
float kernel_depth = getDepth(vertexClip.xy);
if (kernel_depth < sample_depth) AO = AO + 1.0;
}
AO = 1.0 - AO/128.0;
gl_FragColor = vec4(vec3(AO),1.0);
}
I know theres a lot of code to go through but maybe someone will see something that i cant?
I was checking depthmap, normalmap and tangent map they seem to be fine, also getdirectionfromscreen seems to work as expected too