I’ve recently been working on building an approximation of the Max Physical Material as a Cycles shader node graph. Once complete, this will allow this plugin to render the Physical Material with a similar appearance to ART. For this post I will be explaining how I built the reflection component of this Cycles shader graph.
To start, we need to know what the reflection component on its own looks like. Fortunately Max makes this easy by simply allowing one to disable all other components. Using default settings, the reflection component looks like this when rendered on a sphere using ART:
From this image, we can learn three important things:
- Looking closely at the top-left and bottom-right reflection, we can see there are no light gray pixels surrounding the white reflections. This means that the reflection is very sharp.
- This surface is only reflecting some of the light that hits it. Were it reflecting everything, the whole thing would be the color of the gray background. Every part that is darker than the background is absorbing some light.
- Looking around the edges of the sphere, there is a very noticeable vignetting effect. This is a result of the material reflecting a different amount of light based on the relative angle between the light and the surface. This phenomenon is known as Fresnel reflection. In this case, the material reflects more light at low angles of incidence that at high angles. The gray color around the edge comes from the sphere reflecting the gray background.
With this knowledge, we can begin assembling the shader. The first step is to create a perfectly sharp reflective material. Cycles makes this step easy by providing a Glossy Shader that is exactly what we need, it looks like this:
The light reflections are noticeably bigger in this image, that is just side-effect of the different lighting setup being used Cycles compared with the one used in ART. Later on when we draw direct comparisons between the Cycles and ART versions of the material, we will use a scene where both are lit the same. The spheres are just a quick preview.
The next thing we need to account for is the amount of light that is reflected from and absorbed by this shader. Only three things can happen to light that hits this surface, it can either be absorbed, transmitted, or reflected. This material is completely opaque, meaning there is no transmission, so we know that for this material light can only be absorbed or reflected.
We already have a shader that reflects all light that hits it, so now we should make one that absorbs all light. We can then use a Mix shader and a weighting factor to decide how much of the light gets directed to the glossy shader, which will reflect it, and how much gets directed to the black shader, which will absorb it. Our black shader looks like this, as you may expect from its name:
We can combine these using a Cycles Mix node. This node takes a weighting factor and two other shaders as inputs. By default the weighting factor is 0.5 across the sphere’s entire surface, meaning that half of the light hitting the surface will be directed to one of the sub-shaders, and half to the other. Combining our glossy and black nodes using a weight of 0.5 produces the following output:
This is closer to what we want, but it isn’t there yet. Now we need to account for the Fresnel reflection that is occurring in the ART render. To start, we’ll just make a Cycles Fresnel node and connect it to the color channel of an Emission shader. This will allow us to visualize what the Fresnel weighting factor looks like on its own in Cycles:
Plugging this in as the weighting factor between the reflective and absorptive shader, such that lighter means more reflection and darker means more absorption, we get this:
Recreated in Blender, our node graph looks like this:
Now we have a Cycles shader the closely resembles how the physical material is rendered in ART, but there is still another parameter that is part of the reflection component that we need to account for: roughness. So far all the pictured renders have used a roughness of zero.
To see how roughness changes the appearance of this material in ART, I set up a simple scene with a number of reflective planes of differing roughness all reflecting the same light source. In this image the left-most plane has roughness of 0.0 and every other plane has roughness of 0.04 higher than the plane to its left, with the right-most plane having a roughness of 0.24
Our Cycles Glossy node also takes a parameter named roughness. To start off, lets just take the roughness value from the physical material, plug it straight in to the Cycles shader, and render the above scene again, this time with Cycles.
In this image the plane with 0.0 roughness looks good, but everything else is far too rough. At 1.0 roughness both look about about the same (not pictured), so we need to find a way to map the [0, 1] range of the ART shader to visually identical values in the range [0, 1] for the Cycles Shader. Both roughness of 0.0 and 1.0 render correctly in Cycles, so it is the values in between that we must focus on.
For this, we will need to create a function to convert from Physical Material roughness to Cycles roughness. For an input of 0, it must produce a value of 0, and for an input of 1, it must produce a value of 1. For values between 0 and 1, the output (Cycles roughness) should be some amount lower than the input (material roughness), which we know from observing the above two renders.
This can be easily achieved with a power function, which is simply: out = in ^ power. For any power greater than 1, this matches the criteria we specified in the previous paragraph. Now we must find exactly what this power should be.
Just by eyeballing the above 2 images, we can see that 0.24 roughness for the Physical Material is approximately equal to 0.04 roughness for Cycles. Substituting those numbers into the power equation gives us:
0.04 = 0.24 ^ power
Solving for power, we get ~2.25. Now that we have a function that we expect will correctly convert from Physical Material roughness to Cycles roughness, we can plug it in to our Cycles shader graph and render again.
Much closer than before, but now we have the opposite problem. In this render, the reflections in Cycles are a bit sharper than equivalent reflections in ART. This means we need to reduce the power. I’ll skip over the tedious part here, but after a few rounds of altering the power and re-rendering I found that a value of 2.05 makes the Cycles render closely, though imperfectly, resemble the ART render.
And that is it, we’re done. Now we have a Cycles shader graph that approximates the reflection component of the Physical Material. Here is a quick comparison of their appearance at 0.0, 0.2, 0.5, and 1.0 roughness.