/
ssao.frag.glsl
112 lines (71 loc) · 3.16 KB
/
ssao.frag.glsl
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
106
107
108
109
110
111
112
#version 410 core
#define KERNEL_SIZE 32
// This constant removes artifacts caused by neighbour fragments with minimal depth difference.
#define CAP_MIN_DISTANCE 0.0001
// This constant avoids the influence of fragments, which are too far away.
#define CAP_MAX_DISTANCE 0.005
uniform sampler2D u_texture;
uniform sampler2D u_normalTexture;
uniform sampler2D u_depthTexture;
uniform vec3 u_kernel[KERNEL_SIZE];
uniform sampler2D u_rotationNoiseTexture;
uniform vec2 u_rotationNoiseScale;
uniform mat4 u_inverseProjectionMatrix;
uniform mat4 u_projectionMatrix;
uniform float u_radius;
in vec2 v_texCoord;
out vec4 fragColor;
vec4 getViewPos(vec2 texCoord)
{
// Calculate out of the fragment in screen space the view space position.
float x = texCoord.s * 2.0 - 1.0;
float y = texCoord.t * 2.0 - 1.0;
// Assume we have a normal depth range between 0.0 and 1.0
float z = texture(u_depthTexture, texCoord).r * 2.0 - 1.0;
vec4 posProj = vec4(x, y, z, 1.0);
vec4 posView = u_inverseProjectionMatrix * posProj;
posView /= posView.w;
return posView;
}
void main(void)
{
// Calculate out of the current fragment in screen space the view space position.
vec4 posView = getViewPos(v_texCoord);
// Normal gathering.
vec3 normalView = normalize(texture(u_normalTexture, v_texCoord).xyz * 2.0 - 1.0);
// Calculate the rotation matrix for the kernel.
vec3 randomVector = normalize(texture(u_rotationNoiseTexture, v_texCoord * u_rotationNoiseScale).xyz * 2.0 - 1.0);
// Using Gram-Schmidt process to get an orthogonal vector to the normal vector.
// The resulting tangent is on the same plane as the random and normal vector.
// see http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
// Note: No division by <u,u> needed, as this is for normal vectors 1.
vec3 tangentView = normalize(randomVector - dot(randomVector, normalView) * normalView);
vec3 bitangentView = cross(normalView, tangentView);
// Final matrix to reorient the kernel depending on the normal and the random vector.
mat3 kernelMatrix = mat3(tangentView, bitangentView, normalView);
// Go through the kernel samples and create occlusion factor.
float occlusion = 0.0;
for (int i = 0; i < KERNEL_SIZE; i++)
{
// Reorient sample vector in view space ...
vec3 sampleVectorView = kernelMatrix * u_kernel[i];
// ... and calculate sample point.
vec4 samplePointView = posView + u_radius * vec4(sampleVectorView, 0.0);
// Project point and calculate NDC.
vec4 samplePointNDC = u_projectionMatrix * samplePointView;
samplePointNDC /= samplePointNDC.w;
// Create texture coordinate out of it.
vec2 samplePointTexCoord = samplePointNDC.xy * 0.5 + 0.5;
// Get sample out of depth texture
float zSceneNDC = texture(u_depthTexture, samplePointTexCoord).r * 2.0 - 1.0;
float delta = samplePointNDC.z - zSceneNDC;
// If scene fragment is before (smaller in z) sample point, increase occlusion.
if (delta > CAP_MIN_DISTANCE && delta < CAP_MAX_DISTANCE)
{
occlusion += 1.0;
}
}
// No occlusion gets white, full occlusion gets black.
occlusion = 1.0 - occlusion / (float(KERNEL_SIZE) - 1.0);
fragColor = vec4(occlusion, occlusion, occlusion, 1.0);
}