+import _pbr_prefilter;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 vertex;
+void main()
+{
+ gl_Position = vertex;
+ out vec2 texcoord = vertex.xy*0.5+0.5;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec2 frag_out;
+void main()
+{
+ vec3 normal = vec3(0.0, 0.0, 1.0);
+ vec3 look_dir = vec3(sqrt(1.0-texcoord.y*texcoord.y), 0.0, -texcoord.y);
+ float roughness = texcoord.x;
+
+ float geom_k = roughness*roughness/2.0;
+ float geom_look = -look_dir.z/(geom_k-look_dir.z*(1.0-geom_k));
+
+ vec2 sum = vec2(0.0);
+ for(int i=0; i<n_samples; ++i)
+ {
+ vec3 halfway = ndist_ggxtr_importance_sample(hammersley(i, n_samples), roughness);
+ vec3 light_dir = reflect(look_dir, halfway);
+
+ if(light_dir.z>0)
+ {
+ float geom_light = light_dir.z/(geom_k+light_dir.z*(1.0-geom_k));
+ float geom = geom_look*geom_light;
+
+ // Look_dir points towards the surface, so the dot product is negated
+ float half_dot_look = dot(halfway, look_dir);
+ float ng = geom*half_dot_look/(halfway.z*look_dir.z);
+ float a = pow(max(1+half_dot_look, 0.0), 5.0);
+
+ sum += vec2(ng*(1-a), ng*a);
+ }
+ }
+
+ frag_out = sum/n_samples;
+}