Implementing the example of Walter et al. (2007) paper As the title suggests I'm trying to implement the last images of the &quot;Microfacet Models for Refraction through Rough Surfaces&quot; Paper by Walter et al. in OpenGL
I &quot;think&quot; (I had to put that into quotation marks) I know how the microfacet model should work and hopefully am only stuck on practical execution.
So I started by implementing the GGX formulas for the Normal Distribution, Fresnel and Geometry Function.
Initially and still I'm not so sure how to get the color of the object behind the glass into the formulas. My first thought was to create a cubemap around the slate of glass and then use the outgoing direction vectors (o_t and o_r) to sample the cubemap. But then I'm still not so sure how to incorporate that into the larger picture. Going by my first thought again I just multiplied the result of the BTFD with the sample of the o_t vector but apparently the BTDF was really big so the whole slate turned white (possible bug?). After dividing the result a few times some washed-up version of what was supposed to show up appeared.
Also I think I read somewhere that the reflection and transmission should be handled seperatly depending on the result of the Fresnel formula.
Or should it be handled at the same time (possibly somethink like : BRDF * sample_of_reflection + BTDF * sample_of_refraction)?
And another thing I found curious is the given equation for sampling:
$\theta = arctan(a * sqrt(rand1) / sqrt(1 - rand1))$
$\phi = 2 * \pi * rand2$
After some playing around with this function I noticed that is basically something akin to a gaussian distribution pointing towards the positive z-axis. But shouldn't the distribution give samples which are distributed around the surface normal?
I'm wondering if I have to add an additional pair of quotation marks to my earlier statement...
So anyway here is the pseudocode for my implementation until now:
for(#samplecount)
{
 //get a sample m
 vec3 m = drawsample();
 
 //calculate normal and incoming vector
 vec3 i = normalize(viewPosition - fragmentPosition);
 vec3 n = normalize(Normal); 
 
 // calculate outgoing vector
 vec3 o_r = calculate_like_paper();
 vec3 o_t = calculate_like_paper();

 //sample cubemap
 vec3 reflection = sampleCubemap();
 vec3 refraction = sampleCubemap(); 

 //calculate halfvectors
 vec3 h_r = calculate_like_paper();
 vec3 h_t = calculate_like_paper();

 //calculate NDF, Fresnel and Geometry
 float D = GGX_D(h_r);
 float G = GGX_G(i, o_r, h_r);
 float F = GGX_F(i, h_r);

 //calculate BSDF, BRDF &amp; BTDF
 float BRDF = F * G * D / (4.0 * abs(dot(i, n)) * abs(dot(o_r, n)));
 float BTDF = longFormula();

 float BSDF = BRDF + BTDF
 
 vec3 result += BRDF * reflection + BTDF * refraction //?
}
result /= #samplecount;

Thank you if you take your time to answer and I'm relatively new to StackExchange so I could definitely do with some feedback to improve the way I ask questions.
Edit:
So if anyone found this question and has similar questions Epic Games has some nice notes on this topic:    https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
Initially and still I'm not so sure how to get the color of the object behind the glass into the formulas.


Normal, this was written with path / ray tracers in mind where that part is easy. Your idea of a cube map might be ok for some use cases (eg. reasonably rough surface for the distance to the surrounding objects). It is not a general solution however. That would likely require GPU ray tracing.


  Going by my first thought again I just multiplied the result of the BTFD with the sample of the o_t vector but apparently the BTDF was really big so the whole slate turned white (possible bug?).


I'm writing this from memory but I think you need to divide by the PDF. Which means that your weights will be close to 1. But not quite 1 as the sampling distributions don't include the shadowing terms.


  Also I think I read somewhere that the reflection and transmission should be handled seperatly depending on the result of the Fresnel formula. Or should it be handled at the same time (possibly somethink like : BRDF * sample_of_reflection + BTDF * sample_of_refraction)?


A classic path tracer would randomly pick either reflection or refraction based on the fresnel coefficient. That does efficient sampling. But if you can easily get both from a cube map, you can also blend them with the fresnel coefficient.


  After some playing around with this function I noticed that is basically something akin to a gaussian distribution pointing towards the positive z-axis. But shouldn't the distribution give samples which are distributed around the surface normal?


Yes, you need to transform the generated direction. It is mentionned in section 5.2, after equation (24), that $\theta_m$ is the angle between $m$ (microfacet normal) and $n$ (surface normal). They don't go into great detail as this way of defining microfacet models goes back to much older articles.

The short version is that you build an orthonormal basis using the surface normal as z and two other perpendicular vectors as x and y. Here it does not matter which as the distribution is isotropic, as long as they are perpendicular to each other and to the normal. Then you transform using that basis.