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