What is the best PBR Real Time Fresnel function

Started by
5 comments, last by Hodgman 7 years, 8 months ago

So I'm working on my physically based renderer, and I've come to a sort of crossroads regarding the Fresnel factor. I'm having trouble finding the best way to represent it. I know that Schlick's fresnel approximation is based off IOR, but IORs can go up to 38.6 for a meta-material, and 4.05 for an actually natural element, Germanium (Source: https://www.quora.com/Which-medium-has-the-highest-refractive-index), which will make representing these in a 0-1 image difficult, as well as confusing. I also noticed no one really uses IOR maps.

I also read this paper on Unreal's PBR integration (https://de45xmedrsdbp.cloudfront.net/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf ), and I discovered that they initially wanted to use a F0 of 0.4 for non-metals. What would be the F0 for metals in this case, and isn a static value, 0.4, worth the limitations for that TINY bit of memory? I believe the F0 tends to the Base Color as it becomes more metallic, but I'd like confirmation.

And finally, there's reflectivity or specular, as is used in modern PBR equations. Is there a standard for this in regard to getting an F0, because it seems arbitrary (is it a float value up to that directly maps to F0?

Ultimately, I'm asking for a comparison between methods, please!

And I know this is sort of unrelated, so I'm not going to officially ask for it, but are there any real reasons NOT to combine specular color and base color, as Unreal has done? I can't think of a single real reason, even for more stylized stuff.

Thank you, guys!

(NOTE: This is a cross-post from here, so I can get a variety of opinions: http://gamedev.stackexchange.com/questions/129320/what-is-the-best-pbr-real-time-fresnel-function )

Advertisement

F0 = ( (1 - IOR) / 1 + IOR )²

You can also convert from F0 to IOR by moving the terms in the equation.

I also noticed no one really uses IOR maps.

Because IORs have no upper bounds (it can go up to infinity) which makes them really hard to represent them reliably in just 8 bits. Also converting from IOR to F0 in the pixel shader is more expensive (it even has a division!), unnecessarily. Note that an IOR = 9999 maps to F0 = 0.996004 while IOR = 99 maps to F0 =0.9604

F0 goes only from 0 to 1; which fits nicely with GPU textures.

And I know this is sort of unrelated, so I'm not going to officially ask for it, but are there any real reasons NOT to combine specular color and base color, as Unreal has done? I can't think of a single real reason, even for more stylized stuff.

Because it's not the same. It looks different and the plethora of BRDFs you can represent diminishes. However, artists find it very intuitive and makes them more productive.

Schlick's fresnel approximation is based off IOR

The version we use in graphics is based on F0.

And I know this is sort of unrelated, so I'm not going to officially ask for it, but are there any real reasons NOT to combine specular color and base color, as Unreal has done? I can't think of a single real reason, even for more stylized stuff.

There's two different (popular) content creation workflows - often called "spec/gloss" and "metal/rough".

The "metalness" workflow is much simpler, as you just have base colour (RGB), metalness (grey) and roughness (grey), but unfortunately this compact representation does not interpolate perfectly:
metalnessedgeartifacts01.jpg

http://www.marmoset.co/toolbag/learn/pbr-practice
http://www.marmoset.co/toolbag/learn/pbr-conversion

and I discovered that they initially wanted to use a F0 of 0.4 for non-metals. What would be the F0 for metals in this case

They use 0.04, which is an IOR of 1.5, which is about right for glass. Water is IOR=1.33 / F0~=0.02, and Sapphire is IOR=1.76 / F0 ~=0.08... So F0 of 0.04 is within the ballpark for most non-metals.
For metals, the F0 is much, much brighter (using the "base colour" in the metalness workflow).

e.g. Silver is IOR=0.18, which using the above formula gives F0~=0.48. However, the above formula for converting between F0/IOR is an approximation of the real physics, which only works well for non-metals... In reality, Silver has an F0 value of more like 0.95 IIRC! When doing the conversion for metals, you also need to know it's IOR as a complex number, where the real part is used as normal, and the complex part becomes an extinction coefficient.
I think the formula for metals is: F0=((n-1)^2 + k^2)/((n+1)^2+k^2), where n is the real part of the IOR and k is the imaginary part, so if we said that Silver had an IOR of 0.18+8.4i, then it's F0 would be 0.99

Note though that the IOR value for a material depends on the wavelength of light that you're using to measure it. For non-metals, this wavelength-dependent graph tends to be pretty flat, so a greyscale IOR/F0 value is fine... but for metals, the graph tends to be sloped through the visibile spectrum, so the IOR/F0 value for Red, Green, and Blue wavelengths will be different, which is why you need an RGB F0 map.

Because it's not the same. It looks different and the plethora of BRDFs you can represent diminishes. However, artists find it very intuitive and makes them more productive.

Matias, are those materials not 0/1 metalness? Is that why they require seperate colors for base and specular? Thanks!

There's two different content creation workflows - often called "spec/gloss" and "metal/rough".

Hey Hodgman, I'm well aware of the two seperate workflows. My question was about how many workflows have Base Color, Specular Color, Metalness, and Roughness. (ie: Unreal). In other papers, I see only Base, Metal, and Roughness, no specular. I see the Base is combined with the specular map, so it acts as a specular for metals and as a diffuse for nonmetals. The issue is, for nonmetals, where would the F0 then come from, if the Base Color goes to Diffuse.

I hadn't, though, known about interpolation issues. is there a good way to overcome it?

Also, do polarizing cameras only capture the diffuse of nonmetals? How would you capture textures for metals, if that's the case? As far as I know (I create my textures by hand, not camera), polarizing cameras remove specular hilights, and if a metal is all diffuse, would it actually capture? Would this be an issue at all?

Thanks again to both of you!

EDIT: Oh, by the way, is there a free source for PBR models? Everything I find uses Gloss+Specular. Thanks!

Hey Hodgman, I'm well aware of the two seperate workflows. My question was about how many workflows have Base Color, Specular Color, Metalness, and Roughness. (ie: Unreal). In other papers, I see only Base, Metal, and Roughness, no specular. I see the Base is combined with the specular map, so it acts as a specular for metals and as a diffuse for nonmetals. The issue is, for nonmetals, where would the F0 then come from, if the Base Color goes to Diffuse.
EDIT: Oh, by the way, is there a free source for PBR models? Everything I find uses Gloss+Specular. Thanks!

Both spec/gloss and metal/rough can be PBR workflows (or not).

In the "specular workflow", you have:
* RGB Diffuse Colour
* RGB Specular Colour
* Glossiness (pretty much: roughness)
In the "metalness workflow", you have:
* RGB Colour
* Metalness
* Roughness (pretty much: glossiness)

You can think of this last one as being a compression algorithm for the first one.
Before doing any shading, you "decompress" your metalness data back into specular data:
diffuse = lerp( base, 0.0, metalness );
specular = lerp( 0.04, base, metalness );


i.e. for non-metals, the F0 is hard-coded to 0.04 when using the metalness workflow, and the diffuse and specular RGB maps are both generated by decoding the base-colour and metalness maps. Likewise, the diffuse colour of metals is hard-coded to 0.0.

Just to reiterate: metalness is not a property of the BRDF at all. It's a property of this texture packing scheme.

Also, do polarizing cameras only capture the diffuse of nonmetals? How would you capture textures for metals, if that's the case? As far as I know (I create my textures by hand, not camera), polarizing cameras remove specular hilights, and if a metal is all diffuse, would it actually capture? Would this be an issue at all?

Polarizing filters don't remove specular - they can be used in certain situations to remove some of the specular highlights...

* set yourself up a perfectly black room with perfectly black walls
* put an object on the floor to photograph
* put a single spot-light in there with a polarizing filter over it that only lets through vertically polarized light
* put a camera in there with a polarizing filter over it that only lets through vertically polarized light
* take a photo
** diffuse reflections will "unpolarize" the light, turning vertically polarized light into any other kind of polarization with random chance, so your camera will capture approximately half of the diffuse reflections.
** specular reflections will not change the polarization of the light, so you will get (hopefully) all of the specular reflection.
* now rotate the filter on your camera 90º so that it only lets through horizontally polarized light
* take a photo
** you will still capture half the diffuse lighting, as it's randomly polarized
** hopefully you will capture almost none of the specular reflection
* subtract photo #2 from photo #1 and you'll have a picture of just the specular lighting ((~50% diffuse + ~100% specular) - (~50% diffuse + ~0% specular) = ~0% diffuse + ~100% specular).

In practice your room won't be perfectly black, your filters won't be perfect, your alignment won't be perfect, and the idea of "diffuse" and "specular" reflections won't perfectly match the real world, so your photos won't give you this perfect separation either.

I hadn't, though, known about interpolation issues. is there a good way to overcome it?

It's usually not even noticeable. If you're making a lot of assets with texture transitions from dark metal to light plastic, then maybe the metalness workflow isn't the best fit -- use RGB diffuse + RGB specular maps instead of RGB base + metalness maps.

Thanks again Hodgman. For some reason I kept thinking of gloss as specular power. Don't ask why, I've used gloss maps before haha. But one last question, Matias was advocating both Diffuse and Specular in the metalness workflow. Is there any place for this or is it just a waste of gbuffer space? It seems like it's purely convention.
For some reason I kept thinking of gloss as specular power

Gloss / Roughness is equivalent to specular power :D

Matias was advocating both Diffuse and Specular in the metalness workflow. Is there any place for this or is it just a waste of gbuffer space? It seems like it's purely convention.

It's almost universal at the moment to use an RGB F0 parameter to control the colour of the specular highlights, and to have no other multiplier. In the metalness workflow, that's your "base colour" map / the hardcoded 0.04, and in the "specular workflow" it's your specular map.

If you follow Matias' link, and then the link to that research paper, they use a model that has a monochromatic F0 (even for metals, which is wrong!) but then also have an RGB multiplier that gets applied to the entire specular result. This extra multiplier is extremely uncommon in "PBR" game renderers at the moment -- except maybe as a "cavity" or "specular occlusion" multiplier... but as the research shows, they're managing to better match real-world material measurements by having this extra parameter.

So, should be have an extra RGB specular multiplier on top of everything else: Yes.

Are PBR games currently using an extra RGB specular multiplier in order to better match the real world: Not really, no. :(

Also note that these researchers are not using artists to create material values -- they're using an error-minimization algorithm to try and automatically choose their material values in order to match scientific measurements of real materials.

If you give their material model to an artist, they'll likely fuck it up with impossible colour values :lol:

This topic is closed to new replies.

Advertisement