Emulating mia_material

As we saw already in the previous page, mia_material reflection behavior can be emulated exactly. As a matter of fact, almost every aspect can be simulated, and a Phenomenon could be built to mimic the behavior of mia_material for most settings.

The trick is perhaps that mia_material has several switches that turn features on or off, and in general this may need to be simulated with different layering setups. For example, mia_material inherently behaves differently if "thin_walled" mode is on or off - for the layering shaders, the "thin_walled" option is on the mila_material. And the cutout feature is implemented as visibility, yet any given layer could have transperency as a component.

The following is a listing for a mia_material "behave-a-like" Phenomenon called mila_layer_mia_material.

This is just an example of something like an mia_material could be made. It is probably more optimal to use the layering shaders directly, but if one has a scene where one wants to mix existing mia_materials, this could help.

declare phenomenon
    color "mila_layer_mia_material" (
        scalar  "diffuse_weight"      default 1.0, #: min 0.0 max 1.0
        color   "diffuse"             default 0.5 0.5 0.5,
        scalar  "diffuse_roughness"   default 0.0, #: min 0.0 max 1.0

        scalar  "reflectivity"        default 0.6, #: min 0.0 max 1.0
        color   "refl_color"          default 1.0 1.0 1.0,
        scalar  "refl_gloss"          default 1.0, #: min 0.0 max 1.0
        scalar  "refl_gloss_quality"  default 1.0, #: min 0.0 softmax 4.0

        scalar  "transparency"        default 0.0, #: min 0.0 max 1.0
        color   "refr_color"          default 1.0 1.0 1.0,
        scalar  "refr_gloss"          default 1.0, #: min 0.0 max 1.0
        scalar  "refr_ior"            default 1.4, #: min 0.1 softmax 2.0
        scalar  "refr_gloss_quality"  default 1.0, #: min 0.0 softmax 4.0
        boolean "refr_translucency"   default off,
        color   "refr_trans_color"    default 0.7 0.6 0.5,
        scalar  "refr_trans_weight"   default 0.5, #: min 0.0 max 1.0

        scalar  "anisotropy"          default 1.0, #: min 0.1 softmax 10
        scalar  "anisotropy_rotation" default 0.0, #: softmin 0 softmax 1
        integer "anisotropy_channel"  default -1,  #: min -1  softmax 64

        integer "brdf_fresnel_mode"    default 1,  #Custom curve (aka manual), while 0 Fresnel uses refr_ior
        scalar  "brdf_0_degree_refl"   default 0.2, #: min 0.0 max 1.0
        scalar  "brdf_90_degree_refl"  default 1.0, #: min 0.0 max 1.0
        scalar  "brdf_curve"           default 5.0, #: min 0.1 softmax 20

        # Reflection/Refraction optimizations & falloffs

        boolean  "refl_falloff_on"       default off,
        scalar   "refl_falloff_dist"     default 0.0,
        boolean  "refl_falloff_color_on" default off,
        color    "refl_falloff_color"    default 0 0 0,

        boolean  "refr_falloff_on"       default off,
        scalar   "refr_falloff_dist"     default 0.0,
        boolean  "refr_falloff_color_on" default off,
        color    "refr_falloff_color"    default 0 0 0,

        # Factors

        scalar   "indirect"              default 1.0,  #: min 0 softmax 1.0

        # Built in AO
        
        scalar   "quality"        default 1.0,          #: min 0.0 softmax 2.0

        # Only one bump input
        vector   "overall_bump"
    )
    
    shader "refl_roughness" "mila_get_roughness" ("glossiness" = interface "refl_gloss")
    # Reflections
    shader "reflection" "mila_glossy_reflection" (
        "roughness"       = "refl_roughness",
        "quality"         = interface "refl_gloss_quality",

        "anisotropy"      = interface "anisotropy",
        "aniso_angle"     = interface "anisotropy_rotation",
        "aniso_channel"   = interface "anisotropy_channel",
        
        "use_max_dist"       = interface "refl_falloff_on",
        "max_dist"           = interface "refl_falloff_dist",
        "use_max_dist_color" = interface "refl_falloff_color_on",
        "max_dist_color"     = interface "refl_falloff_color",
    )

    shader "refr_roughness" "mila_get_roughness" ("glossiness" = interface "refr_gloss")    
    # Refractions
    shader "refraction" "mila_glossy_transmission" (
        "roughness"       = "refr_roughness",
        "quality"         = interface "refr_gloss_quality",
        "ior"             = interface "refr_ior",
        
        "anisotropy"      = interface "anisotropy",
        "aniso_angle"     = interface "anisotropy_rotation",
        "aniso_channel"   = interface "anisotropy_channel",
        
        "use_max_dist"       = interface "refr_falloff_on",
        "max_dist"           = interface "refr_falloff_dist",
        "use_max_dist_color" = interface "refr_falloff_color_on",
        "max_dist_color"     = interface "refr_falloff_color"        

    )

    # Translucency
    shader "translucency" "mila_diffuse_transmission" (
        "tint"            = interface "refr_trans_color",
        "indirect"        = interface "indirect_multiplier"
    )    

    # Diffuse
    shader "diffuse" "mila_diffuse_reflection" (
        "roughness"        = interface "diffuse_roughness",
        "indirect"         = interface "indirect_multiplier",
        "quality"          = interface "quality"
    )

    # Transparency and Translucency live in a 
    # separate "sub layers" because they steal
    # energy from eachother

    shader "transmission" "mila_layer" (
        "layers" [
            {
                "shader" "translucency",
                "weight_tint" 1 1 1,
                "weight"  = interface "refr_trans_weight",
		"use_directional_weight" off,
                "on"      = interface "refr_translucency"
            },
            {
                "shader" "refraction",
                "weight_tint" 1 1 1, 
                "weight" 1,
		"use_directional_weight" off,
                "on" on
            }
        ]
    )

    #
    # The main layers, mimicking mia_materials
    # energy conservation logic
    #

    shader "mia_layers" "mila_layer" (
        "layers" [
            {
                "shader" "reflection",   # Reflection layer
                "weight_tint"          = interface "refl_color",
                "bump"                 = interface "overall_bump",
                "weight"               = interface "reflectivity",
		"use_directional_weight" on,
                "directional_weight_mode" = interface "brdf_fresnel_mode",
                "normal_reflectivity"  = interface "brdf_0_degree_refl",
                "grazing_reflectivity" = interface "brdf_90_degree_refl",
                "exponent"             = interface "brdf_curve",
                "ior"                  = interface "refr_ior",
                "on" on
            },
            {
                "shader" "transmission", # Transparency+Translucency
                "bump"                 = interface "overall_bump",
                "weight_tint"          = interface "refr_color", 
                "weight"               = interface "transparency",
		"use_directional_weight" off,
                "on" on
            },
            {
                "shader" "diffuse",      # Diffuse
                "bump"                 = interface "overall_bump",
                "weight_tint"          = interface "diffuse", 
                "weight"               = interface "diffuse_weight",
		"use_directional_weight" off,
                "on" on
            }
        ]
    )

    root = "mia_layers"
    
    apply material, texture, shadow, photon
    version 1
end declare

mia_material_emulator has the same parameters as mia_material(_x) with the following exceptions. Some of these differences could be hidden in a user interface or with simple mapping-shaders

These parameters from mia_material are missing or different:

cutout_opacity
should be input directly to the mila_material "visibility" input.
brdf_fresnel
is boolean switch in mia_material. With mila_layer, we first choose whether or not we have directionally-dependent weight with "use_directional_weight", then if "on", we can select which directionally-dependent weight mode from currently two values (0 = Fresnel, 1 = Custom Curve). When using directionally dependent weight, the value 1 matches the old parameters "off" value, and the value 0 matches it's "on" value. In the mia_material in order to get non-directionally-dependent weight, one had to adjust the Custom Curve inputs, because it was always directionally dependent.
refl_is_metal
is missing - the same effect is achieved by having the same reflection color as diffuse color.
brdf_conserve_energy
is missing; these shaders always conserve energy.
refl_gloss
refr_gloss
have different ranges; by default the layering roughness behaves inversely similar to the glossiness parameter for mia_material specular highlights. However, the curve should behave in a more linearly fashion visually for changing roughness. There is one more option that allows you to change the exponent of that curve (current default of 3) in order to adjust how the roughness maps to the blurriness of the material. See mila_glossy_reflection for more detail.
overall_bump
standard_bump
no_diffuse_bump
bump_mode
are replaced by a single bump input overall_bump. Different variants of this Phenomenon could easily be written to support the various variants of these switches (e.g. separate diffuse bump input).
multiple_outputs
are implicitly always on in the layering shaders.
refl_interpolate
refl_hl_only
refl_interpolate
intr_*
fg_quality*
no_visible_area_hl
do_refractive_caustics
skip_inside_refl
backface_cull
hl_vs_refl_balance
additional_color
mode
lights
all refer to features unsupported by this phenomena, or the layering shaders.

Image example

Emulating Car Paint

Emulating the Car Paint shaders is actually more difficult, but generally because the car paint shaders are older and much less physical. This emulation will not be visually exact - it will rather be more realistic looking and much more physically plausible. The old car paint Phenomenon has the following problems:

It makes more sense to try clone the more "sensible" parameters for the car paint and build a new more physically correct Phenomenon, which retains some of the features of the old shaders, but that is much more realistic. Here is one attempt at such a Phenomenon - other versions could exist:

declare phenomenon
    color "mila_layer_car_paint" 
    (
        color   "base_color"             default 0.8 0.1 0,
        color   "edge_color"             default 0 0 0,
        scalar  "edge_color_bias"        default 1.0,
        color   "lit_color"              default 0.6 0 0.2,
        scalar  "diffuse_weight"         default 1.0,

        color   "flake_color"            default 1 1 1,
        scalar  "flake_weight"           default 1.0,

        scalar  "flake_density"          default  0.8,
        scalar  "flake_strength"         default  0.8,
        scalar  "flake_scale"            default 0.1,
        integer "flake_type"             default  0,
        integer "flake_cell_style"       default 0,
        scalar  "flake_cell_size"        default  0.3,
        
        # New - more physical - parameters
        scalar  "flake_roughness"        default 0.4,

        scalar  "glossy_paint_weight"    default 0.1,
        scalar  "glossy_paint_roughness" default 0.6,
        
        color   "clearcoat_1_color"      default 1 1 1,
        scalar  "clearcoat_1_weight"     default 1.0,
        scalar  "clearcoat_1_roughness"  default 0.0,
        
        color   "clearcoat_2_color"      default 1 1 1,
        scalar  "clearcoat_2_weight"     default 0.0,
        scalar  "clearcoat_2_roughness"  default 0.4,
        
        scalar  "clearcoat_ior"          default 1.8,
        
        scalar  "quality"                default 1.0,
        scalar  "max_distance"           default 0.0,

        # Dirt
        color   "dirt_color"             default .3 .3 .3,
        scalar  "dirt_weight"            default 0.0,

        scalar  "irradiance_weight"      default 1.0,
    )

    shader "flakes"  "mila_bump_flakes" (
        "weight"    = interface "flake_weight",
        "scale"    = interface "flake_scale",
        "perturbation" = interface "flake_strength",
        "density"  = interface "flake_density",
        "type"    = interface "flake_type",
        "circle_size"  = interface "flake_cell_size",
        "cell_style" = interface "flake_cell_style",

    )
    
    shader "dirt" "mila_diffuse_reflection" (
        "tint"  = interface "dirt_color",
        "indirect" = interface "irradiance_weight"
    )

    shader "clearcoat_2" "mila_glossy_reflection" (
        "roughness" = interface "clearcoat_2_roughness",
        "quality"   = interface "quality"
    )

    shader "clearcoat_1" "mila_glossy_reflection" (
        "roughness" = interface "clearcoat_1_roughness",
        "quality"   = interface "quality"
    )

    shader "flakes_gloss"  "mila_glossy_reflection" (
        "tint"      = interface "flake_color",
        "roughness" = interface "flake_roughness",
        "quality"   = interface "quality"
    )

    shader "glossy_paint" "mila_glossy_reflection" (
        "roughness"      = interface "glossy_paint_roughness",
        "quality"        = interface "quality"
    )
    
    shader "edge_diffuse" "mila_diffuse_reflection" (
        "tint"   = interface "edge_color",
        "indirect"  = interface "irradiance_weight"
    )

    shader "main_diffuse" "mila_diffuse_reflection" (
        "tint"   = interface "base_color",
        "indirect"  = interface "irradiance_weight"
    )

    shader "mia_layers" "mila_layer" (
        "layers" [
            {
                "shader"               "dirt",
                "weight"               = interface "dirt_weight",
                "weight_tint"          1 1 1,
                "on" on
            },
            {
                "shader"               "clearcoat_1",
                "weight"               = interface "clearcoat_1_weight",
                "weight_tint"          = interface "clearcoat_1_color",
		"use_directional_weight" on,
                "directional_weight_mode" 0,
                "ior"                  = interface "clearcoat_ior",
                "on" on
            },
            {
                "shader"               "clearcoat_2",
                "weight"               = interface "clearcoat_2_weight",
                "weight_tint"          = interface "clearcoat_2_color",
		"use_directional_weight" on,
                "directional_weight_mode" 0,
                "ior"                  = interface "clearcoat_ior",
                "on" on
            },
            {
                "shader"               "flakes_gloss",
                "weight"               = "flakes.visibility",
                "weight_tint"          1 1 1,
                "bump"                 = "flakes.normal",
                "on" on
            },
            {
                "shader"               "glossy_paint",
                "weight"               = interface "glossy_paint_weight",
                "weight_tint"          = interface "lit_color",
                "on" on
            },
            {
                "shader"               "edge_diffuse",
                "weight"               = interface "diffuse_weight",
                "weight_tint"          1 1 1,
                "use_directional_weight" on,
                "directional_weight_mode" 1,
                "normal_reflectivity"  0.0,
                "grazing_reflectivity" 1.0,
                "exponent"  = interface "edge_color_bias",
                "on" on
            },
            {
                "shader"               "main_diffuse",
                "weight_tint"          1 1 1,
                "weight"               = interface "diffuse_weight",
                "on" on
            }
        ]
    )

    root = "mia_layers"
    
    apply material, texture, shadow, photon
    version 2
end declare

This Phenomenon is built from these 7 layers (top to bottom):

These are the parameters of the shader:

base_color
edge_color
edge_color_bias
diffuse_weight
all behave like in the original car paint Phenomenon (see car paint library documentation).
lit_color
has a slightly different behavior, but retains it's name. What in the old shaders was faked as a special kind of colored highlight, this is actually the color of a new colored glossy reflection layer.
flake_color
flake_weight
flake_density
flake_strength
flake_scale
All work essentially the same as the original car paint Phenomenon (see car paint library documentation).
flake_roughness
is the roughness of the flakes in the 0-1 range.
glossy_paint_weight
glossy_paint_roughness
is weight and roughness of the new "colored glossy paint" layer, that uses the lit_color as it's reflection color.
clearcoat_X_color
clearcoat_X_weight
clearcoat_X_roughness
clearcoat_ior
create two true glossy layers for clearcoat. They automatically reflect correctly, and the fresnel effect is always applied (using an IOR of clearcoat_ior). Most of the old confusing parameters that had separate controls for highlights and reflections are gone, as are all the strange settings for "edge" and "base" weights of highlights/reflections, which were only there to simulate fresnel effects anyway.
max_distance
dirt_color
dirt_weight
irradiance_weight
...all work the same as before.

Obsolete parameters from the old Phenomenon that has been removed::

lit_color_bias
Roughly replaced with glossy_paint_roughness
flake_reflect
flake_exp
Flakes now always reflect physically. Replaced by flake_roughness
flake_decay
global_weight
Not supported by this Phenomenon.
ambient
diffuse_bias
reflection_color
edge_factor
reflection_edge_weight
reflection_base_weight
glossy_spread
spec_*
All these are either nonphysical or in a strange range. They are replaced by glossy layers with roughness parameters instead, which inherently always reflect things (i.e. all separate settings for reflections are removed) and follow a fresnel reflectivity curve.
mode
lights
Does not apply to the layering shaders.

Image example