Shader node reflection model setup inaccuracy?
@noobalien - my (possibly faulty) understanding is that 1) everything has specular (or more properly reflectance I guess), and 2) at a strong enough grazing angle all surfaces will act as mirrors & reflect 100% of light. However, the rougher the surface (at a very small scale) the more spread out the highlight; the smoother the surface the sharper & tighter the highlight. So a smooth body of water will appear mirror-like at a grazing angle but a stone will not (unless it has been polished).
Surface reflectance for dielectrics is given as a range of 2-8% with gemstones reaching up to 16%. In a metal-rough workflow where the metalness map determines metal & non-metal surfaces the non-metals are averaged to 4% (a metalness map is generally black or white; intermediate values can apparently cause shading artefacts in game engines).
What about rendering with the Physical Surface root node & Cycles root + nodes as a comparison?
Hopefully @bagginsbill will see this thread ...
noobalien last edited by
I don't understand why would some people get the idea that this is "if a tree falls in a forest" kind of philosophical question, when it isn't.
A mirror is still a mirror inside a dark, closed vault.
There's no need to see a render to notice the three shaders are different because the image shows that indeed the three shaders are different.
Circumstantial conditions such as auxiliary maps or environment were deliberately left out.
Specular node ks_microfacet was chosen because it has separate color, roughness and value (Ks) inputs, while it seems to match GGX distribution.
Thank you, this is closer to the answer I'm looking for. Hopefully Ted can see this and give his input on it.
@noobalien - I know that when Cycles was integrated as Superfly a lot of time & effort went into matching the existing Poser nodes to the nearest equivalent Cycles nodes as far as possible. I've been doing (Diffuse + Gloss) + Fresnel when using Cycles nodes, here's what I've come up with -
Seem to get a very good match between the Poser & Cycles roots using Superfly with this setup.
I'm using the Fac in the MixClosure & the Blending value in the Blender nodes for the % reflectance value. Also, if I plug in a texture or procedural for roughness I have to change the value in ks_microfacet to 1 to get it to match the Cycles node setup.
Still hope @bagginsbill will see this as I'm not entirely confidant that this is 'correct', but hope it may be of some use ;)
Well - you've certainly started an interesting topic.
While these three shader setups are basically the same, they don't produce the exact same results.
But they're not actually the same and therefore we should not expect them to produce the same results.
Many papers claim the front face reflection for dielectrics is "about 4%" and therefore "near 100%" in the edges, but is this factually correct?
The statement is correct, but only for perfectly smooth surfaces.
Before we get started I'd like to change the setup to something with a bit more control.
We want to create a "furnace". This is an environment where the amount of light arriving in any direction to any point is exactly the same. When the arriving light is a constant, analysis and experiments are a lot easier.
If you don't have my environment sphere, get it here:
After you unzip and install in a runtime, load the "EnvSphere" prop.
Go into the advanced material room for the EnvSphere and delete everything. Set the PoserSurface up like this to make it into a furnace.
The prop we use matters, too. The Poser Primitives "Ball Hi-Res" is junk, with a bad UV map.
Go into Poser's Morphing Primitives and get the Ball from there.
I'm going to do small renders (300x300) for speed.
Fill your image mostly with the ball. Place a simple Reflect shader like this on it and render.
Surprise! There's some black smutch on the edge. WTF? This is an artifact, caused by the interpolation of normals on a rather course mesh.
Apply 2 levels of subdivision like so.
Render again and the artifact is gone.
Now it should be apparent that the reflect node is sampling all over the place on the EnvSphere but everywhere it gets the answer, 1 (max white).
Therefore with 100% reflection on the ball, it, too, appears to be 1 (max white). This is expected. It is, however, NOT physically correct, nor even plausible.
There are numerous correct ways to make a glossy black surface, and an infinite number of incorrect ones. (Your odds of picking a correct one at random are near zero).
Here's one way. This is how a perfectly smooth glossy (glassy) surface appears in a furnace.
Here is one of many correct ways to make a glossy surface with idealized Lambertian diffuse reflectance, with rgb 128, 20, 20 as the diffuse color.
The appearance in a furnace is correct. But we don't often experience furnaces so it looks funky.
Just to preserve our belief in the shader, I changed the EnvSphere to use a nice HDRI and the render looks very plausible.
Before we get into studying parameters and node arrangements, it will be useful to have a way to do two different setups in the same prop.
Rotate your Ball using yRotate = 90 degrees.
Now let's make a procedural mask for the ball that will give us black (0) for the left half, and white (1) for the right half.
It should look like this.
Now we can use that 0/1 mask to give us a "control" sample and an experimental sample.
Here I used it plugged in to a Reflect node Softness parameter. So, on the left, our known "control" is still as rendered earlier, with Softness 0. The left half is still completely white as we expect.
The right half is something else though! The right half has Softness .5 because whatever you plug in is multiplied with the value, so .5 times 1 is .5.
Interestingly the ball is not white. In fact, it's not even uniform. The center is darker than the edge.
Change the experimental value to 1 and the difference is even more striking.
I measure around 150 in the center, and 192 near the edge.
I cannot explain this behavior. I presume it means that the legacy Reflect node, when running in SuperFly, is actually using one of the micro-facet reflection models, and not the simple direct sampling we're used to from FireFly.
A quick test with the HDRI shows a surface that appears very much like a diffuse reflection.
Except it's not the same. No model of diffuse reflection gets brighter at the edges - quite the opposite.
Here is a setup with a Diffuse node (rgb 150 150 150) on the left side and the Reflect node with Softness = 1 on the right side.
Observe how at the center they're very similar, but approaching the edge they differ significantly.
So we've demonstrated that with the legacy Reflect node, there is some micro-facet model in play. Could we guess that the Reflect node is actually now a "synonym" for the GlossyBsdf node in a particular setup?
Let's try it and see.
I guessed that the equivalent would be GlossyBsdf with Color white and Distribution GGX.
Looks like a match to me.
But let's try a different Distribution just to be sure.
Well - clearly it's not even slightly matching the Beckmann distribution.
I will leave it to you to experiment with other Distributions and other settings for Roughness. I tried a few and nothing was even close. I'm pretty convinced that the Reflect node is synonymous with the GlossyBsdf set to GGX.
Let's test the first two of the original posted shaders, using the furnace.
Note that because I want both setups in the same shader, I had to make a small change to replicate the first shader. Instead of plugging the diffuse into Alternate_Diffuse and the ks_microfacet into the Alternate_Specular, I did the equivalent combination using an AddClosure. I can assure you the math is the same.
The two shaders produce different responses and it is (to me anyway) obvious why this is so.
The first (top) setup let's the diffuse node run free without modulation, and modulates the ks_microfacet reflectance using the idealized Fresnel equation.
The second arrangement (bottom) uses the fresnel factors to modulate BOTH.
In terms of math, letting S denote the specular node, D the diffuse node, and F the Fresnel coefficient for reflection, we can describe the first and second like this:
First: D + FS
Second: (1-F)D + FS
See the difference? It is no surprise that the outcome differs.
As further evidence of the math, I make a small addition to the first (top) shader wherein I use the complement of the Fresnel reflection coefficient to modulate the Diffuse node.
And now, the two arrangments produce exactly the same result.
So it should be clear that the two shaders truly are now "basically the same", and they DO produce the same results.
Now up top I changed to noobalien's 3rd arrangment. This is basically the same and the image shows this.
However, and this is a very interesting point, these arrangements do differ in parameterization. The 3rd (top) arrangement offers a unique opportunity to manipulate the shader in certain ways that matter towards producing a more physically accurate shader, given that the surface is not ideally smooth, but instead has roughness.
The simpler (bottom) arrangement does not let us adjust the Fresnel equation to compensate for roughness! And that is why the 3rd (top) arrangement is "better".
This is a common theme in my shaders and a common complaint by other users who perceive my shaders as overly complicated. The complication is NECESSARY to implement variations. When you look at a particular set of values (such as roughness = 0), then it is possible to remove some nodes.
But to allow for the other billion roughness values, AND maintain physical accuracy, the four-node setup is far more flexible than the three-node setup, even though they appear to be the same.
They're only the same because they're unfinished. They are both equally WRONG at the moment, but one is easier to correct than the other.