1/* clang-format off */ 2[vertex] 3 4layout(location = 0) in highp vec4 vertex_attrib; 5/* clang-format on */ 6 7void main() { 8 9 gl_Position = vertex_attrib; 10 gl_Position.z = 1.0; 11} 12 13/* clang-format off */ 14[fragment] 15 16uniform sampler2D source_ssao; //texunit:0 17/* clang-format on */ 18uniform sampler2D source_depth; //texunit:1 19uniform sampler2D source_normal; //texunit:3 20 21layout(location = 0) out float visibility; 22 23////////////////////////////////////////////////////////////////////////////////////////////// 24// Tunable Parameters: 25 26/** Increase to make depth edges crisper. Decrease to reduce flicker. */ 27uniform float edge_sharpness; 28 29/** Step in 2-pixel intervals since we already blurred against neighbors in the 30 first AO pass. This constant can be increased while R decreases to improve 31 performance at the expense of some dithering artifacts. 32 33 Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was 34 unobjectionable after shading was applied but eliminated most temporal incoherence 35 from using small numbers of sample taps. 36 */ 37 38uniform int filter_scale; 39 40/** Filter radius in pixels. This will be multiplied by SCALE. */ 41#define R (4) 42 43////////////////////////////////////////////////////////////////////////////////////////////// 44 45// Gaussian coefficients 46const float gaussian[R + 1] = 47 //float[](0.356642, 0.239400, 0.072410, 0.009869); 48 //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0 49 float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0 50//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0 51 52/** (1, 0) or (0, 1) */ 53uniform ivec2 axis; 54 55uniform float camera_z_far; 56uniform float camera_z_near; 57 58uniform ivec2 screen_size; 59 60void main() { 61 62 ivec2 ssC = ivec2(gl_FragCoord.xy); 63 64 float depth = texelFetch(source_depth, ssC, 0).r; 65 //vec3 normal = texelFetch(source_normal, ssC, 0).rgb * 2.0 - 1.0; 66 67 depth = depth * 2.0 - 1.0; 68 depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); 69 70 float depth_divide = 1.0 / camera_z_far; 71 72 //depth *= depth_divide; 73 74 /* 75 if (depth > camera_z_far * 0.999) { 76 discard; //skybox 77 } 78 */ 79 80 float sum = texelFetch(source_ssao, ssC, 0).r; 81 82 // Base weight for depth falloff. Increase this for more blurriness, 83 // decrease it for better edge discrimination 84 float BASE = gaussian[0]; 85 float totalWeight = BASE; 86 sum *= totalWeight; 87 88 ivec2 clamp_limit = screen_size - ivec2(1); 89 90 for (int r = -R; r <= R; ++r) { 91 // We already handled the zero case above. This loop should be unrolled and the static branch optimized out, 92 // so the IF statement has no runtime cost 93 if (r != 0) { 94 95 ivec2 ppos = ssC + axis * (r * filter_scale); 96 float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r; 97 ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit); 98 float temp_depth = texelFetch(source_depth, rpos, 0).r; 99 //vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0; 100 101 temp_depth = temp_depth * 2.0 - 1.0; 102 temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near)); 103 //temp_depth *= depth_divide; 104 105 // spatial domain: offset gaussian tap 106 float weight = 0.3 + gaussian[abs(r)]; 107 //weight *= max(0.0, dot(temp_normal, normal)); 108 109 // range domain (the "bilateral" weight). As depth difference increases, decrease weight. 110 weight *= max(0.0, 1.0 - edge_sharpness * abs(temp_depth - depth)); 111 112 sum += value * weight; 113 totalWeight += weight; 114 } 115 } 116 117 const float epsilon = 0.0001; 118 visibility = sum / (totalWeight + epsilon); 119} 120