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
|
#version 330 core
in vert_t {
vec3 position;
} vert;
out vec4 frag_color;
uniform samplerCube cubemap;
uniform float roughness;
const float PI = 3.14159265359;
float distribution_ggx(vec3 n, vec3 h, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float ndoth = max(dot(n, h), 0.0);
float ndoth2 = ndoth * ndoth;
float nom = a2;
float denom = (ndoth2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
float radical_inverse_vdc(uint bits)
{
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 hammersley(uint i, uint n)
{
return vec2(float(i) / float(n), radical_inverse_vdc(i));
}
vec3 importance_sample_ggx(vec2 xi, vec3 n, float roughness)
{
float a = roughness * roughness;
float phi = 2.0 * PI * xi.x;
float cos_theta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y));
float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
vec3 h;
h.x = cos(phi) * sin_theta;
h.y = sin(phi) * sin_theta;
h.z = cos_theta;
vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, n));
vec3 bitangent = cross(n, tangent);
vec3 samplevec = tangent * h.x + bitangent * h.y + n * h.z;
return normalize(samplevec);
}
void main(void)
{
vec3 n = normalize(vert.position);
vec3 r = n;
vec3 v = r;
uint count = 1024u;
float total = 0.0;
vec3 prefiltered = vec3(0.0);
for (uint i = 0u; i < count; i++) {
vec2 xi = hammersley(i, count);
vec3 h = importance_sample_ggx(xi, n, roughness);
vec3 l = normalize(2.0 * dot(v, h) * h - v);
float ndotl = max(dot(n, l), 0.0);
if (ndotl > 0.0) {
float d = distribution_ggx(n, h, roughness);
float ndoth = max(dot(n, h), 0.0);
float hdotv = max(dot(h, v), 0.0);
float pdf = d * ndoth / (4.0 * hdotv) + 0.0001;
float resolution = 512.0;
float sa_texel = 4.0 * PI / (6.0 * resolution * resolution);
float sa_sample = 1.0 / (float(count) * pdf + 0.0001);
float mip_level = roughness == 0.0 ? 0.0 : 0.5 * log2(sa_sample / sa_texel);
prefiltered += textureLod(cubemap, l, mip_level).rgb * ndotl;
total += ndotl;
}
}
prefiltered /= total;
frag_color = vec4(prefiltered, 1.0);
}
|