Component Shaders

Fast Scatter

This is the main shader that does the actual scattering. It is highly modular and works with several plug-in shaders, and it can even be cascaded into itself for multi-layer scattering (as is done in misss_fast_skin_phen). It layers the results from the plug-in shaders with the scattered light from the lightmap (optionally nonlinearly, in what is known as "screen" transfer mode in various compositing applications) and presents the result as a final composited color.

misss_fast_shader
color "misss_fast_shader" (
    color texture   "lightmap",
    color texture   "depthmap",
    shader          "bump",
    shader          "diffuse_illum",
    color           "diffuse_color",
    shader          "specular_illum",
    scalar          "diffuse_weight",
    color           "front_sss_color",
    scalar          "front_sss_weight",
    scalar          "front_sss_radius",
    color           "back_sss_color",
    scalar          "back_sss_weight",
    scalar          "back_sss_radius",
    scalar          "back_sss_depth",
    scalar          "scale_conversion",
    boolean         "screen_composit",
    boolean         "output_sss_only",
    scalar          "falloff",
    integer         "samples"
    shader          "fallback_shader")
lightmap
depthmap
are the light and depthmap pair from which to extract the data. For more details, read about misss_lightmap_write and the section on Automatic lightmap generation.
bump
is a shader that perturbs the normal. While one could use a shader list and something like mib_bump_passthrough before this shader, for large scattering radii it is preferred that the shader is aware of the normal vector before bump mapping. When a bump mapping shader is assigned to this parameter instead, misss_fast_shader will know the normal both before and after bump mapping.
diffuse_illum
passes any normal illumination shader (returning a color) for the diffuse illumination, generally a named shader based on mib_illum_lambert. If nothing is passed, it automatically defaults to Lambert.
diffuse_color
is an overall color that is applied to all diffuse light, including the scattered contributions.
specular_illum
passes any normal illumination shader (returning a color) for the specular and reflective components. If nothing is passed, no specular shading happens. This is layered on top of any diffuse contributions.
diffuse_weight
is a simple scalar multiplier for the color returned by the diffuse_illum shader, for easier tweaking.
front_sss_color
front_sss_weight
are the color and weight for the front surface scattering.
front_sss_radius
is the scatter radius in the front surface. Light will scatter this distance (in whatever units the model is made) along the surface.
back_sss_color
back_sss_weight
are the color and weight of the back surface (or through) scattering.
back_sss_radius
is the scatter radius and back_sss_depth the depth in the back surface. Generally, the radius and depth are set to the same value (and if the depth is not specified, it defaults to the radius) but can be set separately for increased control.
scale_conversion
is a simple utility function allowing linear division of all distances. Since scattering is distance dependent, loading a material designed for a model made in inches will not work on a model where the unit is meters, and vice versa. Here one can pass the conversion factor.
screen_composit
when turned on, chooses Screen compositing. When simply adding together the contribution of many layers of light, it is very easy to quickly blow out and overexpose into white, but the human eye is inherently nonlinear and perceives intensities in a different way. This option allows use of what is known in many compositing applications as a screen transfer mode between the layers, which yields a softer, more pleasing result. If it is turned off, normal addition is used. If rendering in a high dynamic range, and a proper tone-operator is applied in the final output stage already compressing the final luminance, use off. If not, turning this option on yields a more pleasing result.
output_sss_only
is for debugging and testing or for preparing for external compositing; If it is on, only the scattered contribution is shown.
falloff
sets the shape of the distance falloff along the scatter radius. Higher values yield a sharper falloff, and lower values a smoother falloff, but also make the perceived scatter distance shorter, so one must compensate by increasing the actual scatter distance for a slightly softer look. For high values (1.0 to 10.0), almost all samples within the scatter radius are weighted equally. For low values (0.1 to 1.0), the samples near the edge of the scatter radius are weighted a less.
samples
sets how many samples from the lightmap are considered (maximum) per rendered ray, ideally, a power of two. 32 is probably the lowest useful value, 128 is plenty.
fallback_shader
is a shader used for cases where no stored lightmap samples can be found within the scatter radius. If this parameter is not set, a built-in Lambert shader is used. If this parameter is set, the value returned by the attached shader is used. For best results, this should be the same shader used as lightmap sampling shader in the lightmapping stage.
misss_fast_shader_x
struct {
    color "result",           # composited color

    color "diffuse_result",   # diffuse layer
    color "diffuse_raw",
    color "diffuse_level",

    color "specular_result",  # specular is not altered by the shader, but
                              # passed through from "specular_illum" sub-shader

    color "front_result",     # the "front" SSS layer
    color "front_raw",
    color "front_level",

    color "back_result",      # the "back" SSS layer
    color "back_raw",
    color "back_level"
}
"misss_fast_shader_x" (
    color texture   "lightmap",
    color texture   "depthmap",
    shader          "bump",
    shader          "diffuse_illum",
    color           "diffuse_color",
    shader          "specular_illum",
    scalar          "diffuse_weight",
    color           "front_sss_color",
    scalar          "front_sss_weight",
    scalar          "front_sss_radius",
    color           "back_sss_color",
    scalar          "back_sss_weight",
    scalar          "back_sss_radius",
    scalar          "back_sss_depth",
    scalar          "scale_conversion",
    boolean         "screen_composit",
    boolean         "output_sss_only",
    scalar          "falloff",
    integer         "samples",
    shader          "fallback_shader")

This shader has identical behavior to misss_fast_shader but provides individual components of the shading results as output values before compositing them into the final color value. This supports multi-channel rendering approaches where compositing is performed in external packages.

Fast Scatter 2

misss_fast_shader2

This is an updated and slightly more physical version of the fast scatter shaders. The primary differences is that scatter radii are defined per color (with individual scatter radii for the red, green and blue components). Also, the falloff in energy of the light is always exponential, unlike the older misss_fast_shader which has an explicit parameter to modify the falloff.

The primary benefit with this new shader is that it allows a more realistic effect, since scattering in the real world is exponential, and wavelength-dependent. This also lowers the number of scattering layers needed for a realistic effect; in the past at least two layers were needed to simulate skin, to allow the red color to scatter further. This is no longer necessary with this new shader (although multiple can still be used for greater artistic control.)


Comparison between old (left) and new (right) shaders

On the left we see the older shader. Light that bleeds into the shadow is uniform in color (gray in this image), and light bleeding through the object is red only due to the fact that the default back_sss_color is red. In contrast, on the right, we see the wavelength dependent scattering. Light that scatters into the shadow have a range of colors from white to yellow to red, which is also true for light scattering through the object. These red-shifts exists because the red, green and blue scatter radii are different; in the right image, all scatter colors are set to white.

Here are the parameters of misss_fast_shader2:

    color "misss_fast_shader2" (
        color texture "lightmap",
        color texture "depthmap",
        shader        "bump",
        shader        "diffuse_illum",
        color         "diffuse_color"    default 1 1 1,
        shader        "specular_illum",
        scalar        "diffuse_weight"       default 0.5,
        
        color         "front_sss_color"      default 0.8 0.8 0.8,
        scalar        "front_sss_weight"     default 0.5,
        vector        "front_sss_radius"     default 20 10 5,
        color         "front_sss_radius_mod" default 1 1 1,

        color         "back_sss_color"       default 0.8 0.8 0.8,
        scalar        "back_sss_weight"      default 0.5,
        vector        "back_sss_radius"      default 20 10 5,
        color         "back_sss_radius_mod"  default 1 1 1,

        scalar        "back_sss_depth",      # unassigned (zero) means "same as radius"
        scalar        "sampling_radius_mult" default 3.0,
        
        scalar        "scale_conversion"     default 1.0,
        boolean       "screen_composit"      default off,
        boolean       "output_sss_only",        
        integer       "samples"           default 64,
        shader        "fallback_shader"
    )
Most parameters are identical in behavior to misss_fast_shader with these exceptions and notes:
front_sss_radius
is not a scalar but a vector, with three different radii, for the red, green and blue light respectively. Generally, red scatters the most, green less, and blue very little. Note that the falloff is exponential and has no hard stop (unlike the old shader), so the value set here is at which distance the light has diminished to 10 precent of its original intensity, not where the intensity is zero.
front_sss_radius_mod
is a color parameter allowing the modification of the scatter radii. This exists to ease applying a texture map for changing the scatter radii across the surface; the texture can vary within a normal black-to-white range, which is multiplied by the values set in the front_sss_radius parameters.
back_sss_radius
is a vector with three different radii for the red, green and blue component of the back scattering. Values work the same as front_sss_radius.
back_sss_radius_mod
is a radius modification input, working the same as front_sss_radius_mod.
sampling_radius_mult
is a multiplier for the largest radii set in either of the front_sss_radius and back_sss_radius for within which any samples are actually taken. So if the largest of any these radii is e.g. 10 units, setting this parameter to 2.0 will cause samples to actually be taken within 20 units distance, completely ignoring any light outside that radius. Setting this value too small, can yield a visible hard cutoff to the scattering. Setting it too large, and too many samples are wasted in far away samples with extremely small contribution; since the falloff is exponential, and the scattering radii parameters are defined as "distance until 10 percent contribution" the furthest samples would have a weight of 10 percent raised to the power of this parameter (2 = 1 percent, 3 = 0.1 percent, 4 = 0.01 percent etc)
misss_fast_shader2_x
struct {
    color "result",           # composited color

    color "diffuse_result",   # diffuse layer
    color "diffuse_raw",
    color "diffuse_level",

    color "specular_result",  # specular is not altered by the shader, but
                              # passed through from "specular_illum" sub-shader

    color "front_result",     # the "front" SSS layer
    color "front_raw",
    color "front_level",

    color "back_result",      # the "back" SSS layer
    color "back_raw",
    color "back_level"
}
"misss_fast_shader_x" (
        color texture "lightmap",
        color texture "depthmap",
        shader        "bump",
        shader        "diffuse_illum",
        color         "diffuse_color"    default 1 1 1,
        shader        "specular_illum",
        scalar        "diffuse_weight"       default 0.5,
        
        color         "front_sss_color"      default 0.8 0.8 0.8,
        scalar        "front_sss_weight"     default 0.5,
        vector        "front_sss_radius"     default 20 10 5,
        color         "front_sss_radius_mod" default 1 1 1,

        color         "back_sss_color"       default 0.8 0.8 0.8,
        scalar        "back_sss_weight"      default 0.5,
        vector        "back_sss_radius"      default 20 10 5,
        color         "back_sss_radius_mod"  default 1 1 1,

        scalar        "back_sss_depth",      # unassigned (zero) means "same as radius"
        scalar        "sampling_radius_mult" default 3.0,
        
        scalar        "scale_conversion"     default 1.0,
        boolean       "screen_composit"      default off,
        boolean       "output_sss_only",        
        integer       "samples"           default 64,
        shader        "fallback_shader"
    )
This shader is identical in behavior to misss_fast_shader2 but with the multiple outputs as described in misss_fast_shader_x.

Shader Usage

The misss_fast_shader(..) family of shaders conceptually work with the layering of several light contributions, all stacked on top of each other. The actual compositing can be done with simple addition or with the softer looking screen compositing.


Conceptual layering of misss_fast_shader

Plug-in shaders provide the actual contribution for the various layers. bump, diffuse_illum and specular_illum are the main plug-in shaders that provide the shading model.

The bump shader affects the surface normal and is called before the "... _illum" shaders and hence affects their shading. However, no bump mapping is performed on the scattered light, since this happens under the surface. It is possible to include the effect of bump mapping in the light before it is scattered by including a bump map shader in the lightmapping phase.

To create the subsurface scattering itself, light from specially prepared lightmaps is gathered, weighted by distance, and tinted. The whole stack is finally layered together as follows, from top to bottom.

The following two observations are noteworthy: First, keep in mind that the contributions from layers 2, 3 and 4 are all multiplied with the " diffuse_color" parameter as an overall tinting and attenuation color for the diffuse contributions. Second, since the plug-in shaders are simply called and layered in, it is possible to cascade several shaders together to create multiple layers as follows:


Cascading of misss_fast_shader

This graph shows how a 2nd iteration of misss_fast_shader is used as the diffuse_illum parameter of the 1st. This works because the scattering function receives its diffuse illumination from the lightmaps, and does not care about what diffuse_illum actually returns. It simply layers it into the mix.

This is precisely how the skin Phenomenon is implemented. A second shader is cascaded into the first, giving an extra layer. In principle, there is nothing preventing the stacking of an arbitrary number of shaders.

Lightmap Creation

This is the lightmapping shader. It is required for the fast subsurface scattering to work [1]. It creates a lightmap and stores the front and back surfaces, their depth, and irradiant light intensities in one or more specially formatted lightmaps. Two modes of behavior are supported:

misss_lightmap_write
struct {
    vector "point",
    vector "normal"
}
"misss_lightmap_write" (
    color texture   "lightmap",
    color texture   "depthmap",
    string          "lightmap_group",
    scalar          "lightmap_size",
    integer         "write_lightmap",
    scalar          "scatter_bias",
    shader          "input")
lightmap
should point to a writable color texture and depthmap be unassigned or both should be assigned to a pair of Phenomenon interface parameters as detailed in Automatic lightmap generation.
lightmap_group
is a string with a scatter group name with automatic lightmap generation. All objects and materials that use the same scatter group will scatter light into each other.
lightmap_size
is the size, in percent of render size, for the automatically generated lightmap.
write_lightmap
is currently reserved for future use.
scatter_bias
adjusts the light in the lightmap to favor back scattering (light from behind the camera scatters back towards the camera) when using negative values and forward scattering when using positive values. The technical range is -1 to 1, but generally only small values (-0.2 to 0.2) make visual sense.
input
is the shader that actually samples the lighting in the model for the lightmap. Generally misss_lambert_gamma is used, but any illumination shader can be used, for example mib_illum_lambert or even experiment with mib_illum_phong and scattering of specular reflections.

Lambert Illumination

This is the supplied lightmap sampling shader. Any illumination shader can be used like mib_illum_lambert but this one is specially tuned for the job and has additional options for lightmap gamma correction, normal flipping and indirect light inclusion.

misss_lambert_gamma
color "misss_lambert_gamma" (
    color           "ambient",
    color           "ambience",
    color           "diffuse",
    boolean         "indirect",
    scalar          "diffuse_curve",
    integer         "flip",
    integer         "mode",
    array light     "lights")
diffuse
is the diffuse color.
ambient
ambience
are multiplied with each other to yield a final contribution of ambient light.
indirect
if on, will cause indirect illumination (such as final gathering and photons) to be included in the lightmap, at the expense of increased rendering time.
diffuse_curve
is the gamma curve for diffuse light. The Lambertian cosine is raised to the power of this value (i.e. pow(dot_nl, diffuse_curve)) to flatten (for values less than 1.0) or narrow (for values above 1.0) the curve for greater control.
flip
can be one of the following: 0, normals are not flipped; 1, normals are flipped; or 2, both the unflipped and flipped-normal sides are lightmapped. This can be useful for translucency in thin objects such as leaves.
mode
is the mode selector for the light lists.
lights
list of lights directly linked to the shader.

Specular Skin

This is a function geared towards recreating the peculiar specular characteristics of skin. It contains two specular highlights and glossy reflections with edge enhancement.

The shader can be used anywhere where specular highlights are needed. It has no diffuse component and hence needs to be layered together with another shader that provides the diffuse shading.

misss_skin_specular
color "misss_skin_specular" (
    scalar          "overall_weight",
    scalar          "edge_factor",

    color           "primary_spec_color",
    scalar          "primary_weight",
    scalar          "primary_edge_weight",
    scalar          "primary_shinyness",

    color           "secondary_spec_color",
    scalar          "secondary_weight",
    scalar          "secondary_edge_weight",
    scalar          "secondary_shinyness",

    scalar          "reflect_weight",
    scalar          "reflect_edge_weight",
    scalar          "reflect_shinyness",
    boolean         "reflect_environment_only",

    integer         "mode",     
    array light     "lights")
overall_weight
is the overall level of specularity and reflections. Generally, any specularity map is included here and will affect the level of all specularity options that follow below.
edge_factor
sets the edge width of the edge reflection effects. Skin reflects more when watched in angles nearly perpendicular to it (known as a "Fresnel effect") and this parameter sets the narrowness of this edge. Higher values yield a thinner edge. This edge width applies to all the edge weights listed below.
primary_spec_color
primary_spec_weight
are the color and base weight for the first layer of specularity. The skin specularity functions are two-layered, allowing simulation of both the broad soft specularity of skin and any near-reflective specularities of top layer oiliness and wetness.
primary_edge_weight
sets the additional multiplier for the edge, where final specularity at the edge is the sum of weight and edge weight.
primary_shinyness
is the specular exponent (higher values yield a smaller and sharper specular highlight, which is a modified Phong with edge softening).
secondary_spec_color
secondary_spec_weight
secondary_edge_weight
secondary_shinyness
work exactly like the parameters that begin with primary_ and are for the second layer of specularity.
reflect_weight
reflect_edge_weight
the weight and edge weight for reflections. If it is nonzero, then actual (glossy) reflections are added.
reflect_shinyness
is the shinyness value for glossy reflections. When it is 0.0, standard raytraced mirror reflections are used, but for nonzero values glossy reflections are generated, which increases render time.
reflect_environment_only
if true only the current environment map is sampled for reflections, and no actual rays are traced.
mode
is the mode selector for the light lists.
lights
array of lights directly linked to the shader.

Call Shader

This is a utility "pass through" shader for Phenomenon building. It allows passing shaders as parameters to material Phenomena for items such as environment, photons, and displacement.

misss_call_shader
color "misss_call_shader" (
    shader  "shader",
    shader  "default_shader",
    integer "mode")
shader
is the shader to be called.
default_shader
is the shader that is called if shader is not specified.
mode
is the shader calling mode, where 0 is "automatic". Any other number maps to a shader calling mode miShader_type. See the shader.h include file.

Here is an example in pseudo code of using this shader in a Phenomenon:

declare phenomenon 
    material "my_phenomenon" (
        color       "my_special_color",
        scalar      "my_size",
        shader      "optional_environment",
        ...
    )
    shader "default_environment" "...." (
        .... some environment shader ...
    )
    shader "env" "misss_call_shader" (
        # call the passed shader
        "shader"    = interface "optional_environment",
        # if none was passed, call our default
        "default_shader" "default_environment"
    )
    environment = "env" 
end declare

[1] The sample shader, misss_lambert_gamma is optional. Any illumination shader can be used.

Copyright © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.