I am using Schlick approximation to calculate the value of the Fresnel effect I found here

When I try to find corner cases for the formula I get the value of 1 when the angle between normal and viewing direction is 90° and 0,02 for 0° (I am using IOR 1 and 1.33). This means that when looking, for example, at a sphere its edges will reflect almost all of the light and its center will reflect just 2% of light.

But he doesn't make sense for me when I try to use it in the microfacet model for BRDF. enter image description here

This means that the reflectance when looking directly from above on the surface will be just 2% which is unrealistically low. 98% of the energy would be absorbed by the surface. So just after 3 bounces, the ray would transmit less than 0,0008% of the light. This would darken an image and I would have to increase its emitted light by a great amount.

Am I thinking in a bad way about it?

My second idea what that it means how much light is directly reflected as a perfect reflection without being scattered my microfacet to other directions. The rest is used for diffuse/glossy reflection. But I cannot find any evidence for it anywhere.

Or I don't simply have to use Fresnel when I am dealing with non-transparent materials.


This is my code for now.

//Position of intersection is world space
float3 hitpoint = ray.origin + ray.direction * ray.distance;

//Direction towards camera
float3 wo = -ray.direction;

//Geometry normal
float3 N = ray.worldNormal;

//Microfacet normal
float3 H = SampleMicrofacetNormal(roughness, &N, &ray);

//New direction of ray
float3 wi;      

// Add light emitted from surface
ray.color += ray.mask * emission;

float F = Fresnel(&H, &wi);

float r1 = new_random(&ray.seed1);

if (r1 <= F) {

    //Reflected direction
    float3 wi = reflect(&H, &wo);    

    float D = D_ggx(roughness, &N, &H);
    float G = G_CookTorrance(roughness, &N, &H, &wo, &wi);

    float weight = fabs(dot(wo, H)) / fabs(dot(N, wo) * dot(N, H));

    //Not using F because it is already taken into a count by 
    //the probability of this IF/ELSE statement
    float reflectance = G * weight;

    ray.mask *= reflectance;

    //Check - new direction cannot point towards surface
    if (dot(wi, N) < 0) ray.mask = (float3)(0.0, 0.0, 0.0);
else {
    //Ray change color because light to through the material
    ray.mask *= color;

    //New random direction of diffuse ray
    wi = SampleDiffuseCosineWeighted(&N, &ray);

    //Importance sampling weight    
    ray.mask *= dot(wi, N);

//Set new direction and position for next tracing
ray.direction = wi;
ray.origin = hitpoint + N * EPSILON;
  • $\begingroup$ 2% reflected energy can still be significant when using HDR. $\endgroup$ – PaulHK Apr 22 '20 at 5:40
  • 1
    $\begingroup$ Just to open pauls comment. Think of the sky, its really, really bright. Even a little energy of that is still bright. Remember we dont clamp light to 0-1 range. $\endgroup$ – joojaa Apr 22 '20 at 7:07
  • $\begingroup$ What do you mean by clamping light to the range? I have an indoor scene similar to this for reference. Does it mean I have to make my lightbulb really really bright? raytracey.blogspot.com/2015/10/… $\endgroup$ – Vít Gardoň Apr 22 '20 at 7:29
  • $\begingroup$ The 2% is only at normal angle. That is the lowest reflection you get. As the reflection angle goes away from the normal this percentage increases rapidly $\endgroup$ – ali May 4 '20 at 4:42

If you just implement Fresnel alone you'll see that what you think in your original question is mainly correct for dieletric materials.

enter image description here

However don't calculate Fresnel ahead and then stochastically decide if evaluate your specular component or your diffuse one. Being part of the BRDF you have to accumulate the Fresnel term while evaluating the BRDF and only then eventually do 1-Facc for the diffuse part. If you are in a pure stochastic pathtracer then you do that directly while evaluating your microfacet. This is called 'rough Fresnel' and it's the model all modern render engines use.

For better Fresnel get the full Fresnel formula (complex Fresnel for metals). For friendlier Fresnel you can implement the 'Fresnel by colors' (can't remember the exact name rightnow I'll add it later), so instead to input numbers you input colors for F0 and F1. This is the way latest Renderman does it. Eventually add a 'metalness' parameter to switch between Fresnel and ComplexFresnel for metals.

For example some code (BRDF sample fnc) to inspect:

enter image description here

  • 1
    $\begingroup$ @VítGardoň your eval fnc for example will get back with the accumulated Fresnel computed during the BRDF (the one in FDG/.. divided by the number of samples.. that's the 'rough Fresnel' or 'glossy Fresnel'... for example in vray they did it wrong for years and onyl recently made it correct.. take a look at the last image in this link.. chaosgroup.com/blog/understanding-glossy-fresnel $\endgroup$ – Max Tarpini Apr 23 '20 at 21:44
  • 1
    $\begingroup$ @VítGardoň exactly that ! You use the normal from the micro facets which is every time different and not always the same as your macro surface normal. $\endgroup$ – Max Tarpini Apr 23 '20 at 21:48
  • 1
    $\begingroup$ @VítGardoň And for pure pathtracing it's there that you go stochastic and pick your lobe... so you don't need to accumulate. $\endgroup$ – Max Tarpini Apr 23 '20 at 21:49
  • 1
    $\begingroup$ @VítGardoň added some code to the answer so you can inspect it a bit. Sry to late here to type it .. $\endgroup$ – Max Tarpini Apr 23 '20 at 22:10
  • 1
    $\begingroup$ @VítGardoň the code is just about Fresnel. I don't split there because I'm accumulating Fresnel. For splitting.. take a look at Mitsuba code for example (around line 318.. github.com/mitsuba-renderer/mitsuba/blob/master/src/bsdfs/… $\endgroup$ – Max Tarpini Apr 24 '20 at 17:01

I will answer based on my experience with Fresnel models. Due to Kirchhoff's law of thermal radiation, in an opaque material the emissivity plus reflectivity plus absorptivity equals to one for every direction in thermal equilibrium. If the BRDF model you are using is physically-based, it should preserve energy conservation. That means that for a given viewing angle, the integral of the equation for the entire hemisphere should be equal to 1. It may be possible the reflectivity value near the normal is low, but that means that most of its contribution is elsewhere. For example, for a near-normal viewing direction, you can have a really low specular reflectivity but a much higher diffuse component. That may be the case of your model.

  • $\begingroup$ Thanks for your answer but I still didn't get a few points. You are speaking about "diffuse component" but I used microfacet BRDF which have only one component "specular". It selects a microfacet normal and does a perfect reflection. Microfacet normals are distributed based on roughness. The calculation is based on 3 parts (F, G, D). F is for Fresnel effect (higher the angle between microfacet normal the more reflection), G stands for geometric shadowing (higher the roughness or angle mean a higher chance of light being blocked by another microfacet) and D is just distribution of normals. $\endgroup$ – Vít Gardoň Apr 22 '20 at 21:54
  • $\begingroup$ So there is no diffuse component because it is replaced by the distribution of microfacet normals. Do you mean that G should negate the effect of Fresnel? $\endgroup$ – Vít Gardoň Apr 22 '20 at 21:57
  • $\begingroup$ Ohh, wait a minute. So Fresnel says how much light gets reflected directly and rest of it ( 1 - Fresnel) go through the material and because of my materials aren't transparent then it exits (for simpler model) at the same point in a random direction (diffuse)? $\endgroup$ – Vít Gardoň Apr 22 '20 at 22:46
  • 1
    $\begingroup$ I don't know the answer exactly because I haven't worked with microfacet models. But your last comment is not correct. Fresnel will tell you how much light is reflected specularly, and the rest of it (1-fresnel) is absorbed by the surface (if it is an opaque material). $\endgroup$ – jpaguerre Apr 22 '20 at 23:56
  • $\begingroup$ I found what is the problem of my. Now I am writing the answer. Thanks a lot. $\endgroup$ – Vít Gardoň Apr 23 '20 at 0:37

BIG UPDATE and explanation of BRDF model

While I was cleaning my browser and closing about 100 tabs I found this awesome website (it was there 3 days so I could already found an answer...) which finally made everything clear for me.

The problem wasn't in Fresnel at all. In fact, it doesn't matter what IOR you are using for the most time. Fresnel says how much light is reflected as a part of specular brdf. Here important is the word "specular". It means that light is reflected right when it hit the surface and it does not go through. The rest of it light that isn't refected do one of these things: is absorbed or is refracted (like in glass) or is scattered around and return to the surface as diffuse light. And the diffuse component is missing in my path tracer. I thought that specular BRDF takes a diffuse light into the count but it doesn't.

So here I will sum up how to use microfacet specular BRDF and diffuse BRDF for recursive path tracer, where I can hold only 1 ray at a time for a pixel.

  1. Intersection with geometry
  2. Calculate Fresnel
  3. Generate random number in range 0 to 1
  4. If the number is smaller or equal to Fresnel then use specular BRDF to calculate the new direction based on the distribution function of microfacet normals and evaluate.
  5. If the number is bigger than Fresnel then use simple cosine-weighted diffuse BRDF or do refraction it is up to you.

It is important to use both components of BRDF. Unfortunately, when you search for microfacet BRDF they usually expect you to know that it is just for the specular part.

I hope this help some beginners because it was a big struggle for me.

Original answer - some part of it is wrong. For explanation look at update above.

Ok, after some searching I have probably found a reason why it is totally ok to use Fresnel in the microfacet model.

My problem was low reflectance when looking from 0° grazing angle and as I said I used IOR 1 for the air and 1.33 for the objects. This was a big mistake.

When you create a graph of Schlick approximation for IOR = 1.33 your lower limit is 0.02. But this is only true for materials with IOR of 1.33 such as glass. When I look at this page that shows IOR of different material and you find for a section for a 3D artist you can see that IOR for metal is 3.17. Plugging this into the equation your lower limit becomes 0.27. That's 10 times more!!!

Even more fascinating is a fact that when you scroll down you can find "Reflection calculate". This outputs a function of reflectance (use non-polarized light) which I need. It is quite strange that Schlick approximation results in almost exactly the same function as on the website for glass, but when I use IOR = 3.17 from iron it is waaayyy off. The smallest reflectance should be 0.7688 by the website.

This means that the only thing I have to do is to find a more accurate function for F component (stop using Schick approximation) and use real IOR of materials. Simply said, "walls are not from water, most of the time" :D

Please tell me if I am wrong here... again.


I found this page. It explains everything you need to know about the Fresnel effect. Most importantly it cares about both dielectrics and metals.

Here is a simplified version:

Use Schlick approximation every time, but instead of calculation F0 = [(n1-n2)/(n1+n2)]^2 use your own value. If you want accurate reflection then look on the website and for F0 choose reflectance at 0°. It is a sort of a baseline. This isn't much important for dielectric (IOR up to 1.5), where base form Schlick approximation works so be free to use the equation above.

Be careful about metallic materials. Fresnel effect depends on the wavelength of light so there will be different values of R, G a B.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.