Substance Painter PBR textures convert to Corona renderer materials


Hi everyone! I am working in "Allegorithmic Substance Painter" regularly. It is incredible, amazing and powerfull tool for creation realistic or stylized textures. At the final of workflow it able to export textures with vast options maps.
Often I am using Corona renderer in 3Ds MAX 2018 for Stand-alone rendering. I love it. It is user friendly tool, powerfull and very iteractive. When I am exporting textures from Substance Painter with default preset "Corona" I have 6 textures:
• Diffuse map
• Glossiness map
• IOR map
• Normal map
• Reflection map
• Height map
This 6 textures are enough to create Corona material in 3Ds MAX. But in every case I needed to fix  maps to succeed same result between "Substance Painter" PBR viewport and Stand-alone 3Ds MAX Corona render. Usually I have fixed the gamma value or exposition the maps. It wastes some time. And the result be able to a different than in "Substance Painter" preview. 
For example I have made some renders in 3Ds MAX Corona renderer 1.6. For my experiments I have used the MatMeet model and standard "Substance Painter" smart materials. I have prepared same environment in the scenes (Substance and 3Ds MAX) and similar lighting settings. For HDRi illumiantion I have used "HDRi Studio map". There is the link for download.
On the left you can see Corona renderer with material based on 6 texture maps (Corona preset in Substance Painter). In the middle is screenshot of viewport Substance Painter. He will be a reference. And on the right you can see Corona renderer with material based on PBR textures (Albedo, Metallic, Roughness, Normal, Height). Actually for process optimization I have excluded Height map. Height map do not affect to the result globally in this case.
On the right in material based PBR textures I have invert Metallic map and assign it yo IOR slot. As you can see on the right is terrible result. This it was obvious. In the further I will not considering this option.
However the material based on Corona preset looks not bad. But it is not same result! I have changed the environmnet rotation angle to another example for comparing.
The image shows that Reflections, Glossiness and IOR are different. Do not pay attention to the different color, hue, brightness. Albedo map and Diffuse will be same. It is correcting with contrasts or another filter. In the next image you as demonstraded differences in Reflection, Glossiness and IOR withour color.
If you compare CESSENTIAL_Reflect from 3Ds MAX "Render Elements" with Roughness+Metallic+Normal maps (without Albedo map) you will see that difference is vast. On the right there is screenshot viewport with Roughness map only in Substance Painter.
To succeed best result you have to experiment with output values into 3Ds MAX. 

I have created the universal Corona material for 3Ds MAX based on PBR textures. You don't have to fix output values or something else. Maybe it needs to little correcting for best result. Anyway I think it is good decision. 
Let me show how it looks. On the right is screenshot viewport of Substance Painter and on the left is Corona renderer based on my PBR material. 
As you can see the result very similar. Reflections, Glossiness and IOR are correct! 

How do it use? It is so easy! Just take PBR maps (Albedo/BaseColor, Metallic, Roughness, Normal, Height) and put into empty slots. In the materials there is no empty "Height map slot". If you need it put into Heigh in both materials.
This templete of Corona materials is not panacea :) Sometimes the materials needs to adjustments for best result. Generally "Roughness/Glossiness" and IOR able to look little different. Use "Map #243" (Output map) for adjustment non-metal material Glossiness. If you want to fix Glossiness you need Decrease or increase "RGB Offset" value in output options. For adjustments Glossiness in the "Metal material" use "Map #237" (CoronaMix map). If you want to customize metall glossiness you need to  increase or decrease "multiplier" of Top layer in the CoronaMix map. 
There is rare case - wrong IOR in the Blended composite material. This is typical of complex metals (Rust or similar). In this case you need to fix Outputs values in "Metallic map". If you want to make material in general more metallic decrease "RGB Level" (Less than 1). If you want to make material in general less metallic do not use "RGB Level" (leave default value - 1), Instead use "RGB Offset". Increasing in "RGB Offset" value do material more non-metallic in general. 
I guess my template will a good start point for converting PBR textures to Corona renderer materials.
Make sure that you using default 2.2 gamma in Preferences of 3Ds MAX.


3Ds MAX 2018 material library file with the template you can download here. It is FREE!  

If you appreciate or this materials was helpfull you can donate me via:

BitCoin wallet
1Brm4jUw8URjgkpxTkekxLfddguovcaJ9U

Etherium wallet
0x828b96185896facb8c998b50fb5d2ce67ecf6d23

Monero wallet
47H5gKghN65fHZwAYuo4mWiRNXAsRHBe9fYqh1oGGqDTMKtFQKzvL7hTfbrFfkGhNJY1iqNN3GhNt5uXqxH9Fb1tBavpWdg





Comments

  1. Thank you for sharing your workflow on this, It's been very informative! I've been trying this out myself as i want to start using it in Arch viz a little more.

    Just a question, with your bitmaps, is there a reason for using bitmap over coronabitmap? Corona bitmap gives slightly better / smoother results, so i've switched the bitmaps to corona bitmaps.

    Also for use of AO, i've created a composite material at Diffuse map to mix as a multiply with AO, Looks nice, adds a bit to the material.

    Keep up the amazing work.

    Chris

    ReplyDelete
    Replies
    1. Thank you, Chris!
      Sorry for latest response. Yes, sure! You can use corona bitmap for another and better result. I guess I need to use CoronaBitmap also!
      Main idea is combine 2 or more materials (metal and non metal) using metal PBR texture as mask

      Delete
  2. Replies
    1. Welcome!
      Glad to hear that it was be usefull for you! :)

      Delete
  3. Thank you so much for such a wonderful and detailed tutorial.

    I was wondering if their is any workflow which would work in reverse way ?
    for example if i want to extract PBR render elements from corona materials.

    one of the use of this would be creating low poly game ready assets from high poly corona based workflow.

    where the PBR Textures for low poly assets are extracted from highpoly corona material s

    ReplyDelete
  4. Hi Igor, just in case you are still have not scripted it by yourself here is simple script to recreate your template from PBR texture set (store it as pbr2corona.ms and drag to viewport to work):

    ReplyDelete

  5. fn createMaterials fpath tex_group_name ext =
    (
    format "Creating material for %\n" tex_group_name

    local _MAPBASE = 1
    local _MAPHEIGHT = 2
    local _MAPMETALLIC = 3
    local _MAPNORMAL = 4
    local _MAPROUGHNESS = 5
    local _MAPOPACITY = 6

    local map_suffixes = #("_BaseColor", "_Height", "_Metallic", "_Normal", "_Roughness", "_Opacity")
    local map_names = #("ALBEDO", "HEIGHT", "METALLIC", "NORMAL", "ROUGHNESS", "OPACITY")
    local map_bitmaps = #()

    for i = 1 to map_suffixes.count do
    (
    local path_tex = fpath + tex_group_name + map_suffixes[i] + ext
    local tbmp = undefined
    local tex_exist = false
    try
    (
    if i == 1 then
    tbmp = openBitmap path_tex gamma:#auto
    else
    tbmp = openBitmap path_tex gamma:#auto --gamma:1.0
    tex_exist = (tbmp != undefined)
    )
    catch()
    free tbmp

    local bmptex = undefined
    if not tex_exist then
    format "File % not found, skipping\n" path_tex
    else
    (
    --format "Adding %\n" path_tex

    bmptex = Bitmaptexture()
    try
    (
    bmptex.bitmap = openBitMap path_tex;
    )
    catch();
    )

    append map_bitmaps bmptex
    )


    local map_output1 = output()
    map_output1.map1 = map_bitmaps[_MAPROUGHNESS]
    map_output1.map1Enabled = true
    map_output1.output.invert = true

    local map_output2 = output()
    map_output2.map1 = map_output1
    map_output2.map1Enabled = true
    map_output2.output.RGB_Offset = -0.12

    local map_normal = CoronaNormal()
    map_normal.normalMap = map_bitmaps[_MAPNORMAL]
    map_normal.addGamma = true -- ??
    map_normal.additionalBumpOn = true
    map_normal.additionalBump = map_bitmaps[_MAPHEIGHT]

    local map_color1 = CoronaColorCorrect()
    map_color1.inputTexmap = map_bitmaps[_MAPROUGHNESS]
    map_color1.contrast = 10.0
    map_color1.exposure = 2.166
    map_color1.invert = false

    local map_color2 = CoronaColorCorrect()
    map_color2.inputTexmap = map_bitmaps[_MAPROUGHNESS]
    map_color2.contrast = 3.0
    map_color2.invert = true

    local map_mix = CoronaMix()
    map_mix.mixOperation = 11
    map_mix.mixAmount = 0.7
    map_mix.texmapTop = map_color1
    map_mix.texmapBottom = map_color2
    map_mix.topLayerContrast = 3
    map_mix.baseLayerContrast = 0

    local metMat = CoronaMtl()
    metMat.name = "met_" + tex_group_name

    local nonMetMat = CoronaMtl()
    nonMetMat.name = "nm_" + tex_group_name


    nonMetMat.texmapDiffuse = map_bitmaps[_MAPBASE]
    nonMetMat.texmapReflectGlossiness = map_output2
    nonMetMat.texmapOpacity = map_bitmaps[_MAPOPACITY]
    nonMetMat.texmapBump = map_normal

    metMat.texmapReflect = map_bitmaps[_MAPBASE]
    metMat.texmapReflectGlossiness = map_mix

    metMat.texmapOpacity = map_bitmaps[_MAPOPACITY]
    metMat.texmapBump = map_normal

    local blend_mat = Blend()
    blend_mat.name = tex_group_name + "_mtl"
    blend_mat.mask = map_bitmaps[_MAPMETALLIC]
    blend_mat.maskEnabled = true
    blend_mat.map1 = nonMetMat
    blend_mat.map1Enabled = true
    blend_mat.map2 = metMat
    blend_mat.map2Enabled = true
    blend_mat.interactive = 0
    blend_mat.useCurve = false

    metMat.fresnelIor=999.0
    nonMetMat.fresnelIor=1.6
    metMat.ior=1.52
    nonMetMat.ior=1.52
    nonMetMat.levelReflect = 1
    metMat.levelDiffuse = 0
    metMat.levelReflect = 1

    metMat.showInViewport = true
    nonMetMat.showInViewport = true

    sme.Open()
    local smev = sme.getView 1

    smev.CreateNode blend_mat [100,100]
    --ARRANGE THE VIEW
    actionMan.executeAction 369891408 "40060"

    blend_mat
    )

    fn findLast s symb = ( local r = -1; for i = s.count to 1 by -1 do ( if s[i] == symb do ( r = i; exit;) ); r)

    fn getFileBase fname =
    (
    local fnm = getFilenameFile fname
    local ff= findLast fnm "_"
    local s = ""
    if ff != -1 do
    s = substring fnm 1 (ff-1)
    s
    )


    fn main =
    (
    local fpath = getBitmapOpenFilename caption:"Please specify any file from textureset"
    local fb = getFileBase fpath
    createMaterials (getFilenamePath fpath) fb (getFilenameType fpath)
    )


    main()

    ReplyDelete
    Replies
    1. wooh! Cool! It is great idea and work! I don't have script) Now I working with little bit different workflow :) Maybe I will post about this later :)

      Delete
  6. Didn't found your email so posted here. Your template helped me a lot, but I use 3dsmax 2014 so I had to install 2018 trial, read your template params and script them. In case code above doesn't work because of site formatting , here is drive link: https://drive.google.com/file/d/15h5bMNptFCnZekSXsP7kHcl0WmHc3L6o/view?usp=sharing

    ReplyDelete

Post a Comment

Popular posts from this blog

Wooden wine barrels | PBR Low-Poly 3D model