aboutsummaryrefslogtreecommitdiff
path: root/res/shaders/postprocess.fs
blob: 1d90d75bdd0e914a1b7a1c124a34a8020761e7df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#version 420 core

in vec2 _f_texture;

layout(binding = 2) uniform sampler2D main_colour;

layout(std140, binding = 0) uniform _u_globals {
    mat4 proj;
    mat4 view;
    vec4 frustum[6];
    float znear;
    float zfar;
    float xfov;
    float yfov;
    int time;
};

const float u_lumaThreshold = 0.125f;
const float u_mulReduce = 1.0f / 8.0f;
const float u_minReduce = 1.0f / 128.0f;
const float u_maxSpan = 8.0f; 

out vec4 _o_colour;

void main() {
    const vec2 coords =
        vec2((_f_texture.x + 1.0f) / 2.0f, (_f_texture.y + 1.0f) / 2.0f);

    vec3 rgbM = texture(main_colour, coords).rgb;
    vec2 size = textureSize(main_colour, 0);
    vec2 u_texelStep = vec2(1.0f / size.x, 1.0f / size.y);

	// Sampling neighbour texels. Offsets are adapted to OpenGL texture coordinates.
	vec3 rgbNW = textureOffset(main_colour, coords, ivec2(-1, 1)).rgb;
    vec3 rgbNE = textureOffset(main_colour, coords, ivec2(1, 1)).rgb;
    vec3 rgbSW = textureOffset(main_colour, coords, ivec2(-1, -1)).rgb;
    vec3 rgbSE = textureOffset(main_colour, coords, ivec2(1, -1)).rgb;

	// see http://en.wikipedia.org/wiki/Grayscale
	const vec3 toLuma = vec3(0.299, 0.587, 0.114);

	// Convert from RGB to luma.
	float lumaNW = dot(rgbNW, toLuma);
	float lumaNE = dot(rgbNE, toLuma);
	float lumaSW = dot(rgbSW, toLuma);
	float lumaSE = dot(rgbSE, toLuma);
	float lumaM = dot(rgbM, toLuma);

	// Gather minimum and maximum luma.
	float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
	float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));

	// If contrast is lower than a maximum threshold ...
	if (lumaMax - lumaMin <= lumaMax * u_lumaThreshold)
	{
		// ... do no AA and return.
		_o_colour = vec4(rgbM, 1.0);

		return;
	}

	// Sampling is done along the gradient.
	vec2 samplingDirection;
	samplingDirection.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
    samplingDirection.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));

    // Sampling step distance depends on the luma: The brighter the sampled texels, the smaller the final sampling step direction.
    // This results, that brighter areas are less blurred/more sharper than dark areas.
    float samplingDirectionReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * 0.25 * u_mulReduce, u_minReduce);

	// Factor for norming the sampling direction plus adding the brightness influence.
	float minSamplingDirectionFactor = 1.0 / (min(abs(samplingDirection.x), abs(samplingDirection.y)) + samplingDirectionReduce);

    // Calculate final sampling direction vector by reducing, clamping to a range and finally adapting to the texture size.
    samplingDirection = clamp(samplingDirection * minSamplingDirectionFactor, vec2(-u_maxSpan), vec2(u_maxSpan)) * u_texelStep;

	// Inner samples on the tab.
	vec3 rgbSampleNeg = texture(main_colour, coords + samplingDirection * (1.0/3.0 - 0.5)).rgb;
	vec3 rgbSamplePos = texture(main_colour, coords + samplingDirection * (2.0/3.0 - 0.5)).rgb;

	vec3 rgbTwoTab = (rgbSamplePos + rgbSampleNeg) * 0.5;

	// Outer samples on the tab.
	vec3 rgbSampleNegOuter = texture(main_colour, coords + samplingDirection * (0.0/3.0 - 0.5)).rgb;
	vec3 rgbSamplePosOuter = texture(main_colour, coords + samplingDirection * (3.0/3.0 - 0.5)).rgb;

	vec3 rgbFourTab = (rgbSamplePosOuter + rgbSampleNegOuter) * 0.25 + rgbTwoTab * 0.5;

	// Calculate luma for checking against the minimum and maximum value.
	float lumaFourTab = dot(rgbFourTab, toLuma);

	// Are outer samples of the tab beyond the edge ...
	if (lumaFourTab < lumaMin || lumaFourTab > lumaMax)
	{
		// ... yes, so use only two samples.
		_o_colour = vec4(rgbTwoTab, 1.0);
	}
	else
	{
		// ... no, so use four samples.
		_o_colour = vec4(rgbFourTab, 1.0);
	}

    //_o_colour.r = 1.0f;
}