Skin shader

From Bohemia Interactive Community
Jump to navigation Jump to search

Motivation, goal


Head model with skin shader
SkinShader01.jpg

Skin Shader imitating human skin with the aid of layers with diverse lighting diffusion. It's type of method like "fake subsurface scattering". Result should be similar like "SSS Fast Skin" material in Mental Ray.

Skin effect applies only to surface defined by masc (A-channel of SDM texture), on rest of surface is acts nearly as Super Shader.

Material is composed from 3 layers: unscattered, epidermal, subdermal. All 3 layers got mutual normal texture but differs by color.

unscattered - layer color is given by product of color from EP texture and color "unscattered color'

epidermal - layer color is given by EP texture

subdermal - layer color is given by SDM texture


Skin effects within preexposure by main light - individual layers got weight set to 1 in order that they were seen nicely (shown with aid of tuning parameters of CgFX version of Skin Shader for Maya)
SkinShader02.jpg


Material parameters

unscatteredColor - modulation color for layer "unscattered"; default value [0.8, 0.9, 1.0]

unscatteredWeight, epidermalWeight, subdermalWeight - scales of individual layers; sum total should be approximately 1; it is possible set in interval <0.0, 1.0>; default values for standalone layers : 0.1, 0.4 and 0.5

epidermalMul, epidermalAdd - parameters defining light scattering inside epidermal layer; values in intervals <0.0, 2.0> and <-1.0, 1.0>; default values 0.8 and 0.2

subdermalMul, subdermalAdd - same meaning like with epidermal layer; default values 0.65 and 0.35

darkRimFactorEp, darkRimFactorSu - light decrease factor in accordance to angle between sight direction and normal line (something like "inverse fresnel"); values are in interval <0.0, 1.0>; default values: 0.3 and 0.7


Mask display generate by "dark rim" factor (gradually from from left: dark rim factor = 0.0, 0.5 and 1.0)
SkinShader03.jpg


hemisphericSpecLevel - reflection intensity from hemispheric light; <0.0, 1.0>; default value 0.5

Definition of texture stages in material

0. Epidermal/Color map

1. Normal map (NO, NOHQ)

Normal map of type _NO or _NOHQ.

texture="#(argb,8,8,3)color(0.5,0.5,1,1)";

2. Macro map (MC)

Used same as with SuperShader.

texture="#(argb,8,8,3)color(0,0,0,0)";

3. Subdermal map and mask (SDM)

RGB channels contains color for subdermal layer. Within alpha change is mask which determine skin effect usage.

texture="#(argb,8,8,3)color(0,0,0,0)";

4. AmbientShadow map (AS)

Used same as with SuperShader.

texture="#(argb,8,8,3)color(0,1,1,1)";

5. Specular map (SMDI)

Specular map of type _SMDI. On the contrary map of type _SM isn't supported.

6. Fresnel function

Fresnel function is entered as procedural texture in following form: texture="#(ai,64,1,1)fresnel(N,K)";. For detailed see Super shader.

7. Environmental map

For the moment it is not used! Environmental reflection is replaced by hemispherical light reflection.


Temporary material solution

Because it is not possible easily prepare GUI for specific Skin Shader parameters (unscatteredWeight, epidermalWeight, epidermalMul, darkRimFactorEp...), let's use temporary solution.

unscattered layer color - constantly set to RGB = (0.6, 0.8, 1.0)

unscattered weight, epidermal weight, subdermal weight, hemis. specular level - parameters will read from RGBA components of color Forced Diffuse

epidermal mul par., epidermal dark rim factor, subdermal mul par., subdermal dark rim factor - parameters will read from RGBA of color Emissive

epidermal add par. - value obtained by calculation: 1 - epidermal mul par.

subdermal add par. - value obtained by calculation: 1 - subdermal mul par.


RGBA components meaning of colors Forced Diffuse and Emissive for Skin Shader (default values inside brackets):
SkinShaderTempGUI01.jpg

Example of temporary ".rvmat" file

Specific parameters of Skin Shader are in Forced Diffuseand Emissive.

ambient[]={1.000000,1.000000,1.000000,1.000000};
diffuse[]={1.000000,1.000000,1.000000,1.000000};
forcedDiffuse[]={0.200000,0.400000,0.400000,0.500000};
emmisive[]={0.800000,0.300000,0.650000,0.700000};
specular[]={0.300000,0.300000,0.300000,1.000000};
specularPower=1.000000;
PixelShaderID="Skin";
VertexShaderID="Skin";
class Stage1
{
  texture="hhl_NOHQ.tga";
  uvSource="tex";
  class uvTransform
  {
    aside[]={1.000000,0.000000,0.000000};
    up[]={0.000000,1.000000,0.000000};
    dir[]={0.000000,0.000000,0.000000};
    pos[]={0.000000,0.000000,0.000000};
  };
};
class Stage2
{
	texture="#(argb,8,8,3)color(0,0,0,0,MC)";
	uvSource="tex";
};
class Stage3
{
  texture="CA\characters2\SkinShaderHead\hhl_SDM.tga";
  uvSource="tex";
};
class Stage4
{
  texture="CA\characters2\SkinShaderHead\hhl_AS.tga";
  uvSource="tex";
};
class Stage5
{
  texture="CA\characters2\SkinShaderHead\hhl_SMDI.tga";
  uvSource="tex";
};
class Stage6
{
  texture="#(ai,64,1,1)fresnel(1.0,0.6)";
  uvSource="none";
};

Example of optimal ".rvmat" file

For specific Skin Shader parameters is needed add support in engine and Objektiv.

ambient[]={1.000000,1.000000,1.000000,1.000000};
diffuse[]={1.000000,1.000000,1.000000,1.000000};
forcedDiffuse[]={0.000000,0.000000,0.000000,0.000000};
emmisive[]={0.000000,0.000000,0.000000,0.000000};
specular[]={1.000000,1.000000,1.000000,1.000000};
specularPower=10.000000;
unscatteredColor[]={1.000000,1.000000,1.000000,1.000000};
unscatteredWeight=0.1;
epidermalMul=0.8;
epidermalAdd=0.2;
darkRimFactorEp=0.3;
epidermalWeight=0.4;
subdermalMul=0.65;
subdermalAdd=0.35;
darkRimFactorSu=0.7;
subdermalWeight=0.5;
hemisphericSpecLevel=1.0;
PixelShaderID="Skin";
VertexShaderID="Skin";
class Stage1
{
	texture="skin_NOHQ.tga";
	uvSource="tex";
};
class Stage2
{
	texture="#(argb,8,8,3)color(0,0,0,0,MC)";
	uvSource="tex";
};
class Stage3
{
	texture="skin_SDM.tga";
	uvSource="tex";
};
class Stage4
{
	texture="skin_AS.tga";
	uvSource="tex";
};
class Stage5
{
	texture="#(argb,8,8,3)color(0,0.1,0.1,0,SMDI)";
	uvSource="tex";
};
class Stage6
{
	texture="#(ai,64,1,1)fresnel(1.0,0.6)";
	uvSource="tex";
};

Texture preparation

Light penetration through human skin and it is following diffusion depends on wave length.Light with longer wave length (red part of spectrum) penetrates deepest under skin and respectively light with shorter wave length (blue-violet part of spectrum) nearly not penetrate at all. On following picture is comparison of individual colored channels on cutout from CO map.Individual channels are modified with help of curves to be approximately of equal brightness. On first look it is visible that red channel is in the skin area most 'blurred". That's just caused by larger share of light diffusion under skin.On the contrary blue channel contains most surface details.


Detail comparison in individual colored channels within segment of CO map:
SkinShaderTextures01.jpg

Subdermal map and skin mask (SDM)

Subdermal texture looks like color shifted CO map to orange and more color saturated. Yet this technique isn't suitable. With regard to above information about dependence of light diffusion on wave length, it is probably most suitable prepare subdermal map with help of mixing channels (Photoshop->Layer->New Adjustment Layer->Channel Mixer...).)


SDM texture (rgb - subdermal map, alpha - skin mask):
SkinShaderTextures02.jpg


Used settings of "Channel mixer" for individual RGB channels while preparing subdermal map from CO map:
SkinShaderTextures03.jpg

Skin mask defines where it is used skin effect (white) and where is used material similar to Super Shader (black). Mask on the picture is prepared from red channel by help of curves and retouching with classic and de-inking brush.

Epidermal map

Epidermal map prepared like subdermal with aid of tool "Channel Mixer". In settings emphasize blue channel and suppress red one. Preparation of epidermal map with simple de-saturation of CO map is unrecommended.


Used settings of "Channel mixer" for individual RGB channels while preparing epidermal map from CO map:
SkinShaderTextures05.jpg

With aid of skin mask insert resulting epidermal into CO map. There where is in CO map skin will be epidermal map, rest portions of CO map stays untouched. Within our sample cutout stay unchanged areas with hairs,beard and eyebrow.


Standalone epidermal map (left) and resulting CO map with epidermal map inserted in the skin area:
SkinShaderTextures04.jpg

Normal and specular map (NOHQ and SMDI)

By materials with light diffusion under surface are visually appearing small surface asperities way less within light diffusion component but always stays expressive in specular component. For skin shader we would ideally need 4 normal maps (for each layer - subdermal, epidermal, unscattered, specular) with various surface niceness. For our case at the moment is sufficient compromise solution with one normal map along with not very indistinctive details suitable for diffuse component and specular map with amplified details. Actual normal map (hhl_NOHQ.tga) is high quality however SMDI map (hhl_SMDI.tga) has not needed level of details. Consequently new SMDI map was created by combining extracted details from normal and CO map. It needs still lot of retouching but it is enough for showcase.


Cut from green channel (specular mask) of example SMDI map:
SkinShaderTextures06.jpg


Detail painting added by example SMDI map (right) against plain specular (left):
SkinShaderTextures07.jpg