Custom Fresnel curves in Maya

custom_fresnel_curves_maya

So, we all know about fresnel reflections, objects reflect more at grazing angles. A few years ago we would use the facing ratio and a ramp to achieve that effect, and then reverse the result in the diffuse to keep somehow a physical based workflow. With more recent shaders and render engines we can drive the reflection with the index of refraction (ior or n) which works great for dielectric materials (plastic, wood, etc) but for metals the index of refraction is a bit more complex and very few render engines have gone through the trouble of writing those more complex reflection formulas. The question is: does it make any difference at all? Can’t we just tweek it until “looks good”? Sure we can, after all it’s all about art, making it look good, and realism is not always pleasing. So don’t take this too serious, but in the end you might learn something.

Simple vs complex Index of refraction

Dielectric materials have a simple ior, you can just search online for the value, feed your shader and the resulting “reflection falloff curve” will behave like the real thing.

What if you search for cooper or gold material? If you feed your shader with that number won’t work at all, you have 2 options, increase the ior to an arbitrary number like 8 or 15, or play with the reflection options that your shader allows, in this post I will be using the aiStandard shader, which gives you the option to play with the reflection at 0 degrees.

simple vs complex ior

So you might have heard that metals have another variable called “k”, extinction coefficient (imaginary part of complex index of refraction), and this value is the key to create the real reflection falloff curves of metals. The “problem” is that arnold and many other render engines don’t have a k attribute, so what you can do is to use a few maya nodes to manually create the reflection curves to mimic the real thing and feed the reflection attribute with it.

Analysing reflection curves

Now let’s see what’s going on on those reflection curves to better understand the concept and make sure we are doing it correctly.

I have created a python script to generate a bunch of planes (91) so we can analyse the reflection curves, those planes are rotated from 0 to 90 degrees , and the last one is at 0 degrees since we can’t render a surface at 90º from the camera. We will render this scene from an orthographic camera with a not so common resolution like 1024px by 20px.

fresnel reflections maya scene

To analyse reflection we need a light, a consistent one and with no shadow casting, so we use a Skydome light with an 100% white color and no shadows. If you really want to get crazy you might want to change your AA filter, I found that for this, the “closest” filter is the best. Now you create a shader, get rid of any diffuse, and change the color and specular amount to 1/white, check fresnel and in the refraction attributes also check Fresnel use IOR. Let’s use a simple IOR first, a value of ~1.5 (plastic) for instance.

fresnel use ior arnold

After rendering the scene, we get a gradient from black to white (remember that the last square is fully white to pretend that it’s the 90º one).

maya render fresnel

Now we jump into nuke, create a crop to node to get rid of any extra render useless space, and a sampler node to analyse the pixels. After sample the colors we get a curve and we need to compare it against something, in this case an online reference refractiveindex.info/legacy.

In this website choose the polycarbonate (common plastic) and set the wavelength around 0.65(red light). We get a refractive index (n) of 1.57869. If you scroll down you also have an important value R = 0.05036, which is the reflection at 0º degrees, if you compare it to the first square of the render, that’s exactly the number you get, so we are doing good so far.

Let’s now check all the curve shape and compare it to the graph we see on the website. Keep in mind that the curve will have slight bumps/imperfections to it, that’s normal. To be precise you can download a jpeg out of it, I have gone through the trouble of overlaying the images and compare. So here is the result:

maya nuke fresnel

That’s very close, the shader is doing a great job of rendering a true reflection curve for the given ior. Too bad we can’t get the same behavior for metals, so let’s see what we can do about it.

N and K

Right, since our render engines don’t have a k attribute we need to use some maya nodes do draw the curve manually with the same shape as our reference (refractiveindex.info/legacy). But that’s not good enough, we can get a bit more complex and write a python script with the fresnel reflection formulas that we can get online so the script can draw the curves for us.

After a bit of experiment and copy from here and there, we have a function named IOR() which takes 2 arguments, n and k, that we feed with the info from our reference, and the function will output an array with the reflection values for all the angles (0 to 90).

ior formula

Now we can use those values to draw the reflection curve into a remapValue node, I won’t go into details about the script because that would be another entire post, I can do it for the next time if you guys are interested.

fresnel maya ui

As you see in the interface I have an n and k inputs and it creates the fresnel curve with the remapValue node selected. The fresnel formula also works for simple ior’s, leaving the k value at 0.

maya custom fresnel

The Shading network

We have the curve but we still need a way to calculate the facing angle of the object and for that we use the facingRatio attribute of the samplerInfo maya node. Also the facingRatio is 0/black at 90º and 1/white at 0º, so we need to reverse this because objects always reflect more at grazing angles. So connect the facingRatio to a reverse node, inputX for instance since it’s just a single value. And then we connect the outputX of the reverse node to our remapValue inputValue.

Finally we can connect to the outValue (not outColor) to the material. About the material, we dont need to calculate refletions now, we could feed this value to a simple shader like an aiUtility/surfaceShader and analyse the curves, it will work the same in the reflections. Make sure you connect the outValue to the r,g and b colors of the material.

maya shading network

Now let’s analyse the pixels in Nuke. For this example I used Aluminium values for a given wavelength (0.65 ~ red). At the first look it seems like everything is working great, the curve has the same shape, but if we overlay the images and compare, there’s a slight shift to the curves.

fresnel curve maya shift

Why is that? The shape is there, but the values are shifted somehow, what’s going on really? Is it our fresnel python formula not working? That’s not the case really, there’s another problem in between, more precisely in the beginning, the facingRatio.

FacingRatio “spike” curve

So if we take our test scene and analyse the “raw input” of the facingRatio we see that we don’t get a straight curve, or a linear curve (nothing to do with any linear workflow issue). Without going into detail about how the facingRatio is calculated (look at the maya docs for that), we can’t really remap the values with the fresnel curve linearly if the “raw input” of the facingRatio is not linear. So to solve this and without knowing maths like me, what I found is that if we create a “reflected” curve of the facingRatio curve (see the image below) we can make it linear and then remap the values with the formula. So again I did that, just after the facingRatio connect a remapValue node to reflect/invert the curve, I used a python script to do that, but then saved out a preset for future use.

facingratio maya reflected

The correct curves

Finally, after our update to the shading network, we can compare the results against the reference image and we see that the results are accurate.

correct fresnel reflections maya

Still remember the simple ior reflection curve? With the custom fresnel curves the result is even closer.

Metals

For metals you will need to create 3 curves (3 remapValue nodes), for red, green and blue light and then feed the material reflection color with it, using the same workflow, but this time you have 3 inputs, for example cooper reflects more red light than green or blue, that’s why it looks more “redish”. As reference use for red: 0.65, green: 0.51 and blue: 0.475 in the wavelength input at the refractiveindex website. Then we calculate the reflectivity for all based on the n and k values. You can always create a script to automate the process.

Conclusion

I don’t know how many of you are still reading until here, but hopefully you have learned something even if you don’t care much about this topic. In the end with so many things happening like bumps, scratches, roughness, grading, etc, you really need to care only about the look and don’t get crazy with physical accuracy. Anyways, it’s always good to know a bit more and give it a try. If you ask me if I will use this in my daily workflow, I guess not, what if autodesk/render engines provide us with a decent node/shaders to deal with metal reflections? That would be appreciated, at least we could try without going into crazy shading networks and scripts.

Please let me know about your own workflows and if there’s something that I am missing here or there that could simplify the approach. Thanks for reading.

Online Reference

Refractiveindex.info
Custom curves with animCurves
SamplerInfo facingRatio
Fresnel overview dielectrics vs metals
  • crltt

    This article is just awesome! I’ve always been interested in this argument and I’ve searched a long time for a method that could give me a falloff curve inside maya to deal with ior of metals. Thank you very much, and if you’ll find the time to explain in depth the script as you mentioned in the post before I would really appreciate. Thanks for everything, this blog is just gold!

    crltt

    • therenderblog

      Thanks for the input :)

      No problem, I am planning to do an update to the custom tools toolbar including this ior script. I just need to organize the script better and make it more easy to use, maybe with some presets and so.

      • crltt

        Wow, you’re a genius! thank you so much, I really look forward to read your next article, and thank you also for the custom toolbar.
        Just for give you my “easy-stupid-proven” solution, which was less accurate and precise. I was dealing with the absence of curves node with the ramp node, and If you take a look to the curve node in max, you can find the gradient at the back end. My method was going through the refractive index website, find the values, import them into max and adjust the curve. At that point I was able to preview a similar ramp in max which I will recreate with the ramp node in maya. Then attach it to the samplerinfo and the reverse node. This linear error of the sampler is a whole new world that you’ve opened for me, because I had never test, as you did, the curve with the resultant out from the sampler-reverse-ramp pipe. Hope this helps

        • therenderblog

          Thanks crltt :)

          I just found that “non-linear” thing from the facingRatio when comparing the true reflection of the material’s simple ior to my script. Then I tested the raw input of the facingRatio and saw that.

          Anyways, it was fun to find somehow a “solution” to do this in maya, the result is there, now it’s a matter of experimenting with it.

          • crltt

            I really look forward to experiment with it. In the meantime I’m experimenting with photoscan and hdri vs simple jpgs with multiple exposures, I will write my results on the correct post after I’ve finished with it! Thanks again

  • X Y

    Alright – this is all nice. I’ve seen this point brought up by others before… I just have only one problem with it:

    Since mental ray does not deal with real world light intensities etc, the gi is a joke etc. what is the point of being this scholastic with the fresnel of your materials? Has anyone tested this more extensively and really observed a definite difference in the believability of a material? That’s what I am primarily interested in.

    I mean, I kinda get it in hdri lit environments, might be a bit of a game changer, but even so I am relatively skeptical at this points, lacking of course the personal experience with this setup.

    Thanks,

    • therenderblog

      Thanks X Y.

      Just like I said in the article what matters in the end is “looking good”, not physical accurate. But when you mentioned mental ray, if you analyze the material reflection when using the IOR switch, that curve will match a “true” reflection, that you can also recreate for complex ior’s with the fresnel formula, something that Mr doesnt allow by default (k attribute).

      We can always try, but we might find that in the end we need to tweek everything and delete all the nodes :D

  • Pingback: Creating Your Own Custom Fresnel Curves in Maya | LESTERBANKS

  • Roman Lapaev

    This one is somewhat removes necessity for having curve like control of Fresnel like one in max? I haven’t had time to get to it but have you ever thought of making same curve control of 0 to 90 degree reflection like one in max?

    Can’t wait for you to share that script, you need to setup donate button so we can fund your research ;)

    • therenderblog

      Thanks Roman.

      It would be much better to have a curve control like 3ds max. That gradient thing is just an hack, and you have to find a way to interpolate the points, also there’s a 50 points limit, we just need to find the best way to interpolate them and use less points. I am not a c++ developer so this is the best I can do :)

      But hey, this is just an experiment, but it works , we could always use it as a starting point.

      I will put all of this in one simple script and share in a few days so you guys can play with it.

      • Roman Lapaev

        Do you really find this workflow excessive? I would clearly implement this in my dialy look dev, metals are the only thing usually the weakest point of sometimes spectacular looking renders.

        If i get it right your workflow with the toolbar script is:

        1) refreactiveindex website
        2) input numbers into one of those simple generators or the one that broken into rgb?
        3) plug into shader reflection
        4) rednder

        Not too excessive for my taste i would even use that on crazy fast demanding projects

        Can’t wait to try and compare using 5-12 iors vs your solution!

  • Adam Cheshire

    I appreciated the read – very interesting indeed

  • dagoose

    very nice! especially the facing ratio non linearity. I’m building my customs fresnels the same way not as sophisticated like you with python just manually by hand. So I can’t wait for your script to generate correct mat IORs and linearize the facing ratio.

    cheers!

  • Janosch

    Well explained! I used nearly exactly the same technique for analysing and rebuilding a measured car paint material. I think I compensated for the non linearity of the facing ratio with a sinus calculation in Nuke, since my curves where already there (sampler node). I obviously didn’t need to write those ior formulas, since I measured the measured material… Nice work!
    I came to my limit, when I tried to mathematically mimic the specular highlights / BRDF stuff… I ended up eyeballing it.
    Keep it up!

    • therenderblog

      Thanks Janosch. Do you still remember that “sinus calculation in nuke” ? :) I would like to try myself

      • Janosch

        Sure, I can have a look to it on monday at work.
        I think it was like so: Because the facingRatio is (according to the docs) the cosine function, you can linearize it with the sine (sorry, in german it’s called sinus). In Nuke you can select the curves values of the sampler node, rightclick, edit, move and type sine(x) into the x field. Before that, make sure your values go from 0 to 90.
        On monday, I will make sure how it was exactly.

        • therenderblog

          Thanks for that. I shouldn’t have missed math classes I guess :D

          • Janosch

            now at work.
            my values in the nuke sampler where between 0 and 1. And then the result should be in radiants but the sine spits out degrees, so the formula has to be x = sin(x*90*pi/180)

  • Justin

    Great explanation. I think you’re right, I won’t implement this into my workflow, but I’m much more informed. Thank your for sharing.

  • ScottishCpt

    Greetings!

    I was just wondering, can you by chance share the source code for the IOR function? I’m trying to port this to another CG application (Cinema 4D)- I’ve found a few equations that seem to do something online, but none of them are giving me results similar to yours.

    Great article BTW.

    • therenderblog

      Sure, I sent you by email. I will do a new post about it anytime soon.

      • Shane Simms

        Hi there,

        Could I possibly grab the source code off of you as well? I’ve just been doing some reading into this topic and after stumbling across this post would love to have a play with it.

  • http://jdbeals.com/ thebeals

    I have been trying to create this myself for the longest time and have always fallen short! Really incredible job here. Along with everyone else here, I would love to be able to play with the script/the updated UI as well as get another post on the script :) when you get the chance. Really exciting stuff.

    • therenderblog

      Thanks!

      I have taken this further making all the maths inside the python script, so we just need to use 1 samplerInfo and 1 remapValue node (that the script will also create)

      As soon as I have some time I need to find the best way to interpolate the values to use less points as possible. After that I will share the script and make a post about it. Cheers

  • James Williams

    Great information. I would like to use this with vray any chance you wouldn’t mind sharing the python script so I might take a crack at implementing it?

    • therenderblog

      I am working on the next post, making the script more user friendly and it should work for any render. What I have right now has a lot of “moving parts”. In the next post I will share with everyone. Stay tuned :)

  • Pingback: Custom Fresnel curves in Maya – Part 2 | The Render Blog

  • Ron Besseling

    i really love this script… after seeing the tutorial of grant warwick in 3ds max. i have been searching and trying to figure out a way to make complex fresnel for materials in maya… i have no experience with any scripting, but i am wondering how hard it will be to make the Custom Fresnel Curves Script (with presets) work with Vray in maya.. or is it already working??? “still need to install maya 2014 because i don`t get it working in 2013, but i will tomorrow for sure ;)

    • therenderblog

      Hey Ron.

      You can just create the 3 curves manually with the first 2 input boxes of the script UI, and make the explained connections manually. If you have arnold installed you can also create with arnold material, delete it and connect to a vrayMtl or mia mat.

      Let me know if you need help.

  • Adam Cheshire

    Hi – I was looking at the reference you put with your article

    http://bct.me/tutorials/mini-cooper/

    In this he describes using the graph editor to create his curves in the paint shader update section.

    I tried this method as I think the graph editor would be much easier to manipulate then the gizmo you have used the UI (as you would be able to adjust multiple points at a time rather than one by one), however I cannot for the life of me get it to work – have you looked at it/been able to figure it out?

    This is a brilliant article btw – follows closely in line with Grants tutorial

    • therenderblog

      I think that old approach doesnt work with arnold render.

      • Adam Cheshire

        Thats a real shame – I much prefer the graph style found in max, frustrating!

  • Adam Cheshire

    Has anyone managed to control the curve via the anim curve as explained in the ‘custom curves with animcurves’ article you put in the online reference section?