where to start Physical based shading ?

Started by
41 comments, last by Alundra 10 years, 1 month ago


Wikipedia and every physical based rendering source material contradict what you are saying. http://en.wikipedia.org/wiki/Gloss_(optics)#Surface_roughness

Read this two: http://en.wikipedia.org/wiki/Specular

These two wiki pages refer to real world conditions, not the techniques use by real time rendering.

Specualar maps, Gloss maps and Specualar color maps, are nothing but tricks to fool the viewer.

If you would like to make shaders that can cast real specular reflections and gloss optics you will need to use ray tracing.

Even though ray tracing is now entering a era where it can be used in games it will still take time before we can bounce the huge amount of rays needed, over a surface and back at the viewer that is needed for gloss, although I am proud to say that specular is now possible even if it isn't practical.

This better explains real time specular, even if it is a bit dated: http://en.wikipedia.org/wiki/Specular_highlight

Here is a guide for materials from the artists view point: https://www.marmoset.co/toolbag/learn/materials (Good read)

I have worked for five years as a cg artist, by rule of thumb the maps are:

Specular map. intensity

Gloss map. Size (yes it should be roughness but it really only scales the specular size of the spot over the normals)

Specular color map. Color

But these names changes from software to software, so it helps to know what each does.

If any one would like to see how these maps work, you can just download a 3d modeling app and test them your self or you could just search for "How do specular and gloss maps work."

Advertisement

Scouting ninja - in your first post you've said that "gloss" can be used as a name for two of the maps (intensity and size) -- this is why using roughness/smoothness/etc is now common.

You've bolded the one under size though -- this is the same as roughness, it defines the size/shape of the specular highlight, while the other map (intensity) controls how visible the highlight is. The intensity map can be RGB or monochrome, or both (which will be multiplied together in the shader).

In traditional ad-hoc shaders, artists needed to tweak the two maps in conjunction to get good results -- e.g. increasing intensity while reducing size.
With PBR, this is no longer the case. We're now using real physics (regardless of whether were raytracing or not, the BRDF is the same) - so the material inputs / maps that we provide are now physical values. A *normalized* specular BRDF means that the intensity is automatically boosted/dulled by the physically correct amount based on the roughness/size value. The intensity is also modified according to Fresnel's law; the value painted in your specular intensity map is the fresnel reflectance at normal incidence, Fresnel's equations allow us to use that value to find the correct specular intensity for other incidence angles.

An infinitely smooth surface will reflect 100% of the incoming light out of one single point, a Lambertian-rough surface will reflect 1/pi of the incoming light from each point - that amount is then multiplied by the 'intensity' value, which results in small highlights being brighter than large highlights, even if both materials have the same specifed 'specular intensity' value.

With a PBR renderer, the spec maps are not just values to fool the viewer, they are real, measurable physical values being plugged into a simulation. Also, a lot of the same BRDFs are being used in real-time engines now, as are being used in offline ray-tracers for VFX. While VFX has the liberty of Ray-tracing everything, they still often use IBL for "ambient specular", which still gives real reflections, very quickly, but only for distant objects -- real time systems now use the same IBL type systems as film too!

The correct specular intensity value for a material can be calulated if it's IOR is measured -- for most non-metal objects, this value is about 3/100 -- this value does not change depending on whether the surface is smooth/glossy/rough, it only depends on the raw material that the surface is built out of.

Roughness/smoothness/size/etc is a statistical value that gets plugged into a probability distribution to simulate a highly detailed normal-map that's smaller than a pixel. If you cared to sculpt/scan your surfaces at the micro-meter scale, you could automatically select correct roughness values based on the distribution of the normals within that micro-surface.

So basically - your advice is correct for traditional rendering systems, but not PBR systems.

Under a traditional (non-normalized) BRDF:

-- smooth plastic has low roughness / high gloss, and has high intensity.

-- rough plastic has high rougness / low glass, and low intensity.

Under a PBR BRDF though, they're both the same material, and they're both a common dielectric, so they both have the same intensity of about 3% (AKA Fresnel reflectance at incidence zero) and only the roughness/gloss value is different.

Likewise, smooth plastic and smooth chrome share the same roughness/gloss value, but have completely different 'intensity' values (~3% vs 90+%).

[edit] Here's another link dump - not so great for implementation, but just talking about PBR:

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

https://www.fxguide.com/featured/the-state-of-rendering/

http://www.fxguide.com/featured/the-state-of-rendering-part-2/

http://www.fxguide.com/featured/game-environments-parta-remember-me-rendering/

Let me see if I have understood this correctly. To implement Cook-Torrance I need to:

1. Modify my G-buffer to store specular intensity (AKA ref_at_norm_incidence in the article) and a roughness value.

2. Normalize the function by multiplying the diffuse term by (1 - (specular intensity AKA ref_at_norm_incidence)).

3. Bathe in the glory of physical based shading.

My bet is that this is 100x easier to tweak to realistic results compared to my current lighting.

Sorry to double post, but a simple "yes" or "no" is all I need... ._.

Yes.

Though even Phong or Blinn-phong (the typical specular formulas) both stored intensity and roughness values in the g-buffer too (often called spec-mask / just "specular" and spec-power / spec-exponent).

But from what I've undersood the specular power is actually the inverse of roughness, since a roughness value of 0 would correspond to a very high gloss value (over 100 at least or something?). You're right that the change in the G-buffer isn't much of a change though.

But from what I've undersood the specular power is actually the inverse of roughness, since a roughness value of 0 would correspond to a very high gloss value (over 100 at least or something?). You're right that the change in the G-buffer isn't much of a change though.

Yeah. But in practice, roughness is often actually stored in a "smoothness" map, where 0=rough and 255=smooth... but we still call the variable roughness anyway unsure.png

With specular power, it's a value that goes from 0 to infinity -- or generally, usually from 1 to a large number, maybe 2048 or 8192...

Often to decode spec-power from a texture (which only stores a 0-1 range), you'll use something like:

float power = sqrt( tex2D(...) ) * 8192 + 1; //or

float power = pow( 2, tex2D(...) * 12 + 1 );

Each engine will decide on a different mapping between their textures and how to decode them into spec-power values...

Different BRDFs will use different ranges for roughness. In some of them, roughness is in the 0-1 range, where 0=rough and 1=smooth -- in that case, you can just use the texture as is. In others 0=smooth and 1=rough -- in that case you can just use 1-tex2D(...). With the GGX BRDF that I'm using, I'm currently using 0=smooth, 1=rough and 4=extremely-rough, so I use pow(tex2D(...),4.4)*4.

The different curves - pow(x, y) or sqrt(x) (which is just pow(x, 1/2.0)) are there to skew the middle grey levels in the texture either towards 1 or 0.

e.g. you might want spec-power values from 1-8000. However, spec values of 1.5, 2, 2.5 and 3 give extremely different appearances, while spec values of 7800, 7900 and 8000 all look pretty much identical. So, in this case, you want to skew distribution of your middle grey values down towards zero, so you've got a more even distribution of different appearances when the artists try to paint their maps.

I was in the same situation recently, after reading a lot of paper I wanted to implement physically based shading.

I'll just add one link to the ones provided above : http://graphicrants.blogspot.ca/2013/08/specular-brdf-reference.html

There is a lot of cook torrance specular variations, I found it very helpfull.

If you want to see an actual implementation you can dive in the Unreal Engine 4 source code, you'll found those equations, and the parameters used.

Before implementing PBS in my (tiled) deferred engine I made a very simple forward viewer, to test the inputs I'll want to store on the GBuffer. If you want to look at it, you can download it here: http://www.alexandre-pestana.com/physically-based-rendering-viewer/

It's very basic, but it allows me to test textures and parameters. I didn't release the source code yet (I need to clean some import mess before), but you have access to the pixel shader, so maybe you'll find that helpfull. You can also modify the shader and dynamically recompile it by pressing "Alt Gr". But if it does not compile I think the viewer will miserably crash (I use this feature for development, with breakpoints to relaunch compilation in case of error).

As I said, I'm discovering PBS, so it may still be some mistakes in my implementation. If you found one, I would be happy to know !

I've made a new version of the viewer, where I implemented all the specular variations found in the blog post from Brian Karis, I think I'll upload it tonight or tomorrow.

Thank you very much! I've converted the Cook-Torrance shader to GLSL and I believe I have it working. I'm not quite sure if the result is correct though. In my opinion the fresnel effect is way too strong. Here are my results with a specular intensity of 0.0 and a roughness value of 0.5.

Result:

JYYaVSd.jpg

Specular only:

OrckCO4.jpg

Is this really the correct result? Despite the specular intensity being 0, I get a huge amount of specular reflection when the view angle is high. The "problematic" line is


float fresnel = specularIntensity + (1.0 - specularIntensity) * pow(1.0 - VdotH, 5.0f);

which basically causes the specular intensity to approach 1.0 when VdotH approaches 0 regardless of what the original specular intensity was. Is this really correct? It looks very different from how I am used to. For example, I attempted to reproduce these results in real life using a plain white A4 paper and a lamp, and the specular intensity was pretty much negligable. Perhaps I was just using a too low roughness value (0.5), since a roughness value of >1 produces very good "papery" result.

you can change your line by this one who gives better perf for the same result :


float fresnel = specularIntensity + ( 1.0f - specularIntensity ) * exp2( (-5.55473f * VdotH - 6.98316f) * VdotH );

This topic is closed to new replies.

Advertisement