Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Gritty realistic skin shader

Discussion in 'Shaders' started by r33lwhiteboy, Apr 10, 2012.

  1. r33lwhiteboy

    r33lwhiteboy

    Joined:
    Apr 5, 2012
    Posts:
    119
    Any shaders out there that make skin look realistic? All of the pre-built shaders look shiny and fake- almost plasticky.
     
  2. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
  3. kurylo3d

    kurylo3d

    Joined:
    Nov 7, 2009
    Posts:
    1,123
    actually yes, ive seen a skin shader that looks liek real life...

    http://janbubenik.blogspot.com/2010/10/3d-scan-skin-shading.html

    was done with an earlier version of unity .. like unity 2 ... so doesnt really work at this point. But its proof of possibilities...

    Plus if u go to the asset store.. ive seen one that looks pretty damn good in there... with some true sub surface scatterting.
     
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    That isn't a good demonstration without alternate shaders to try out. It mostly looks good, but the ears look terrible. Let's see the textures with simpler shaders and see if it's worth the electricity.
     
  5. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    The ears look alright to me in that one.

    This is mine, which is a bit more exaggerated here, but the surface curvature is dynamically calculated and the SSS scale is adjustable. Also has fresnel specular term and gamma-correct lighting.
     
  6. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    :-|

    Does nobody understand how to actually demo a shader? Screenshots do not work! You need to have buttons to enable and disable features one at a time! Put something like this on a turntable, and use the web player for the non-iOS version of the site.
     
    Last edited: May 2, 2012
  7. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
  8. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Hi Farfarer,
    How did it look with lightprobe? Because when i'm using Blended Normal shader with lightprobe the SSS effect is gone.
     
  9. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    It won't work with a light probe because there's no light direction for it to work with :/

    I don't think any SSS will work nicely with light probes because they tend to rely on light direction.
     
  10. Swearsoft

    Swearsoft

    Joined:
    Mar 19, 2009
    Posts:
    1,632
    Nice work Farfarer, had to look at the maps to get a feel of how much it adds (it does). Maybe add a side by side shot. I don't really like the face of the girl though. Any other angles or a gif?
     
  11. wdcstudios

    wdcstudios

    Joined:
    Apr 18, 2011
    Posts:
    11
    Farfarer - Sir this has be one of the best realtime skin shader I've seen.
     
  12. Wolfos

    Wolfos

    Joined:
    Mar 17, 2011
    Posts:
    950
  13. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    Is this available somewhere in the asset store?
     
  14. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    I can release it if you want. It's quite specifically engineered to my needs at the moment, though. And it's quite a complex shader that works in D3D9 with SM3 only.
     
  15. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    I'd be very interested in seeing the code for it, if you feel like sharing.
     
  16. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Well, here's the code.

    http://www.farfarer.com/blog/2013/02/11/pre-integrated-skin-shader-unity-3d/

    Some tips;
    • Keep the curvature scale small. (i.e. 0.01 - 0.02). Big values just end up giving the surface a uniform curvature.
    • The "real world" fresnel value is 0.028, but I find near 0.19 looks better. A value of 1.0 is "regular" spec with no fresnel, I'd discourage using a value of 1.
    • This is the image to use for the BRDF texture. You'll want to set it's Wrap Mode to Clamp in the inspector. Also ensure it bypasses sRGB sampling.
    • The blur bias is for the curvature calculation. Blurring the normal map helps it to ignore fine details that shouldn't affect SSS (like skin pores or small wrinkles). 0 is unblurred. Best keep this at 1 or 2, depending on how detailed the normal map is.
    • Works best with a properly baked normal map. Otherwise the curvature can look faceted.

    Click for bigger.

     
    Last edited: Mar 11, 2013
    qiankanglai likes this.
  17. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    Thank you very much for sharing. Less so the guy sharing the teddy bear puppies information.
     
  18. Swearsoft

    Swearsoft

    Joined:
    Mar 19, 2009
    Posts:
    1,632
    Nice job farfarer! I wish I had some time to check it out. Maybe next week
     
  19. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Hi;

    Thank you for sharing your shader for free!
    By default it looks pretty good, but when I come near pointlights or spotlights, it just lights the character without any transition from dark to light, almost like it snaps, there are no shades of darkness, just light and dark. I'm using the free version of unity, could this be the source of the problem?

    I'm also working with real world values. My character is 1.8 units tall, and I have the curvature scale set to 0.01.

    Can you please advise?
     
  20. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    I've updated the code in my post.

    Give that a try? (Not got an install fo Unity handy, so I can't test it myself).
     
  21. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    No, the problem still persists :(
    I've also tried to emulate the anisotropic material you've created for your explorer model but haven't been able to get proper results. How did you get that beautiful blue-ish shade around your character?
     
  22. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    The code I'm using for my anisotropic shader is up on the Unify wiki. Google "unify shader wiki anisotropic" and it should be up in the first few results. I'm just using a texture to lerp between the two.

    The blue colour is just from a blue light, nothing fancy there.

    I'll have a look into the point/spot light thing tomorrow. I think I've just been stupid (very tired today) and it's an easy fix.
     
  23. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Alright, I'll check the thread tomorrow then.
     
  24. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Give it a try now.
     
  25. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Works like a charm :)
    Looks awesome as it is, but are you going to update the shader so that that blue haze around the darker areas are generated automatically?
     
  26. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    I'm not really sure what you mean about the blue haze.

    There's nothing special in the shader that does that.

    In the image, I've just got two lights. A slightly blue light behind the character with a high intensity (2.0) and a slightly yellow/orange one in front of her at normal intensity (1.0). All of the blue colour comes from that light.
     
  27. scarletsnake

    scarletsnake

    Joined:
    Nov 27, 2009
    Posts:
    106
    Twice now I've typed in some information on what I tried to mean and twice now Unity has expired my post... Argh..

    Sorry; I'm having trouble expressing my thoughts. I'm talking about the blue highlights found around the character's darker areas, I think your anisotropic highlighter does something similar? The results I get makes my character looks like he's wrapped in plastic. I'm sure I'm missing something here. I've used different aniso direction textures with no success.
    Here are two examples of what I'm talking about;

    http://www.pcgameshardware.com/screenshots/original/2009/08/Mafia_II_GamesCom__6_.jpg

    http://www.ten24.info/upload/pages/Headfor store.jpg

    I'm really ignorant when it comes to shaders so I have no idea what this highlighting effect is called.
    The closest think I can think of is "the fresnel".

    I'm not sure if I'm making any sense here... :D
     
  28. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    The anisotropic part is meant for long hair or brushed metal. If your character doesn't have long hair, you can just strip the anisotropic stuff out of the code, you won't need it.

    What the fresnel value does is reduce the specular highlight's brightness when face-on to a surface and increases the highlight's brightness at glancing angles. The lower this value, the more extreme the effect is. Values closer to 1.0 gives a result closer to regular spec that you find in Unity's built in shaders.

    Most real-world surfaces have a value between 0.00 and 0.04, except for metals that go higher, to about 0.3.

    Skin has a value of about 0.028, but I find about 0.2 that gives nicer results.

    The blue channel of the specular texture will mask between that value and a default of 0.2 (also masking the skin shader effect). You can change this value in the shader code.
     
  29. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    I'm getting weird results with this in 4.0.1, but only when shadows are on (see attached). At some point it was working really well but then it didn't, but unfortunately I don't know when that occurred because I've only just come back to this!

    I'm not using a MainTex or normal map.

    edit: It's fixable by forcing atten = 1.0 in the lighting function. I don't get it.
     

    Attached Files:

  30. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
  31. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    That did the trick - thanks James!
     
  32. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Got Lightprobe work with this shader, not perfect but give kinda stylish looks :D
    Here the code in case someone interested
    Code (csharp):
    1.  
    2. Shader "Custom/Skin Shader Probe" {
    3.     Properties {
    4.     _Color ("Main Color", Color) = (1,1,1,1)
    5.     _MainTex ("Diffuse (RGB)", 2D) = "white" {}
    6.     _SpecularTex ("Specular (R) Gloss (G) SSS Mask (B)", 2D) = "yellow" {}
    7.     _BumpMap ("Normal (Normal)", 2D) = "bump" {}
    8.     // BRDF Lookup texture, light direction on x and curvature on y.
    9.     _BRDFTex ("BRDF Lookup (RGB)", 2D) = "gray" {}
    10.     // Curvature scale. Multiplier for the curvature - best to keep this very low - between 0.02 and 0.002.
    11.     _CurvatureScale ("Curvature Scale", Float) = 0.005
    12.     // Controller for fresnel specular mask. For skin, 0.028 if in linear mode, 0.2 for gamma mode.
    13.     _Fresnel ("Fresnel Value", Float) = 0.2
    14.     // Which mip-map to use when calculating curvature. Best to keep this between 1 and 2.
    15.     _BumpBias ("Normal Map Blur Bias", Float) = 1.5
    16.     _S3STR ("SSS Strenght", Float) = 1.5
    17.     _ProbeShininess("Probe Spec Pow", Range(1,10) ) = 2
    18.     _ProbeSpecStr("Probe Spec Multiply", Range(0,2) ) = 0.5
    19.     _ProbeSpecSub("Probe Spec Subtrator", Range(0.2,1) ) = 2
    20.     _ProbePow("Probe Pow", Range(0.7,1.5) ) = 1
    21.     }
    22.  
    23.     SubShader{
    24.         Tags { "Queue" = "Geometry" "RenderType" = "Opaque" }
    25.  
    26.         CGPROGRAM
    27.          
    28.         #pragma surface surf SkinShader fullforwardshadows novertexlights
    29.         #pragma target 3.0
    30.         // Bit complex for non-desktop.
    31.         #pragma only_renderers d3d9 d3d11 opengl
    32.         // Required for tex2Dlod function.
    33.         #pragma glsl
    34.          
    35.         struct SurfaceOutputSkinShader {
    36.             fixed3 Albedo;
    37.             fixed3 Normal;
    38.             fixed3 NormalBlur;
    39. //            fixed3 Gloss;
    40.             fixed3 Emission;
    41.             fixed3 Specular;
    42.             fixed Alpha;
    43.             float Curvature;
    44.         };
    45.          
    46.         struct Input{
    47.             float2 uv_MainTex;
    48.             float3 worldPos;
    49.             float3 worldNormal;
    50.             float3 worldRefl;
    51.             float3 viewDir;
    52.             INTERNAL_DATA
    53.         };
    54.          
    55.         sampler2D _MainTex, _SpecularTex, _BumpMap, _BRDFTex;
    56.         float _BumpBias, _CurvatureScale, _Fresnel,_ProbePow,_ProbeShininess,_ProbeSpecStr,_ProbeSpecSub,_S3STR;
    57.         float4 _Color;
    58.          
    59.         void surf (Input IN, inout SurfaceOutputSkinShader o){
    60.             float4 albedo = tex2D ( _MainTex, IN.uv_MainTex );
    61.             float3 Norm = UnpackNormal ( tex2D ( _BumpMap, IN.uv_MainTex ) );
    62.             o.Normal = Norm;
    63.             float3 specMap = tex2D ( _SpecularTex, IN.uv_MainTex ).rgb;
    64.             o.Specular = specMap;
    65. //            o.Gloss = specMap.g;
    66.            
    67. //            o.Albedo = albedo.rgb;
    68.  
    69.             // Calculate the curvature of the model dynamically.
    70.             // Get a mip of the normal map to ignore any small details for regular shading.
    71.             o.NormalBlur = UnpackNormal( tex2Dlod ( _BumpMap, float4 ( IN.uv_MainTex, 0.0, _BumpBias ) ) );
    72.             // Transform it back into a world normal so we can get good derivatives from it.
    73.             float3 worldNormal = WorldNormalVector( IN, o.NormalBlur );
    74.             // Get the scale of the derivatives of the blurred world normal and the world position.
    75.             // From these it's possible to work out the rate of change of the surface normal; or it's curvature.
    76.             #if SHADER_API_D3D11
    77.             // In DX11, ddx_fine should give nicer results.
    78.             float deltaWorldNormal = length( abs(ddx_fine(worldNormal)) + abs(ddy_fine(worldNormal)) );
    79.             float deltaWorldPosition = length( abs(ddx_fine(IN.worldPos)) + abs(ddy_fine(IN.worldPos)) );
    80.             #else
    81.             // Otherwise stick with ddx or dFdx, which can be replaced with fwidth.
    82.             float deltaWorldNormal = length( fwidth( worldNormal ) );
    83.             float deltaWorldPosition = length( fwidth ( IN.worldPos ) );
    84.             #endif
    85.             o.Curvature = saturate( deltaWorldNormal / deltaWorldPosition ) * _CurvatureScale;
    86.            
    87.             o.Normal = normalize(o.Normal);
    88.             #ifdef LIGHTMAP_ON
    89.             o.Albedo = albedo;
    90.             o.Emission = (0,0,0);
    91.             #else
    92.             float4 Fresnel0=(1.0 - dot( normalize( float4( IN.viewDir.x, IN.viewDir.y,IN.viewDir.z,1.0 ).xyz), normalize( Norm.xyz ))).xxxx;
    93.             fixed3 worldN = WorldNormalVector(IN, o.Normal);
    94.             fixed3 worldR = normalize(WorldReflectionVector(IN, o.Normal));
    95.             fixed3 worldRb = normalize(WorldReflectionVector(IN, normalize(o.NormalBlur)));
    96.             float3 fProbeSpecCol = ShadeSH9(float4(worldR,1.0));
    97.             float fProbeSpecMask = pow(max(_ProbeSpecStr*(length(fProbeSpecCol)-_ProbeSpecSub),0),_ProbeShininess+Fresnel0);
    98.             o.Albedo =albedo * (ShadeSH9(float4(worldRb,1.0))*_ProbePow); //pow(ShadeSH9(float4(worldRb,1.0)),_ProbePow);
    99.             o.Emission = (o.Albedo * pow(ShadeSH9(float4(worldR,1.0)),2)*_ProbePow) + fProbeSpecCol.rgb * fProbeSpecMask * o.Specular.r;
    100.             #endif
    101.            
    102.         }
    103.          
    104.         inline fixed4 LightingSkinShader( SurfaceOutputSkinShader s, fixed3 lightDir, fixed3 viewDir, fixed atten ){
    105.             viewDir = normalize( viewDir );
    106.             lightDir = normalize( lightDir );
    107.             s.Normal = normalize( s.Normal );
    108.             s.NormalBlur = ( s.NormalBlur );
    109.             float NdotL = dot( s.Normal, lightDir );
    110.             float3 h = normalize( lightDir + viewDir );
    111.              
    112.             float specBase = saturate( dot( s.Normal, h ) );
    113.              
    114.             float fresnel = pow( 1.0 - dot( viewDir, h ), 5.0 );
    115.             fresnel += _Fresnel * ( 1.0 - fresnel );
    116.              
    117.             float spec = pow( specBase, s.Specular.g * 128 ) * s.Specular.r * fresnel;
    118.              
    119.             float2 brdfUV;
    120.             float NdotLBlur = dot( s.NormalBlur, lightDir );
    121.             // Half-lambert lighting value based on blurred normals.
    122.             brdfUV.x = NdotLBlur * 0.5 + 0.5;
    123.             //Curvature amount. Multiplied by light's luminosity so brighter light = more scattering.
    124.             brdfUV.y = s.Curvature * dot( _LightColor0.rgb, fixed3(0.22, 0.707, 0.071 ) );
    125.             float3 brdf = tex2D( _BRDFTex, brdfUV ).rgb;
    126.             float m = atten; // Multiplier for spec and brdf.
    127.             #if !defined (SHADOWS_SCREEN)  !defined (SHADOWS_DEPTH)  !defined (SHADOWS_CUBE)
    128.             // If shadows are off, we need to reduce the brightness
    129.             // of the scattering on polys facing away from the light
    130.             // as it won't get killed off by shadow value.
    131.             // Same for the specular highlights.
    132.             m *= saturate( ( (NdotLBlur * 0.5 + 0.5) * 2.0) * 2.0 - 1.0);
    133.             #endif
    134.              
    135.             fixed4 c;
    136.             c.rgb = (lerp(s.Albedo * saturate(NdotL) * atten, s.Albedo * (brdf*_S3STR) * m, s.Specular.b ) * _LightColor0.rgb + (spec * m * _LightColor0.rgb) ) * 2;
    137.             c.a = s.Curvature; // Output the curvature to the frame alpha, just as a debug.
    138.             return c;
    139.         }
    140.          
    141.         ENDCG
    142.         }
    143.     FallBack "VertexLit"
    144. }
    145.  
    $SkinShader.PNG
     
  33. reset

    reset

    Joined:
    May 22, 2009
    Posts:
    393
    Thanks for a great shader Farfarer.

    But I am having problems on the rim of my character skin (apologies first - the skin texture is in development still :))

    What would be causing this?

    $skin.jpg
     
  34. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    I would need to know more - what are your settings, etc?
     
  35. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Runs fine on Unity 4 here... that's what I developed it in.

    Are there no more errors?
     
  36. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,079
    Assert in file : C:/BuildAgent/work/a0f11f3559d72c6d/Runtime/GfxDevice/d3d/GfxDeviceD3D9.cpp at line: 182
     
  37. ksam2

    ksam2

    Joined:
    Apr 28, 2012
    Posts:
    1,079
    Infact the the skin looks like an see through material !!!! Never did you seen this problem before?
     
    Last edited: Jul 18, 2013
  38. eagletree

    eagletree

    Joined:
    Sep 1, 2012
    Posts:
    11
    Working great on Unity Pro 4.3.2f1. Thank you.

    Is there any license to quote for usage?
     
  39. IronMathbook

    IronMathbook

    Joined:
    Apr 12, 2014
    Posts:
    60
    Is the code for this shader still around?
     
  40. Md. Shakir Khan

    Md. Shakir Khan

    Joined:
    Feb 13, 2014
    Posts:
    2
    Hi, this a great work. Thanks a lot for sharing the work. I am getting the following warning with your code:
    Program 'frag_surf', cannot map expression to ps_4_0 instruction set (compiling for d3d11) at line 64

    What I understood that this is for PS4.
    I am not using the Pro version of Unity, using the free one and I am very beginner with the Shader Scripting. Could you please so kind and tell me what is this warning about and how can I solve the warning?

    And one more thing, can anybody tell me how to create a Specular Map from a given diffuse map?
     
    Last edited: Apr 30, 2014
  41. Md. Shakir Khan

    Md. Shakir Khan

    Joined:
    Feb 13, 2014
    Posts:
    2
    Hello,
    Changing the value of "Curvature Scale" and "Normal Map Blur Bias" doesn't create any effect. Only changing "Fresnel Value" has effect. I tried with two different models but no couldn't get any change for the first twos.
    Could you please so kind and suggest me how to solve the problem?
    Thanks.
     
  42. Steviebops

    Steviebops

    Joined:
    Apr 9, 2013
    Posts:
    132
    Im having some trouble with this, will there be any updates fro newer versions of unity?
     
  43. metaleap

    metaleap

    Joined:
    Oct 3, 2012
    Posts:
    589


    ps in this context refers not to PlayStation but to shader model ("pixel shader") ;)
     
  44. Eric2241

    Eric2241

    Joined:
    Dec 2, 2012
    Posts:
    642
    Lux has a pretty good skin shader.
     
  45. Simian_Studios

    Simian_Studios

    Joined:
    Dec 25, 2016
    Posts:
    2
    Does this shader still work