Any shaders out there that make skin look realistic? All of the pre-built shaders look shiny and fake- almost plasticky.
Have you ever seen a realtime skin shader that didn't look fake, like plastic? http://unifycommunity.com/wiki/index.php?title=SkinShader http://unifycommunity.com/wiki/index.php?title=Skin_Shader_3
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.
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.
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.
:-| 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.
Don't really have the time to do that, sorry. It's pretty much Eric Penner's Pre-Integrated Skin Shading technique that I've slightly modified for a better curvature result.
Hi Farfarer, How did it look with lightprobe? Because when i'm using Blended Normal shader with lightprobe the SSS effect is gone.
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.
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?
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.
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.
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?
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).
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?
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.
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?
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.
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...
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.
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.
Make sure the bdrf texture is set to clamp, not wrap. Also, worth checking this, as it's a better version; http://www.farfarer.com/blog/2013/02/11/pre-integrated-skin-shader-unity-3d/
Got Lightprobe work with this shader, not perfect but give kinda stylish looks Here the code in case someone interested Code (csharp): Shader "Custom/Skin Shader Probe" { Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Diffuse (RGB)", 2D) = "white" {} _SpecularTex ("Specular (R) Gloss (G) SSS Mask (B)", 2D) = "yellow" {} _BumpMap ("Normal (Normal)", 2D) = "bump" {} // BRDF Lookup texture, light direction on x and curvature on y. _BRDFTex ("BRDF Lookup (RGB)", 2D) = "gray" {} // Curvature scale. Multiplier for the curvature - best to keep this very low - between 0.02 and 0.002. _CurvatureScale ("Curvature Scale", Float) = 0.005 // Controller for fresnel specular mask. For skin, 0.028 if in linear mode, 0.2 for gamma mode. _Fresnel ("Fresnel Value", Float) = 0.2 // Which mip-map to use when calculating curvature. Best to keep this between 1 and 2. _BumpBias ("Normal Map Blur Bias", Float) = 1.5 _S3STR ("SSS Strenght", Float) = 1.5 _ProbeShininess("Probe Spec Pow", Range(1,10) ) = 2 _ProbeSpecStr("Probe Spec Multiply", Range(0,2) ) = 0.5 _ProbeSpecSub("Probe Spec Subtrator", Range(0.2,1) ) = 2 _ProbePow("Probe Pow", Range(0.7,1.5) ) = 1 } SubShader{ Tags { "Queue" = "Geometry" "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf SkinShader fullforwardshadows novertexlights #pragma target 3.0 // Bit complex for non-desktop. #pragma only_renderers d3d9 d3d11 opengl // Required for tex2Dlod function. #pragma glsl struct SurfaceOutputSkinShader { fixed3 Albedo; fixed3 Normal; fixed3 NormalBlur; // fixed3 Gloss; fixed3 Emission; fixed3 Specular; fixed Alpha; float Curvature; }; struct Input{ float2 uv_MainTex; float3 worldPos; float3 worldNormal; float3 worldRefl; float3 viewDir; INTERNAL_DATA }; sampler2D _MainTex, _SpecularTex, _BumpMap, _BRDFTex; float _BumpBias, _CurvatureScale, _Fresnel,_ProbePow,_ProbeShininess,_ProbeSpecStr,_ProbeSpecSub,_S3STR; float4 _Color; void surf (Input IN, inout SurfaceOutputSkinShader o){ float4 albedo = tex2D ( _MainTex, IN.uv_MainTex ); float3 Norm = UnpackNormal ( tex2D ( _BumpMap, IN.uv_MainTex ) ); o.Normal = Norm; float3 specMap = tex2D ( _SpecularTex, IN.uv_MainTex ).rgb; o.Specular = specMap; // o.Gloss = specMap.g; // o.Albedo = albedo.rgb; // Calculate the curvature of the model dynamically. // Get a mip of the normal map to ignore any small details for regular shading. o.NormalBlur = UnpackNormal( tex2Dlod ( _BumpMap, float4 ( IN.uv_MainTex, 0.0, _BumpBias ) ) ); // Transform it back into a world normal so we can get good derivatives from it. float3 worldNormal = WorldNormalVector( IN, o.NormalBlur ); // Get the scale of the derivatives of the blurred world normal and the world position. // From these it's possible to work out the rate of change of the surface normal; or it's curvature. #if SHADER_API_D3D11 // In DX11, ddx_fine should give nicer results. float deltaWorldNormal = length( abs(ddx_fine(worldNormal)) + abs(ddy_fine(worldNormal)) ); float deltaWorldPosition = length( abs(ddx_fine(IN.worldPos)) + abs(ddy_fine(IN.worldPos)) ); #else // Otherwise stick with ddx or dFdx, which can be replaced with fwidth. float deltaWorldNormal = length( fwidth( worldNormal ) ); float deltaWorldPosition = length( fwidth ( IN.worldPos ) ); #endif o.Curvature = saturate( deltaWorldNormal / deltaWorldPosition ) * _CurvatureScale; o.Normal = normalize(o.Normal); #ifdef LIGHTMAP_ON o.Albedo = albedo; o.Emission = (0,0,0); #else float4 Fresnel0=(1.0 - dot( normalize( float4( IN.viewDir.x, IN.viewDir.y,IN.viewDir.z,1.0 ).xyz), normalize( Norm.xyz ))).xxxx; fixed3 worldN = WorldNormalVector(IN, o.Normal); fixed3 worldR = normalize(WorldReflectionVector(IN, o.Normal)); fixed3 worldRb = normalize(WorldReflectionVector(IN, normalize(o.NormalBlur))); float3 fProbeSpecCol = ShadeSH9(float4(worldR,1.0)); float fProbeSpecMask = pow(max(_ProbeSpecStr*(length(fProbeSpecCol)-_ProbeSpecSub),0),_ProbeShininess+Fresnel0); o.Albedo =albedo * (ShadeSH9(float4(worldRb,1.0))*_ProbePow); //pow(ShadeSH9(float4(worldRb,1.0)),_ProbePow); o.Emission = (o.Albedo * pow(ShadeSH9(float4(worldR,1.0)),2)*_ProbePow) + fProbeSpecCol.rgb * fProbeSpecMask * o.Specular.r; #endif } inline fixed4 LightingSkinShader( SurfaceOutputSkinShader s, fixed3 lightDir, fixed3 viewDir, fixed atten ){ viewDir = normalize( viewDir ); lightDir = normalize( lightDir ); s.Normal = normalize( s.Normal ); s.NormalBlur = ( s.NormalBlur ); float NdotL = dot( s.Normal, lightDir ); float3 h = normalize( lightDir + viewDir ); float specBase = saturate( dot( s.Normal, h ) ); float fresnel = pow( 1.0 - dot( viewDir, h ), 5.0 ); fresnel += _Fresnel * ( 1.0 - fresnel ); float spec = pow( specBase, s.Specular.g * 128 ) * s.Specular.r * fresnel; float2 brdfUV; float NdotLBlur = dot( s.NormalBlur, lightDir ); // Half-lambert lighting value based on blurred normals. brdfUV.x = NdotLBlur * 0.5 + 0.5; //Curvature amount. Multiplied by light's luminosity so brighter light = more scattering. brdfUV.y = s.Curvature * dot( _LightColor0.rgb, fixed3(0.22, 0.707, 0.071 ) ); float3 brdf = tex2D( _BRDFTex, brdfUV ).rgb; float m = atten; // Multiplier for spec and brdf. #if !defined (SHADOWS_SCREEN) !defined (SHADOWS_DEPTH) !defined (SHADOWS_CUBE) // If shadows are off, we need to reduce the brightness // of the scattering on polys facing away from the light // as it won't get killed off by shadow value. // Same for the specular highlights. m *= saturate( ( (NdotLBlur * 0.5 + 0.5) * 2.0) * 2.0 - 1.0); #endif fixed4 c; c.rgb = (lerp(s.Albedo * saturate(NdotL) * atten, s.Albedo * (brdf*_S3STR) * m, s.Specular.b ) * _LightColor0.rgb + (spec * m * _LightColor0.rgb) ) * 2; c.a = s.Curvature; // Output the curvature to the frame alpha, just as a debug. return c; } ENDCG } FallBack "VertexLit" }
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?
Assert in file : C:/BuildAgent/work/a0f11f3559d72c6d/Runtime/GfxDevice/d3d/GfxDeviceD3D9.cpp at line: 182
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?
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.