Skip to content

Commit

Permalink
Make SSAO correct (#5249)
Browse files Browse the repository at this point in the history
* Removed glow under main menu options, see #5109

* Much better SSAO

* Fix shader bug

* Increase kernel size

* Increase kernel size & bring back pute shader

* Reduce sample to 4

* Fix black line

* Stronger bias when resolution is lower
  • Loading branch information
CodingJellyfish authored Jan 18, 2025
1 parent 84830a7 commit b180a49
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 118 deletions.
28 changes: 24 additions & 4 deletions data/shaders/IBL.frag
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
uniform sampler2D ntex;
uniform sampler2D dtex;
uniform sampler2D albedo;
uniform sampler2D ssao;
uniform sampler2D ctex;

#ifdef GL_ES
layout (location = 0) out vec4 Diff;
Expand Down Expand Up @@ -70,25 +72,42 @@ vec2 RayCast(vec3 dir, vec3 hitCoord)
}
}

vec3 gtaoMultiBounce(float visibility, vec3 albedo)
{
// Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion"
vec3 a = 2.0404 * albedo - 0.3324;
vec3 b = -4.7951 * albedo + 0.6417;
vec3 c = 2.7552 * albedo + 0.6903;

return max(vec3(visibility), ((visibility * a + b) * visibility + c) * visibility);
}

// Main ===================================================================

void main(void)
{
vec2 uv = gl_FragCoord.xy / u_screen;
vec3 normal = DecodeNormal(texture(ntex, uv).xy);

Diff = vec4(0.25 * DiffuseIBL(normal), 1.);

float z = texture(dtex, uv).x;

vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix);
vec3 eyedir = -normalize(xpos.xyz);
// Extract roughness
float specval = texture(ntex, uv).z;

float ao = texture(ssao, uv).x;
// Lagarde and de Rousiers 2014, "Moving Frostbite to PBR"
float ao_spec = clamp(pow(max(dot(normal, eyedir), 0.) + ao, exp2(-16.0 * (1.0 - specval) - 1.0)) - 1.0 + ao, 0.0, 1.0);

#ifdef GL_ES
Spec = vec4(.25 * SpecularIBL(normal, eyedir, specval), 1.);
Diff = vec4(0.25 * DiffuseIBL(normal) * ao, 1.);
Spec = vec4(.25 * SpecularIBL(normal, eyedir, specval) * ao_spec, 1.);
#else
vec3 surface_color = texture(ctex, uv).xyz;
vec3 ao_multi = gtaoMultiBounce(ao, surface_color);
vec3 ao_spec_multi = gtaoMultiBounce(ao_spec, surface_color);

// :::::::: Compute Space Screen Reflection ::::::::::::::::::::::::::::::::::::

// Output color
Expand Down Expand Up @@ -123,7 +142,8 @@ void main(void)
outColor = fallback;
}

Spec = vec4(outColor.rgb, 1.0);
Diff = vec4(0.25 * DiffuseIBL(normal) * ao_multi, 1.);
Spec = vec4(outColor.rgb * ao_spec_multi, 1.0);
#endif

}
34 changes: 17 additions & 17 deletions data/shaders/bilateralH.comp
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,46 @@ uniform sampler2D source;
uniform sampler2D depth;
uniform vec2 pixel;
layout(r16f) volatile restrict writeonly uniform image2D dest;
uniform float sigma = 5.;
uniform float sigma = 2.;

layout (local_size_x = 8, local_size_y = 8) in;
layout (local_size_x = 4, local_size_y = 4) in;

shared float local_src[8 + 2 * 8][8];
shared float local_depth[8 + 2 * 8][8];
shared float local_src[4 + 2 * 4][4];
shared float local_depth[4 + 2 * 4][4];

void main()
{
int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y);
ivec2 iuv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
vec2 uv_m = (iuv - ivec2(8, 0)) * pixel;
vec2 uv_m = (iuv - ivec2(4, 0)) * pixel;
vec2 uv = iuv * pixel;
vec2 uv_p = (iuv + ivec2(8, 0)) * pixel;
vec2 uv_p = (iuv + ivec2(4, 0)) * pixel;

local_src[x][y] = texture(source, uv_m).x;
local_depth[x][y] = texture(depth, uv_m).x;
local_src[x + 8][y] = texture(source, uv).x;
local_depth[x + 8][y] = texture(depth, uv).x;
local_src[x + 16][y] = texture(source, uv_p).x;
local_depth[x + 16][y] = texture(depth, uv_p).x;
local_src[x + 4][y] = texture(source, uv).x;
local_depth[x + 4][y] = texture(depth, uv).x;
local_src[x + 8][y] = texture(source, uv_p).x;
local_depth[x + 8][y] = texture(depth, uv_p).x;

barrier();

float g0, g1, g2;
g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma);
g1 = exp(-0.5 / (sigma * sigma));
g2 = g1 * g1;
float sum = local_src[x + 8][y] * g0;
float pixel_depth = local_depth[x + 8][y];
float sum = local_src[x + 4][y] * g0;
float pixel_depth = local_depth[x + 4][y];
g0 *= g1;
g1 *= g2;
float tmp_weight, total_weight = g0;
for (int j = 1; j < 8; j++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x - j][y] - pixel_depth));
for (int j = 1; j < 5; j++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[4 + x - j][y] - pixel_depth));
total_weight += g0 * tmp_weight;
sum += local_src[8 + x - j][y] * g0 * tmp_weight;
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x + j][y] - pixel_depth));
sum += local_src[4 + x - j][y] * g0 * tmp_weight;
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[4 + x + j][y] - pixel_depth));
total_weight += g0 * tmp_weight;
sum += local_src[8 + x + j][y] * g0 * tmp_weight;
sum += local_src[4 + x + j][y] * g0 * tmp_weight;
g0 *= g1;
g1 *= g2;
}
Expand Down
4 changes: 2 additions & 2 deletions data/shaders/bilateralH.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ out vec4 FragColor;

void main()
{
float sigma = 5.;
float sigma = 2.;

vec2 uv = gl_FragCoord.xy * pixel;
float X = uv.x;
Expand All @@ -23,7 +23,7 @@ void main()
g0 *= g1;
g1 *= g2;
float tmp_weight, total_weight = g0;
for (int i = 1; i < 9; i++) {
for (int i = 1; i < 5; i++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X - float(i) * pixel.x, Y)).x - pixel_depth));
sum += texture(tex, vec2(X - float(i) * pixel.x, Y)) * g0 * tmp_weight;
total_weight += g0 * tmp_weight;
Expand Down
34 changes: 17 additions & 17 deletions data/shaders/bilateralV.comp
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,45 @@ uniform sampler2D source;
uniform sampler2D depth;
uniform vec2 pixel;
layout(r16f) volatile restrict writeonly uniform image2D dest;
uniform float sigma = 5.;
uniform float sigma = 2.;

layout (local_size_x = 8, local_size_y = 8) in;
layout (local_size_x = 4, local_size_y = 4) in;

shared float local_src[8][8 + 2 * 8];
shared float local_depth[8][8 + 2 * 8];
shared float local_src[4][4 + 2 * 4];
shared float local_depth[4][4 + 2 * 4];

void main()
{
int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y);
ivec2 iuv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
vec2 uv_m = (iuv - ivec2(0, 8)) * pixel;
vec2 uv_m = (iuv - ivec2(0, 4)) * pixel;
vec2 uv = iuv * pixel;
vec2 uv_p = (iuv + ivec2(0, 8)) * pixel;
vec2 uv_p = (iuv + ivec2(0, 4)) * pixel;

local_src[x][y] = texture(source, uv_m).x;
local_depth[x][y] = texture(depth, uv_m).x;
local_src[x][y + 8] = texture(source, uv).x;
local_depth[x][y + 8] = texture(depth, uv).x;
local_src[x][y + 16] = texture(source, uv_p).x;
local_depth[x][y + 16] = texture(depth, uv_p).x;
local_src[x][y + 4] = texture(source, uv).x;
local_depth[x][y + 4] = texture(depth, uv).x;
local_src[x][y + 8] = texture(source, uv_p).x;
local_depth[x][y + 8] = texture(depth, uv_p).x;

barrier();

float g0, g1, g2;
g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma);
g1 = exp(-0.5 / (sigma * sigma));
g2 = g1 * g1;
float sum = local_src[x][y + 8] * g0;
float pixel_depth = local_depth[x][y + 8];
float sum = local_src[x][y + 4] * g0;
float pixel_depth = local_depth[x][y + 4];
g0 *= g1;
g1 *= g2;
float tmp_weight, total_weight = g0;
for (int j = 1; j < 8; j++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 + j] - pixel_depth));
sum += local_src[x][y + 8 + j] * g0 * tmp_weight;
for (int j = 1; j < 5; j++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 4 + j] - pixel_depth));
sum += local_src[x][y + 4 + j] * g0 * tmp_weight;
total_weight += g0 * tmp_weight;
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 - j] - pixel_depth));
sum += local_src[x][y + 8 - j] * g0 * tmp_weight;
tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 4 - j] - pixel_depth));
sum += local_src[x][y + 4 - j] * g0 * tmp_weight;
total_weight += g0 * tmp_weight;
g0 *= g1;
g1 *= g2;
Expand Down
4 changes: 2 additions & 2 deletions data/shaders/bilateralV.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ out vec4 FragColor;

void main()
{
float sigma = 5.;
float sigma = 2.;

vec2 uv = gl_FragCoord.xy * pixel;
float X = uv.x;
Expand All @@ -23,7 +23,7 @@ void main()
g0 *= g1;
g1 *= g2;
float tmp_weight, total_weight = g0;
for (int i = 1; i < 9; i++) {
for (int i = 1; i < 5; i++) {
tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X, Y - float(i) * pixel.y)).x - pixel_depth));
sum += texture(tex, vec2(X, Y - float(i) * pixel.y)) * g0 * tmp_weight;
total_weight += g0 * tmp_weight;
Expand Down
4 changes: 1 addition & 3 deletions data/shaders/combine_diffuse_color.frag
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
uniform sampler2D diffuse_map;
uniform sampler2D specular_map;
uniform sampler2D ssao_tex;
uniform sampler2D normal_color;
uniform sampler2D diffuse_color;
#if defined(GL_ES) && defined(GL_FRAGMENT_PRECISION_HIGH)
Expand Down Expand Up @@ -28,7 +27,6 @@ void main()
float specMapValue = texture(normal_color, tc).z;
float emitMapValue = diffuseMatColor.w;

float ao = texture(ssao_tex, tc).x;
vec3 DiffuseComponent = texture(diffuse_map, tc).xyz;
vec3 SpecularComponent = texture(specular_map, tc).xyz;

Expand All @@ -42,7 +40,7 @@ void main()
vec3 tmp = DiffuseComponent * mix(diffuseMatColor.xyz, vec3(0.0), metallicMapValue) + (metallicMatColor * SpecularComponent);

vec3 emitCol = diffuseMatColor.xyz + (diffuseMatColor.xyz * diffuseMatColor.xyz * emitMapValue * emitMapValue * 10.0);
vec4 color_1 = vec4(tmp * ao + (emitMapValue * emitCol), 1.0);
vec4 color_1 = vec4(tmp + (emitMapValue * emitCol), 1.0);

// Fog
float depth = texture(depth_stencil, tc).x;
Expand Down
7 changes: 5 additions & 2 deletions data/shaders/degraded_ibl.frag
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
uniform sampler2D ntex;
uniform sampler2D ssao;

#ifdef GL_ES
layout (location = 0) out vec4 Diff;
Expand All @@ -17,7 +18,9 @@ void main(void)
{
vec2 uv = gl_FragCoord.xy / u_screen;
vec3 normal = DecodeNormal(texture(ntex, uv).xy);
vec3 spec_color = vec3(0.031, 0.106, 0.173);
float ao = texture(ssao, uv).x;

Diff = vec4(0.25 * DiffuseIBL(normal), 1.);
Spec = vec4(0.031, 0.106, 0.173, 1.);
Diff = vec4(0.25 * DiffuseIBL(normal) * ao, 1.);
Spec = vec4(spec_color * ao, 1.);
}
44 changes: 30 additions & 14 deletions data/shaders/ssao.frag
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// From paper http://graphics.cs.williams.edu/papers/AlchemyHPG11/
// and improvements here http://graphics.cs.williams.edu/papers/SAOHPG12/
// and implementations here https://github.com/google/filament/blob/026b985c07b7eec4f678e0e5130d0a4e742e9c61/filament/src/materials/ssao/saoImpl.fs

uniform sampler2D dtex;
uniform float radius;
uniform float k;
uniform float sigma;
out float AO;

const float tau = 7.;
const float beta = 0.002;
const float epsilon = .00001;
const float thickness = 10.0;

#define SAMPLES 16
const float invSamples = 0.0625; // 1. / SAMPLES
#define SAMPLES 4
const float invSamples = 0.25; // 1. / SAMPLES

vec3 getXcYcZc(int x, int y, float zC)
{
Expand All @@ -22,6 +21,12 @@ vec3 getXcYcZc(int x, int y, float zC)
return vec3(xC, yC, zC);
}

float interleavedGradientNoise(highp vec2 w)
{
const vec3 m = vec3(0.06711056, 0.00583715, 52.9829189);
return fract(m.z * fract(dot(w, m.xy)));
}

void main(void)
{
vec2 uv = gl_FragCoord.xy / u_screen;
Expand All @@ -35,31 +40,42 @@ void main(void)
vec3 norm = normalize(cross(ddy, ddx));

float r = radius / FragPos.z;
float phi = 3. * float((x ^ y) + x * y);
float phi = interleavedGradientNoise(vec2(gl_FragCoord.x, gl_FragCoord.y));
float bl = 0.0;
float m = log2(r) + 6. + log2(invSamples);

float theta = mod(2. * 3.14 * tau * .5 * invSamples + phi, 6.283185307179586);
float peak = 0.1 * radius;
float peak2 = peak * peak;
float intensity = 2.0 * 3.14159 * sigma * peak * invSamples;

// Apply stronger bias when the resolution is lower.
float horizon = min(100. / min(u_screen.x, u_screen.y), 0.3);
float bias = min(1. / min(u_screen.x, u_screen.y), 0.003);

float theta = phi * 2.0 * 2.4 * 3.14159;
vec2 rotations = vec2(cos(theta), sin(theta)) * u_screen;
vec2 offset = vec2(cos(invSamples), sin(invSamples));

for(int i = 0; i < SAMPLES; ++i) {
for(int i = 0; i < SAMPLES; ++i)
{
float alpha = (float(i) + .5) * invSamples;
rotations = vec2(rotations.x * offset.x - rotations.y * offset.y, rotations.x * offset.y + rotations.y * offset.x);
float h = r * alpha;
vec2 localoffset = h * rotations;

m = m + .5;
ivec2 ioccluder_uv = ivec2(x, y) + ivec2(localoffset);

if (ioccluder_uv.x < 0 || ioccluder_uv.x > int(u_screen.x) || ioccluder_uv.y < 0 || ioccluder_uv.y > int(u_screen.y)) continue;
ivec2 ioccluder_uv = clamp(ivec2(x, y) + ivec2(localoffset), ivec2(0), ivec2(u_screen));

float LinearoccluderFragmentDepth = textureLod(dtex, vec2(ioccluder_uv) / u_screen, max(m, 0.)).x;
vec3 OccluderPos = getXcYcZc(ioccluder_uv.x, ioccluder_uv.y, LinearoccluderFragmentDepth);

vec3 vi = OccluderPos - FragPos;
bl += max(0., dot(vi, norm) - FragPos.z * beta) / (dot(vi, vi) + epsilon);
float vv = dot(vi, vi);
float vn = dot(vi, norm);
float w = max(0.0, 1.0 - vv / thickness / thickness);
w = w * w;
w *= step(vv * horizon * horizon, vn * vn);
bl += w * max(0., vn - FragPos.z * bias) / (vv + peak);
}

AO = max(pow(1.0 - min(2. * sigma * bl * invSamples, 0.99), k), 0.);
AO = pow(max(1.0 - sqrt(bl * intensity), 0.), k);
}
Loading

0 comments on commit b180a49

Please sign in to comment.