SkinShader

From Unify Community Wiki
Jump to: navigation, search


Author: Aras Pranckevicius, artwork in the shots by Alpha-Loup.

See also: SkinShader2 that supports bumpmapping and where shading terms are controlled with textures.

Contents

Description

Good for skin!

A shader for skin rendering. This one expands on the built-in Glossy (Specular) shader:

  • It uses "wrapped diffuse" lighting instead of regular diffuse. Gives softer look and more details in the shadowed sides of the object.
  • It adds dedicated rim lighting in ambient pass.

It is a pixel-lit shader that requires vertex&fragment programs. Otherwise it falls back to built-in Specular|Glossy.

Usage

Skin shader setup

The shader exposes three additional properties in the material, compared to Glossy shader.

  • Wrap lighting - the strength of "wrap diffuse". Slider on the left is regular diffuse, slider on the right is fully wrapped lighting. Usually it's best to decrease ambient light in render settings, and use higher wrap lighting instead.
  • Rim color - the color of rim lighting.
  • Rim power - how rim lighting spreads around the edges of the model.

Note that rim lighting happens only in the ambient pass; that means if you have vertex lights in your scene, there will be no rim lighting.

Unity 2.x version does not support receiving shadows on purpose, as shadows with wrap lighting don't look that good. It does cast shadows on any other objects though. If you want it to support shadows, replace "#pragma multi_compile_builtin_noshadows" with "#pragma multi_compile_builtin".


ShaderLab - SkinSpecular.shader for Unity 2.x

Invalid language.

You need to specify a language like this: <source lang="html4strict">...</source>

Supported languages for syntax highlighting:

4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript, actionscript3, ada, algol68, apache, applescript, apt_sources, asm, asp, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_loadrunner, c_mac, caddcl, cadlisp, cfdg, cfm, chaiscript, cil, clojure, cmake, cobol, coffeescript, cpp, cpp-qt, csharp, css, cuesheet, d, dcs, delphi, diff, div, dos, dot, e, ecmascript, eiffel, email, epc, erlang, euphoria, f1, falcon, fo, fortran, freebasic, fsharp, gambas, gdb, genero, genie, gettext, glsl, gml, gnuplot, go, groovy, gwbasic, haskell, hicest, hq9plus, html4strict, html5, icon, idl, ini, inno, intercal, io, j, java, java5, javascript, jquery, kixtart, klonec, klonecpp, latex, lb, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, mmix, modula2, modula3, mpasm, mxml, mysql, newlisp, nsis, oberon2, objc, objeck, ocaml, ocaml-brief, oobas, oracle11, oracle8, oxygene, oz, pascal, pcre, per, perl, perl6, pf, php, php-brief, pic16, pike, pixelbender, pli, plsql, postgresql, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, python, q, qbasic, rails, rebol, reg, robots, rpmspec, rsplus, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, uscript, vala, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xbasic, xml, xorg_conf, xpp, yaml, z80, zxbasic


Shader "Skin/Specular" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
    _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
    _MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
    _Wrap ("Wrap lighting", Range(0,1)) = 0.5
    _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
    _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
}

// ------------------------------------------------------------------
// Fragment program

SubShader {
    Blend AppSrcAdd AppDstAdd
    Fog { Color [_AddFog] }
    TexCount 4
    
    
    // Ambient pass
    // This does ambient + rim lighting. Note that if you have vertexlit
    // lights in the scene, then standard vertex lighting will be used instead,
    // so you'll lose rim lighting.
    Pass {
        Name "BASE"
        Tags {"LightMode" = "PixelOrNone"}
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

struct v2f {
    V2F_POS_FOG;
    float2    uv;
    float3    viewDir;
    float3    normal;
};

float4 _MainTex_ST;

v2f vert (appdata_base v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.normal = v.normal;
    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    o.viewDir = ObjSpaceViewDir( v.vertex );
    return o;
}

uniform float4 _Color;
uniform float4 _RimColor;
uniform float _RimPower;

uniform sampler2D _MainTex;

float4 frag (v2f i) : COLOR
{
    i.normal = normalize(i.normal);
    i.viewDir = normalize(i.viewDir);
    half4 texcol = tex2D( _MainTex, i.uv );
    
    // rim factor
    float rim = 1.0 - saturate(dot( i.normal, i.viewDir ));
    
    half3 ambient = texcol.rgb * _PPLAmbient.rgb * 2;
    half3 rimcolor = pow( rim, _RimPower ) * _RimColor.rgb;
    return float4( ambient + rimcolor, texcol.a * _Color.a );
}
ENDCG
    }
    
    
    // Vertex lights
    Pass {
        Name "BASE"
        Tags {"LightMode" = "Vertex"}
        Lighting On
        Material {
            Diffuse [_Color]
            Emission [_PPLAmbient]
            Specular [_SpecColor]
            Shininess [_Shininess]
        }
        SeparateSpecular On

CGPROGRAM
#pragma fragment frag
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest

#include "UnityCG.cginc"

uniform sampler2D _MainTex;

half4 frag (v2f_vertex_lit i) : COLOR {
    return VertexLight( i, _MainTex );
} 
ENDCG

    }
    
    
    // Pixel lights
    Pass {
        Name "PPL"
        Tags { "LightMode" = "Pixel" }
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#pragma multi_compile_builtin_noshadows
#pragma fragmentoption ARB_fog_exp2
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc" 

struct v2f {
    V2F_POS_FOG;
    LIGHTING_COORDS
    float3    uvK; // xy = UV, z = specular K
    float3    viewDir;
    float3    normal;
    float3    lightDir;
}; 

uniform float _Shininess;
uniform float4 _MainTex_ST;

v2f vert (appdata_base v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.normal = v.normal;
    o.uvK.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
    o.uvK.z = _Shininess * 128;
    o.lightDir = ObjSpaceLightDir( v.vertex );
    o.viewDir = ObjSpaceViewDir( v.vertex );
    TRANSFER_VERTEX_TO_FRAGMENT(o);
    return o;
}

uniform sampler2D _MainTex;
uniform float _Wrap;

// Mostly copied from UnityCG.cginc; modified to use wrap lighting
// instead of regular diffuse.
inline half4 SpecularLightWrap( half3 lightDir, half3 viewDir, half3 normal, half4 color, float specK, half atten )
{
    normal = normalize(normal);
    lightDir = normalize(lightDir);
    viewDir = normalize(viewDir);
    half3 h = normalize( lightDir + viewDir );
    
    // This would be regular diffuse component
    //half diffuse = dot( normal, lightDir );
    
    // This is "wrap diffuse" lighting.
    // Note that if you know the _Wrap parameter you will use, the
    // shader can be optimized. E.g. if _Wrap is 1.0, then putting that
    // and simplifying the math becomes just
    //   half diffuse = dot(normal, lightDir) * 0.5 + 0.5;
    half diffuse = max(0.0, (dot(normal, lightDir) + _Wrap) / (1.0 + _Wrap));
    
    float nh = saturate( dot( h, normal ) );
    float spec = pow( nh, specK ) * color.a;
    spec *= diffuse;
    
    half4 c;
    c.rgb = (color.rgb * _ModelLightColor0.rgb * diffuse + _SpecularLightColor0.rgb * spec) * (atten * 2);
    c.a = _SpecularLightColor0.a * spec * atten; // specular passes by default put highlights to overbright
    return c;
}


half4 frag (v2f i) : COLOR
{    
    half4 texcol = tex2D( _MainTex, i.uvK.xy );
    return SpecularLightWrap( i.lightDir, i.viewDir, i.normal, texcol, i.uvK.z, LIGHT_ATTENUATION(i) );
}
ENDCG

    }
}

Fallback "Specular"

}


ShaderLab - SkinGlossy.shader for Unity 1.x

Invalid language.

You need to specify a language like this: <source lang="html4strict">...</source>

Supported languages for syntax highlighting:

4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript, actionscript3, ada, algol68, apache, applescript, apt_sources, asm, asp, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_loadrunner, c_mac, caddcl, cadlisp, cfdg, cfm, chaiscript, cil, clojure, cmake, cobol, coffeescript, cpp, cpp-qt, csharp, css, cuesheet, d, dcs, delphi, diff, div, dos, dot, e, ecmascript, eiffel, email, epc, erlang, euphoria, f1, falcon, fo, fortran, freebasic, fsharp, gambas, gdb, genero, genie, gettext, glsl, gml, gnuplot, go, groovy, gwbasic, haskell, hicest, hq9plus, html4strict, html5, icon, idl, ini, inno, intercal, io, j, java, java5, javascript, jquery, kixtart, klonec, klonecpp, latex, lb, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, mmix, modula2, modula3, mpasm, mxml, mysql, newlisp, nsis, oberon2, objc, objeck, ocaml, ocaml-brief, oobas, oracle11, oracle8, oxygene, oz, pascal, pcre, per, perl, perl6, pf, php, php-brief, pic16, pike, pixelbender, pli, plsql, postgresql, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, python, q, qbasic, rails, rebol, reg, robots, rpmspec, rsplus, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, uscript, vala, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xbasic, xml, xorg_conf, xpp, yaml, z80, zxbasic


Shader "Skin/Specular" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
    _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
    _MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
    _Wrap ("Wrap lighting", Range(0,1)) = 0.5
    _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)
    _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0
}

// ------------------------------------------------------------------
// Fragment program

SubShader {
    Blend AppSrcAdd AppDstAdd
    Fog { Color [_AddFog] }
    TexCount 4
    
    
    // Ambient pass
    // This does ambient + rim lighting. Note that if you have vertexlit
    // lights in the scene, then standard vertex lighting will be used instead,
    // so you'll lose rim lighting.
    Pass {
        Name "BASE"
        Tags {"LightMode" = "PixelOrNone"}
CGPROGRAM
// profiles arbfp1
// fragment frag
// vertex vert
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

struct v2f {
    V2F_POS_FOG;
    float2    uv            : TEXCOORD0;
    float3    viewDir        : TEXCOORD1;
    float3    normal        : TEXCOORD2;
}; 

v2f vert (appdata_base v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.normal = v.normal;
    o.uv = TRANSFORM_UV(0);
    o.viewDir = ObjSpaceViewDir( v.vertex );
    return o;
}

uniform float4 _Color;
uniform float4 _RimColor;
uniform float _RimPower;

uniform sampler2D _MainTex : register(s0);

float4 frag (v2f i)  : COLOR
{
    i.normal = normalize(i.normal);
    i.viewDir = normalize(i.viewDir);
    half4 texcol = tex2D( _MainTex, i.uv );
    
    // rim factor
    float rim = 1.0 - saturate(dot( i.normal, i.viewDir ));
    
    half3 ambient = texcol.rgb * _PPLAmbient.rgb * 2;
    half3 rimcolor = pow( rim, _RimPower ) * _RimColor.rgb;
    return float4( ambient + rimcolor, texcol.a * _Color.a );
}
ENDCG
        SetTexture [_MainTex] {}
    }
    
    
    // Vertex lights
    Pass {
        Name "BASE"
        Tags {"LightMode" = "Vertex"}
        Lighting On
        Material {
            Diffuse [_Color]
            Emission [_PPLAmbient]
            Specular [_SpecColor]
            Shininess [_Shininess]
        }
        SeparateSpecular On

CGPROGRAM
// profiles arbfp1
// fragment
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest

#include "UnityCG.cginc"

uniform sampler2D _MainTex;

half4 main (v2f_vertex_lit i) : COLOR {
    return VertexLight( i, _MainTex );
} 
ENDCG

        SetTexture [_MainTex] {combine texture}
    }
    
    
    // Pixel lights
    Pass {
        Name "PPL"
        Tags { "LightMode" = "Pixel" }
CGPROGRAM
// profiles arbfp1
// fragment frag
// vertex vert
// autolight 7
// fragmentoption ARB_fog_exp2
// fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
#include "AutoLight.cginc" 

struct v2f {
    V2F_POS_FOG;
    float3    uvK         : TEXCOORD0; // xy = UV, z = specular K
    float3    viewDir        : TEXCOORD1;
    float3    normal        : TEXCOORD2;
    float3    lightDir    : TEXCOORD3;
    V2F_LIGHT_COORDS(TEXCOORD4);
}; 
struct v2f2 { 
    V2F_POS_FOG;
    float3    uvK         : TEXCOORD0; // xy = UV, z = specular K
    float3    viewDir        : TEXCOORD1;
    float3    normal        : TEXCOORD2;
    float3    lightDir    : TEXCOORD3;
};

uniform float _Shininess;

v2f vert (appdata_base v)
{
    v2f o;
    PositionFog( v.vertex, o.pos, o.fog );
    o.normal = v.normal;
    o.uvK.xy = TRANSFORM_UV(0);
    o.uvK.z = _Shininess * 128;
    o.lightDir = ObjSpaceLightDir( v.vertex );
    o.viewDir = ObjSpaceViewDir( v.vertex );
    PASS_LIGHT_COORDS(1);
    return o;
}

uniform sampler2D _MainTex : register(s0);
uniform float _Wrap;

// Mostly copied from UnityCG.cginc; modified to use wrap lighting
// instead of regular diffuse.
inline half4 SpecularLightWrap(
    half3 lightDir, half3 viewDir, half3 normal,
    half4 color, float specK, half atten )
{
    normal = normalize(normal);
    lightDir = normalize(lightDir);
    viewDir = normalize(viewDir);
    half3 h = normalize( lightDir + viewDir );
    
    // This would be regular diffuse component
    //half diffuse = dot( normal, lightDir );
    
    // This is "wrap diffuse" lighting.
    // Note that if you know the _Wrap parameter you will use, the
    // shader can be optimized. E.g. if _Wrap is 1.0, then putting that
    // and simplifying the math becomes just
    //   half diffuse = dot(normal, lightDir) * 0.5 + 0.5;
    half diffuse = max(0.0, (dot(normal, lightDir) + _Wrap) / (1.0 + _Wrap));
    
    float nh = saturate( dot( h, normal ) );
    float spec = pow( nh, specK ) * color.a;
    spec *= diffuse;
    
    half4 c;
    c.rgb = (color.rgb * _ModelLightColor[0].rgb * diffuse +
        _SpecularLightColor[0].rgb * spec) * (atten * 2);
    // specular passes by default put highlights to overbright
    c.a = _SpecularLightColor[0].a * spec * atten;
    return c;
}


float4 frag (v2f2 i, LIGHTDECL(TEXUNIT1))  : COLOR
{    
    half4 texcol = tex2D( _MainTex, i.uvK.xy );
    return SpecularLightWrap( i.lightDir, i.viewDir, i.normal, texcol, i.uvK.z, LIGHTATT );
}
ENDCG

        SetTexture [_MainTex] {combine texture}
        SetTexture [_LightTexture0] {combine texture} 
        SetTexture [_LightTextureB0] {combine texture}
    }
}

Fallback " Glossy", 0

}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Tools