better metals

Issue #786 resolved
Alessandro Padovani created an issue

Until now we used the principled shader for metal, even for the bsdf option, because I had no idea how to do metal with the bsdf shaders. This causes artifacts as the metallic seam in #661, and also it is not elegant since we mix principled and bsdf.

It turns out that making a quite good bsdf metal is way simpler than I thought. It is enough to use a glossy bsdf, mixed with the non metal material if metallicity < 1. Please note that for 100% metal all the glossy channels but the roughness are ignored by iray, the layered weight is ignored too.

Please note that this is for the uber shader. The pbrskin shader is different and has no glossy roughness, I'm working on it to understand how it works for metal.

Please note that the metallic group is a single glossy node, the dielectric group is diffuse + glossy + fresnel. In the uber shader a 100% metallic material does ignore translucency thus volume and even dual lobe, but not top coat. So the metallic mix will be placed after translucency and dual lobe if any, and before the top coat layer.

In my tests the metallicity mix for the uber shader seems to be quadratic, that's unusual but it's what I get.

# for bsdf metal use a glossy bsdf mixed with the dielectric material
color = base color
roughness = glossy roughness
mix = metallicity ** 2

Below a couple examples and test scenes. The dark storm armor storm.duf first iray then cycles. Then a G8F semi-metallic face g8f-metal.duf first iray then cycles. This last example is more to test the correct position of the metallic node in the shader chain as explained above.

Comments (33)

  1. Alessandro Padovani reporter

    Thomas commit 76883dd works great. I forgot refraction in my tests but the commit works fine with refraction too. Will update as I get the pbrskin shader.

  2. Alessandro Padovani reporter

    Ok I believe I got it.

    The pbrskin shader essentially uses dual lobe instead of glossy, so we get a dual lobe metal. Again a 100% metal ignores translucency thus volume and even dual lobe, but not the top coat. As a good example we can take Victoria 8.1, test scene v8.duf. Below there’s the custom group for the pbrskin metal, and the setup for the face material.

    Please note that metal comes just before top coat.

    In this case the metallicity mix is linear, that is, fac = metallicity.

    IMPORTANT NOTE. In the setup below I did an error because I replaced dual lobe with metal. In this case dual lobe does not have to be deleted because metal is mapped so it’s not 100%. The correct shader chain is diffuse > translucent > makeup > dual lobe > metal > top coat.

    # pbrskin metal
    fac = metallicity
    color = base color
    roughness 1 = dual lobe specular roughness mult * specular lobe 1 roughness
    roughness 2 = dual lobe specular roughness mult * specular lobe 1 roughness * specular lobe 2 roughness mult
    dual ratio = dual lobe specular ratio
    

    Below the rendering first iray then cycles. This time we get the metallic makeup without the seam in #661, and with the full volumetric skin.

  3. Alessandro Padovani reporter

    As for commit 22f01a6 there are a couple issues.

    1. The glossy roughness is ignored if the glossy layered weight is zero. As explained above in iray the metallic layer doesn’t take into account the glossy layered weight, it always takes the glossy roughness for the metal even if the layered weight is zero.

    2. The mix factor is quadratic both for uber and pbrskin. About this, I did more tests and I got inconsistent results both with linear and quadratic factors. This means that when mixing metal with dielectric the results will not be the same in daz and blender in the mid values. But it is is fine near 0% and 100%. Luckily the metal mix seems to be mostly used with maps to overlay 100% metal with 100% dielectric, so in most cases there are no issues.

    So please Thomas make the mix always linear for the time being, that is, mix = metallicity. This is also the case with the principled option so at least we are consistent.

    Below a little example just to show what I mean, test scene metal-mix.duf where I mixed a red metal and a green translucency, at 0% 50% 100% with a linear factor. First iray then bsdf then principled. We see that 0% and 100% works fine enough while 50% is not the same.

  4. Alessandro Padovani reporter

    note. In the picture above we can also see that there are differences between the daz metal and the bsdf and principled metals. That is, the daz metal tends to have both white rims and a black fill. The bsdf metal has none of them. The principled metal only gets white rims. So there’s room for improvement but for the time being I’d be content with this. Again will update if I find something better.

    Then of course if anyone wants to contribute for better metals you’re welcome.

  5. Thomas Larsson repo owner

    Fixed in last commit. Question: in the pbrskin case, should the dual lobe roughness still be used if dual lobe specular weight = 0?

  6. Alessandro Padovani reporter

    Yes, the pbrskin metal does ignore the specular weight, even if it is zero, the reflectivity is also ignored, that’s also why they don’t figure in the equations. Going to test the new commit ..

  7. Alessandro Padovani reporter

    Commit 72367a0 works fine for the uber metal. The pbrskin metal needs to be fixed to ignore the specular weight as reported above.

    We didn’t consider importing the pbrskin dual lobe metal for the principled shader. It seems to me that actually a 0.5 roughness is used for the pbrskin metal. That’s fine for me since the purpose of the principled shader is to be simple then the user may fix it by hand when needed. Or we could mix two principled to make the pbrskin dual lobe metal.

    Thomas I let the decision to you let us know what you think.

  8. Thomas Larsson repo owner

    The pbrskin metal now has roughness even if the dual lobe specular weight = 0.

    The principled roughness seems to be taken from the glossiness channel, and from glossy roughness only if that does not exist. Since there is only one roughness slot in the principled node, the dual lobe roughness does not enter here. Perhaps we should use glossy roughness by default instead. Or perhaps one should pick different iray roughness channels depending on the metallicity value. Anyway, making two principled nodes just for this seems overkill.

  9. Thomas Larsson repo owner

    It turns out that the pbrskin shader has neither glossiness nor glossy roughness, so the importer set the principled roughness to the default value. However, pbrskin does have diffuse roughness, so now I use that instead. That gives roughness = 0.3.

  10. Alessandro Padovani reporter

    Commit 3c6ca09 works as intended.

    The diffuse roughness has really nothing to do with metal or reflections in general. It is for oren nayar diffusion, that's more realistic than lambertian diffusion.

    As for the principled shader, if we want to stay with one layer, I'd rather use the equations below. It's not the same as a dual layer metal but at least it makes some sense. Please note that we set the principled values only for full metal, otherwise the channels are already used by diffusion and reflection and we have to decide what to give priority to.

    A multilayer principled shader would help to better convert dual lobe metals and reflections, other than mixing metal and dielectric. But this is not something that I want to deal with here right now. Just a note to keep in mind.

    # bsdf pbrskin metal
    fac = metallicity
    color = base color
    roughness 1 = dual lobe specular roughness mult * specular lobe 1 roughness
    roughness 2 = dual lobe specular roughness mult * specular lobe 1 roughness * specular lobe 2 roughness mult
    dual ratio = dual lobe specular ratio
    
    # principled pbrskin metal
    if metallicity == 1
        metallic = metallicity
        specular = 1
        specular tint = 1
        roughness = roughness 1 * (1 - dual ratio) + roughness 2 * dual ratio
    else
        metallic = metallicity
    

    Below an example of dual lobe metal first iray then the principled version fixed with the equations above. We can see that the middle value with dual ratio = 0.5 does not match, this is expected since a single node can't do dual lobe effects. Test scene included skin-metal.duf.

  11. Alessandro Padovani reporter

    Commit c8ba05f works fine.

    I want to update the bsdf metals to support a rim and anisotropy as the principled option does. I have the basis already set up but need some more tests.

  12. Alessandro Padovani reporter

    UPDATE.

    daz studio 4.15.0.30, blender 3.0, diffeomorphic 1.6.1.0774

    Ok this took more time than I thought, it is not trivial to setup metals and match iray. But I believe I finally got something decent enough. So let's begin.

  13. Alessandro Padovani reporter

    1. ANISOTROPY

    In #10 we got anisotropy for the principled shader, but we never did it for the bsdf option. Here we try a first implementation that serves both for dielectric and metallic materials.

    Please note that iray and cycles use different distributions for anisotropy, that's why we had to tweak the roughness in #10. Unfortunately it turns out that the principled and anisotropic shaders in cycles use different distributions too, even the ggx distribution is not the same. I didn't find any easy equation to match them, but the shirley distribution seems to approximate iray fine enough for a low roughness, that's where anisotropy is more visible.

    If anyone is kin to math and wants to help for a better conversion have a look at the links below. Didn't find anything about the distribution used by iray though.

    https://blender.stackexchange.com/questions/123765/
    https://blender.stackexchange.com/questions/40586/

    So below are the equations and the dielectric setup. For the bsdf option it is enough to replace the glossy shader with the anisotropic shader, that's the same as glossy but with anisotropy as an added feature. Please note that eevee doesn't support anisotropy and will ignore it. Please note that anisotropy is only for the uber shader, the pbrskin shader doesn't get it.

    # principled bsdf
    roughness = glossy roughness * (1 + glossy anisotropy)
    anisotropic = glossy anisotropy
    anisotropic rotation = 0.75 - glossy anisotropy rotations
    
    # anisotropic bsdf, works fine for low roughness
    distribution = shirley
    roughness = glossy roughness
    anisotropy = glossy anisotropy
    rotation = 1 - glossy anisotropy rotations
    

    Below a comparison, first iray, then the principled bsdf, then the anisotropic bsdf with the equations above. Test scene dielectric.duf.

  14. Alessandro Padovani reporter

    2. METAL FRESNEL

    And of course guess what, the metal fresnel is not the same as the dielectric fresnel. The difference is that the metal fresnel always goes down to zero for front facing geometry and shows the metal color, while the dielectric fresnel always adds some specularity depending on the surface roughness. Credits to Blender Guru for the explanation and setup of pbr metals. Beware that the information there is not always accurate nor up to date, but it is definitely a good start.

    https://www.blenderguru.com/tutorials/making-realistic-pbr-materials-part-2-metal
    https://blender.stackexchange.com/questions/63773/

    We're becoming to get a number of different fresnel groups for the various daz shaders, see #576. So it may be convenient to group all of them into a more general purpose fresnel 2.0. Below the setup and the difference between the dielectric and metal output.

    # daz fresnel 2.0 match with previous groups
    DAZ FRESNEL: power = 1, output = dielectric (ex. uber skin genesis 8)
    DAZ FRESNEL UBER: power = 2, output = dielectric (ex. dual lobe uber skin victoria 8)
    DAZ FRESNEL PBR: power = 4, output = dielectric (ex. pbrskin victoria 8.1)
    

  15. Alessandro Padovani reporter

    3. FULL BSDF METALS AT LAST

    So below there's the new setup for the uber metal, this adds fresnel and anisotropy to the previous one. Please note that in iray metals don't react to ior, so it's fixed ior = 1.5 that seems a good match. For the same reason in the principled metal we set specular = 0.5 that's the equivalent of ior = 1.5. Please note the HSV node for the fresnel color that approximates a metallic tinted reflection.

    # bsdf uber metal
    fac = metallicity
    color = base color
    roughness = glossy roughness
    anisotropy = glossy anisotropy
    rotation = 1 - glossy anisotropy rotations
    
    # principled uber metal
    roughness = glossy roughness * (1 + glossy anisotropy)
    anisotropic = glossy anisotropy
    anisotropic rotation = 0.75 - glossy anisotropy rotations
    if metallicity == 1
        metallic = metallicity
        specular = 0.5
        specular tint = 1
    else
        metallic = metallicity
    

    Below the pbrskin metal. Please note that it doesn't get anisotropy, also it doesn't get tinted reflections as the uber metal does, so we use a white color for the fresnel effect. We still use the shirley distribution though because it gets more contrast and it is more similar to iray.

    # bsdf pbrskin metal
    fac = metallicity
    color = base color
    roughness 1 = dual lobe specular roughness mult * specular lobe 1 roughness
    roughness 2 = dual lobe specular roughness mult * specular lobe 1 roughness * specular lobe 2 roughness mult
    dual ratio = dual lobe specular ratio
    
    # principled pbrskin metal
    roughness = roughness 1 * (1 - dual ratio) + roughness 2 * dual ratio
    if metallicity == 1
        metallic = metallicity
        specular = 0.5
        specular tint = 0
    else
        metallic = metallicity
    

    Finally below a comparison with iray, first the uber metal then the pbrskin metal. Please note that the bsdf version is now much better and more similar to iray than the principled version. We can't do much to match principled with iray due to the principled limitations, but this is expected. Test scenes uber-metal.duf and skin-metal.duf.

  16. Alessandro Padovani reporter

    That was fast, commit 149f76d almost works fine but there are a couple issues.

    1. In general the volume node must not be generated if there’s no translucency, since volume is only visible through translucency. Then 100% metals ignore translucency so volume too.
    2. Same for the principled node, metals ignore sss so there’s no sss for 100% metal. Also the uber metal needs specular = 0.5 and tint = 1.
    3. The daz metal pbr needs shirley.

  17. Thomas Larsson repo owner

    Those were rather minor things and should be fixed now. However, what I don’t understand is why there is such a big difference between metallicity = 1.0 and < 1.0. Naively I would expect there would be a smooth limit, so metallicity = 0.99 should not be very different from 1.0. Or is metallicity only equal to 0 or 1 in practice, and intermediate values never occur?

  18. Alessandro Padovani reporter

    No, the difference is only that 100% metal doesn’t mix, so everything ignored by metals should be pruned. Otherwise, even for 99% metal we mix. Or keep the dielectric values for the principled shader because we want to use a single node, see 2021-12-04 above.

    Going to test the new commit.

  19. Alessandro Padovani reporter

    Commit 69e0052 doesn’t work fine.

    The uber-metal.duf and skin-metal.duf test scenes are good. But the v8.duf test scene isn’t, that is, the volume is pruned even if metal is not 100% aka gets a metal map.

  20. Log in to comment