DGS Exploited

When MentalRay users talk about 'physical correctness', in most of the cases the usage of DGS (diffuse, glossy, specular) shaders is discussed. Some people say you should use them at least as photon shaders, just because they're fast and, yes, physically plausible. But how do they act differently than the Maya base shaders? If you ever used dgs shaders, you probably asked yourself if it was possible to 'mimic' the dgs behavior somehow - just because they are yet simple, but sometimes very hard to bear with (just think of the glossy reflection samples that cant be set - very annoying). What if we could tell a Maya base shader to act like it's dgs companion?

Let's have a look at how 'different' they actually look (without using photons - we're only out for the regular shading for now). I took a standard phongE material without any highlight or reflection (so actually it acts like a lambert material) for comparison:

These are the settings:

And here's a render:

The dgs (left sphere) is obviously much darker - just a matter of settings you'd say. So let's tweak them a bit - let's increase the dgs' diffuse to total white:

Better, but still very dissatisfying - and the 'Color' attribute of our phong is still darker (0.5 value!) than the dgs' diffuse color. What is the cause of this discrepancy? Having a look at the dgs shader sources, which are freely availabe we see the reason for this. A line of comment says (and it's also applied later on in the code):

[code]* m->diffuse is reflectance rho (0 <= rho <= 1). BRDF f_r = rho/pi.[/code]

This means, the radiance (rho), is being divided by pi (approx. 3.1415etc...). Uhm..

[interlude]
What does radiance actually mean? Here's some useful links describing the term:
http://www.dotcsw.com/poy2001.txt
http://en.wikipedia.org/wiki/Radiance
http://en.wikipedia.org/wiki/Luminance

So radiance is used to indicate how much power will be received by an optical system looking at the surface from a certain angle. The division by pi will be explained later on.
[/interlude]

How could we achieve what the dgs is internally doing, with our Maya shader? You guessed it, let's use the 'Diffuse' attribute of our Lambert material, which acts as a simple multiplier to the 'Color' value. Since we cant literally divide, we need to multiply by the fraction: 1/pi (approx. 0.318). Let's do it:

Oops, what went wrong? Sure, we set our dgs' diffuse color to white before, let's do so with our phong.
Set the phong 'Color' to total white:

Jackpot!
But what about the indirect illumination (irradiance), like if we used finalgathering for example?
Let's see:

FG on, all settings same as in the last image:

Ugh! What happened? Lamrug.org gave me the answer:
http://www.lamrug.org/resources/mayafgtips.html. When a shader gathers irradiance with mi_compute_irradiance, it should normally divide the result by Π, since the irradiance is the energy gathered over the hemisphere above that point. Dividing by Π makes it a color at the point.

So the irradiance is being divided by pi already (this does not apply to maya 5 and earlier). Our irradiance is now actually divided 2 times, because 'Diffuse' is multiplying our irradiance as well - not good. But we can overcome this by a simple trick: we just multiply the irradiance by pi again. By clicking on the 'Irradiance Color' (NOT 'Irradiance'!) the color picker pops up. We then replace the 1.000 in the 'Value' field by pi (3.1415):

Alright, let's have a look if it worked out:

Bingo!

Adjusted light intensities:

But what about reflectivities? That's way easier, because the phong's 'Specular Color' acts the same as the dgs' 'Specular' - you only need to set the (tuned) base shader's 'Reflectivity' to 1.

And here's a render:

Note that we set the diffuse colors back to 0.5, and the specular colors to 0.5 as well. This is because the dgs photon shader enforces energy preserving 'scattering coefficients'. The source comments:
[code]/*
* The dgs photon shader enforces energy-preserving scattering coefficients,
* that is, the following three requirements:
* diffuse.r + glossy.r + specular.r has to be <= 1,
* diffuse.g + glossy.g + specular.g has to be <= 1,
* diffuse.b + glossy.b + specular.b has to be <= 1.
*/[/code]

This means, we would get physically incorrect results if we used photon tracing and a combination of diffuse, glossy and specular values that exceed a total value of 1.0. In other words, the V components of our HSV colors should be smaller than 1.0 in the sum.

Speaking of photons, what can we do to mimic the dgs' photonic behavior? All though the solution is easy, it's a bit tricky if dont have any starting point. Well, here it is: We switch off the Derive From Maya checkbox and press the Take Settings From Maya button, to inherit anything we did from the regular shader. It will look like this first:

To recover from the irradiance trick we applied due to internal 'correction-calculations' the shader does, we would need to multiply the photonic intensity by pi again. To do this, we again use the diffuse attribute, but this time the miDiffuse or photonic diffuse attribute. It's currently at 0.318 (1/pi) - so if we multiply it by pi, it yields exactly 1:

And glossiness? Well, the glossy color is again the same as 'Specular Color' (with reflctivity 1.0), the shininess is controlled by 'Reflection Blur' attribute - where a 'Shiny' value of 5 equals (experimentally obtained) approx. a 'Reflection Blur' of 13. However, in my experience it is usually better to rely on custom blurry reflection shaders, like Francesca Luce's ctrl_shading - simply because they are faster than the built-in reflection blur. You can plug the ctrl_shading's reflection output into the Reflected Color slot of your Maya shader, turn the Reflection Limit attribute under Raytrace Options of your material to 0 (to completely hand over raytracing to the custom shader) and set the ctrl_shading's reflectivity to 1.0 (it's actually called 'Scale' in the shader) - it will be properly scaled by our Specular Color attribute of our Maya shader, so no worries. If we use photon tracing, we simply set the 'Shinyness' value of the photon part of our Maya shader to the same value as in the ctrl_shading. The ctrl_shading can be found here: http://forums.cgsociety.org/showthread.php?t=252304

Alternatively in Maya version 7 the mib_glossy_reflection can be used, which now ships with the MentalRay base shaders.

If you ask yourself why the dgs are still faster, specially when using finalgathering, there is an answer too. The dgs internally rejects light sample calls on the 'wrong' side of your surface (the side with normals pointing away from the light). In my tests this reduced the amount of light sample calls by about 30%, resulting in faster rendering. Unfortunately, this cannot be simulated by our Maya shaders, so we have to bear with it.

That's it! I hope you enjoyed the little brain workout! Much of theoretical stuff and no beautiful pics, but "The noblest pleasure is the joy of understanding." (Leonardo da Vinci)

Fetching comments...

Post a comment