You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
11 KiB
377 lines
11 KiB
2 years ago
|
// Marmoset Skyshop
|
||
|
// Copyright 2013 Marmoset LLC
|
||
|
// http://marmoset.co
|
||
|
|
||
|
#ifndef MARMOSET_SKIN_CGINC
|
||
|
#define MARMOSET_SKIN_CGINC
|
||
|
|
||
|
inline float diffuseFresnel(float eyeDP, float scatter) {
|
||
|
eyeDP = 1.0 - eyeDP;
|
||
|
float dp4 = eyeDP * eyeDP; dp4 *= dp4;
|
||
|
return lerp(dp4, eyeDP*0.4, scatter); //0.4 is energy conserving integral
|
||
|
}
|
||
|
|
||
|
inline float3 wrapLighting(float DP, float3 scatter) {
|
||
|
scatter *= 0.5;
|
||
|
float3 integral = float3(1.0,1.0,1.0)-scatter*_ConserveEnergy;
|
||
|
float3 light = saturate(DP*integral + scatter);
|
||
|
float shadow = (DP*0.5+0.5);
|
||
|
shadow *= shadow;
|
||
|
return light * integral * shadow;
|
||
|
}
|
||
|
|
||
|
inline half4 LightingMarmosetSkinDirect( MarmosetSkinOutput s, half3 lightDir, half3 viewDir, half atten ) {
|
||
|
half4 frag = half4(0.0,0.0,0.0,s.Alpha);
|
||
|
#if defined(MARMO_DIFFUSE_DIRECT) || defined(MARMO_SPECULAR_DIRECT)
|
||
|
half3 L = lightDir;
|
||
|
half3 N = s.Normal;
|
||
|
#ifdef MARMO_HQ
|
||
|
L = normalize(L);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
float selfShadow = 1.0;
|
||
|
#ifdef MARMO_DIFFUSE_DIRECT
|
||
|
half dp = dot(N,L);
|
||
|
half3 diff = wrapLighting(dp, s.Subdermis); //*2.0 to match Unity
|
||
|
diff *= s.Albedo.rgb * 2.0;
|
||
|
frag.rgb = diff;
|
||
|
selfShadow = saturate(10.0*dp);
|
||
|
#else
|
||
|
selfShadow = saturate(10.0*dot(N,L));
|
||
|
#endif
|
||
|
|
||
|
#ifdef MARMO_SPECULAR_DIRECT
|
||
|
half3 H = viewDir+L;
|
||
|
#ifdef MARMO_SPECULAR_ANISO
|
||
|
float theta = _AnisoDir * 3.14159 / 180.0;
|
||
|
float3 T = float3(cos(theta),sin(theta),0.0);
|
||
|
H = H - T*dot(H,T)*_Aniso;
|
||
|
#endif
|
||
|
H = normalize(H);
|
||
|
float specRefl = saturate(dot(N,H));
|
||
|
half3 spec = pow(specRefl, s.Specular*256.0);
|
||
|
#ifdef MARMO_HQ
|
||
|
spec *= selfShadow;
|
||
|
#endif
|
||
|
frag.rgb += (0.5 * spec) * s.SpecularRGB; //*0.5 to match Unity
|
||
|
#endif
|
||
|
|
||
|
diff *= s.Albedo.rgb * 2.0;
|
||
|
|
||
|
#ifdef MARMO_SKIN_DIRECT
|
||
|
#ifdef MARMO_TRANSLUCENCY_DIRECT
|
||
|
//TRANSLUCENCY
|
||
|
float transdp = dot(-N,L);
|
||
|
half3 trans = wrapLighting(transdp, float3(1.0,1.0,1.0)); //*2.0 to match Unity
|
||
|
trans *= s.Translucency;
|
||
|
#else
|
||
|
half3 trans = half3(0.0,0.0,0.0);
|
||
|
#endif
|
||
|
//PEACH-FUZZ
|
||
|
float fuzzdp = saturate(dp*_FuzzOcc + (1.0-_FuzzOcc));
|
||
|
trans += s.Fuzz * _FuzzColor.rgb * fuzzdp;
|
||
|
|
||
|
frag.rgb += trans * _ExposureIBL.w;
|
||
|
#endif
|
||
|
frag.rgb *= atten * _LightColor0.rgb;
|
||
|
return frag;
|
||
|
}
|
||
|
|
||
|
void MarmosetSkinVert (inout appdata_full v, out Input o) {
|
||
|
UNITY_INITIALIZE_OUTPUT(Input,o);
|
||
|
o.texcoord = v.texcoord.xy;
|
||
|
#ifdef MARMO_OCCLUSION
|
||
|
o.texcoord1 = v.texcoord1.xy;
|
||
|
#endif
|
||
|
#ifdef MARMO_VERTEX_COLOR
|
||
|
o.color = v.color;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void MarmosetSkinSurf(Input IN, inout MarmosetSkinOutput OUT) {
|
||
|
#define uv_diff TRANSFORM_TEX(IN.texcoord.xy, _MainTex)
|
||
|
#define uv_spec TRANSFORM_TEX(IN.texcoord.xy, _SpecTex)
|
||
|
#define uv_bump TRANSFORM_TEX(IN.texcoord.xy, _BumpMap)
|
||
|
#define uv_glow TRANSFORM_TEX(IN.texcoord.xy, _Illum)
|
||
|
#define uv_occ TRANSFORM_TEX(IN.texcoord1.xy, _OcclusionMap)
|
||
|
|
||
|
#define uv_detail TRANSFORM_TEX(IN.texcoord.xy, _DetailMap)
|
||
|
#define uv_trans TRANSFORM_TEX(IN.texcoord.xy, _TranslucencyMap)
|
||
|
#define uv_subdermis TRANSFORM_TEX(IN.texcoord.xy, _SubdermisTex)
|
||
|
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
half4 exposureIBL = lerp(_ExposureIBL1, _ExposureIBL, _BlendWeightIBL);
|
||
|
#else
|
||
|
half4 exposureIBL = _ExposureIBL;
|
||
|
#endif
|
||
|
exposureIBL.xy *= _UniformOcclusion.xy;
|
||
|
|
||
|
#if LIGHTMAP_ON
|
||
|
exposureIBL.xy *= _ExposureLM;
|
||
|
#endif
|
||
|
half4 baseColor = _Color;
|
||
|
#ifdef MARMO_VERTEX_COLOR
|
||
|
baseColor *= IN.color;
|
||
|
#endif
|
||
|
|
||
|
#ifdef MARMO_DIFFUSE_SPECULAR_COMBINED
|
||
|
half4 diffspec = half4(1.0,1.0,1.0,1.0);
|
||
|
#endif
|
||
|
|
||
|
//DIFFUSE
|
||
|
#if defined(MARMO_DIFFUSE_DIRECT) || defined(MARMO_DIFFUSE_IBL)
|
||
|
half4 diff = tex2D( _MainTex, uv_diff );
|
||
|
#ifdef MARMO_DIFFUSE_SPECULAR_COMBINED
|
||
|
diffspec = diff.aaaa;
|
||
|
#endif
|
||
|
diff *= baseColor;
|
||
|
OUT.Albedo = diff.rgb;
|
||
|
OUT.Alpha = diff.a;
|
||
|
#ifdef MARMO_PREMULT_ALPHA
|
||
|
OUT.Albedo *= diff.a;
|
||
|
#endif
|
||
|
#else
|
||
|
OUT.Albedo = baseColor.rgb;
|
||
|
OUT.Alpha = 1.0;
|
||
|
#endif
|
||
|
|
||
|
//AMBIENT OCC
|
||
|
#if defined(MARMO_VERTEX_OCCLUSION) || defined(MARMO_OCCLUSION)
|
||
|
half4 occ = half4(1.0,1.0,1.0,1.0);
|
||
|
#ifdef MARMO_OCCLUSION
|
||
|
occ = tex2D(_OccTex, uv_occ);
|
||
|
#endif
|
||
|
#ifdef MARMO_VERTEX_OCCLUSION
|
||
|
occ.rg *= IN.color.rg;
|
||
|
#endif
|
||
|
occ = lerp(half4(1.0,1.0,1.0,1.0),occ, _OccStrength);
|
||
|
//TODO: occlude lightprobe SH by diffuse AO
|
||
|
exposureIBL.xy *= occ.rg;
|
||
|
#endif
|
||
|
|
||
|
//SKIN
|
||
|
#if defined(MARMO_SKIN_IBL) || defined(MARMO_SKIN_DIRECT)
|
||
|
//SUBDERMIS
|
||
|
float4 subdermis = _SubdermisColor;
|
||
|
#ifdef MARMO_SUBDERMIS_MAP
|
||
|
subdermis *= tex2D(_SubdermisTex, uv_subdermis);
|
||
|
subdermis.rgb *= _Subdermis;
|
||
|
float skinMask = subdermis.a;
|
||
|
#else
|
||
|
#define skinMask 1.0
|
||
|
#endif
|
||
|
OUT.Subdermis = subdermis.rgb * skinMask;
|
||
|
#endif
|
||
|
|
||
|
//NORMALS
|
||
|
#ifdef MARMO_NORMALMAP
|
||
|
float3 localN = UnpackNormal(tex2D(_BumpMap, uv_bump));
|
||
|
|
||
|
float bias = _NormalSmoothing * 4.0;
|
||
|
float4 uv_blurred = float4(uv_bump.x, uv_bump.y, bias, bias);
|
||
|
float3 smoothN = UnpackNormal(tex2Dbias(_BumpMap, uv_blurred));
|
||
|
|
||
|
#ifdef MARMO_DETAIL
|
||
|
bias = _DetailSmoothing * 8.0;
|
||
|
uv_blurred = float4(uv_detail.x, uv_detail.y, bias, bias);
|
||
|
float3 detailN = UnpackNormal(tex2D(_DetailMap, uv_detail.xy));
|
||
|
float3 smoothDetailN = UnpackNormal(tex2Dbias(_DetailMap, uv_blurred));
|
||
|
|
||
|
float detailOcc = dot(detailN, smoothDetailN) * dot(detailN, smoothN);
|
||
|
|
||
|
localN += detailN * _DetailWeight * skinMask;
|
||
|
smoothN.xy += smoothDetailN.xy * _DetailWeight;
|
||
|
#endif
|
||
|
|
||
|
//localN and viewDir are in tangent-space
|
||
|
localN = normalize(localN);
|
||
|
smoothN = normalize(smoothN);
|
||
|
|
||
|
float specOcc = dot(localN, smoothN);
|
||
|
#ifdef MARMO_DETAIL
|
||
|
specOcc *= detailOcc;
|
||
|
specOcc *= specOcc;
|
||
|
specOcc *= specOcc;
|
||
|
exposureIBL.y *= specOcc;
|
||
|
#endif
|
||
|
|
||
|
OUT.Normal = localN;
|
||
|
float3 worldN = WorldNormalVector(IN, localN);
|
||
|
smoothN = WorldNormalVector(IN, smoothN);
|
||
|
#else
|
||
|
float3 worldN = IN.worldNormal;
|
||
|
#ifdef MARMO_HQ
|
||
|
worldN = normalize(worldN);
|
||
|
#endif
|
||
|
#if !defined(MARMO_NORMALMAP) && defined(UNITY_PASS_PREPASSFINAL)
|
||
|
float3 localN = float3(0.0,0.0,1.0);
|
||
|
//localN and viewDir are in tangent-space
|
||
|
#else
|
||
|
float3 localN = worldN;
|
||
|
//localN and viewDir are in world-space
|
||
|
#endif
|
||
|
float3 smoothN = localN;
|
||
|
#endif
|
||
|
|
||
|
float3 localE = IN.viewDir;
|
||
|
#ifdef MARMO_HQ
|
||
|
localE = normalize(localE);
|
||
|
#endif
|
||
|
|
||
|
//SPECULAR
|
||
|
#if defined(MARMO_SPECULAR_DIRECT) || defined(MARMO_SPECULAR_IBL)
|
||
|
#ifdef MARMO_DIFFUSE_SPECULAR_COMBINED
|
||
|
half4 spec = diffspec;
|
||
|
#else
|
||
|
half4 spec = tex2D(_SpecTex, uv_spec);
|
||
|
#endif
|
||
|
|
||
|
#ifdef MARMO_HQ
|
||
|
half fresnel = splineFresnel(localN, localE, _SpecInt, _Fresnel);
|
||
|
#else
|
||
|
half fresnel = fastFresnel(localN, localE, _SpecInt, _Fresnel);
|
||
|
#endif
|
||
|
|
||
|
//camera exposure is built into OUT.Specular
|
||
|
spec.rgb *= _SpecColor.rgb;
|
||
|
|
||
|
//filter the light that reaches diffuse reflection by specular intensity
|
||
|
#ifdef MARMO_SPECULAR_FILTER
|
||
|
//Light reaching diffuse is filtered by 1-specColor*specIntensity
|
||
|
half3 specFilter = half3(1.0,1.0,1.0) - spec.rgb * _SpecInt;
|
||
|
|
||
|
//If the material exhibits strong fresnel, bias the filter some.
|
||
|
specFilter += _Fresnel.xxx*0.5;
|
||
|
|
||
|
//don't let it get t crazy, clamp 0-1 and apply
|
||
|
OUT.Albedo *= saturate(specFilter);
|
||
|
#endif
|
||
|
|
||
|
spec.rgb *= fresnel;
|
||
|
half glossLod = glossLOD(spec.a, _Shininess);
|
||
|
#ifdef MARMO_SPECULAR_DIRECT
|
||
|
OUT.SpecularRGB = spec.rgb;
|
||
|
OUT.Specular = glossExponent(glossLod);
|
||
|
//conserve energy by dividing out specular integral
|
||
|
OUT.SpecularRGB *= specEnergyScalar(OUT.Specular);
|
||
|
OUT.Specular *= 0.00390625; // 1/256
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if defined(MARMO_SKIN_IBL) || defined(MARMO_SKIN_DIRECT)
|
||
|
//TRANSLUCENCY
|
||
|
float3 trans = _TranslucencyColor.rgb;
|
||
|
#ifdef MARMO_TRANSLUCENCY_MAP
|
||
|
trans *= tex2D(_TranslucencyMap, uv_trans).rgb;
|
||
|
#endif
|
||
|
trans *= _Translucency;
|
||
|
OUT.Translucency = trans.rgb * skinMask;
|
||
|
|
||
|
//PEACH-FUZZ
|
||
|
float eyeDP = dot(localE, localN);
|
||
|
OUT.Fuzz = _Fuzz * diffuseFresnel(eyeDP, _FuzzScatter) * skinMask;
|
||
|
#ifdef MARMO_SPECULAR_IBL
|
||
|
OUT.Fuzz *= 1.0-saturate(OUT.Specular);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
//SPECULAR IBL
|
||
|
#ifdef MARMO_SPECULAR_IBL
|
||
|
float3 skyR = WorldReflectionVector(IN, localN);
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
float3 skyR1 = skyRotate(_SkyMatrix1, skyR); //per-fragment matrix multiply, expensive
|
||
|
#endif
|
||
|
skyR = skyRotate(_SkyMatrix,skyR); //per-fragment matrix multiply, expensive
|
||
|
|
||
|
#ifdef MARMO_MIP_GLOSS
|
||
|
half3 specIBL = glossCubeLookup(_SpecCubeIBL, skyR, glossLod);
|
||
|
#else
|
||
|
half3 specIBL = specCubeLookup(_SpecCubeIBL, skyR)*spec.a;
|
||
|
#endif
|
||
|
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
#ifdef MARMO_MIP_GLOSS
|
||
|
half3 specIBL1 = glossCubeLookup(_SpecCubeIBL, skyR1, glossLod);
|
||
|
#else
|
||
|
half3 specIBL1 = specCubeLookup(_SpecCubeIBL, skyR1)*spec.a;
|
||
|
#endif
|
||
|
specIBL = lerp(specIBL1, specIBL, _BlendWeightIBL);
|
||
|
#endif
|
||
|
|
||
|
OUT.Emission += specIBL.rgb * spec.rgb * exposureIBL.y;
|
||
|
#endif
|
||
|
|
||
|
//DIFFUSE IBL
|
||
|
#ifdef MARMO_DIFFUSE_IBL
|
||
|
#ifdef MARMO_SKIN_IBL
|
||
|
worldN = lerp(worldN, smoothN, 0.5 * skinMask);
|
||
|
#endif
|
||
|
float3 skyN = skyRotate(_SkyMatrix,worldN); //per-fragment matrix multiply, expensive
|
||
|
skyN = normalize(skyN);
|
||
|
#ifdef MARMO_SKIN_IBL
|
||
|
//SH DIFFUSE
|
||
|
float3 band0, band1, band2;
|
||
|
float3 unity0, unity1, unity2;
|
||
|
SHLookup(skyN,band0,band1,band2);
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
float3 skyN1 = skyRotate(_SkyMatrix1, worldN); //per-fragment matrix multiply, expensive
|
||
|
skyN1 = normalize(skyN1);
|
||
|
float3 band01, band11, band21;
|
||
|
SHLookup1(skyN1,band01,band11,band21);
|
||
|
band0 = lerp(band01, band0, _BlendWeightIBL);
|
||
|
band1 = lerp(band11, band1, _BlendWeightIBL);
|
||
|
band2 = lerp(band21, band2, _BlendWeightIBL);
|
||
|
#endif
|
||
|
|
||
|
SHLookupUnity(worldN,unity0,unity1,unity2);
|
||
|
band0 = (band0*exposureIBL.x) + unity0;
|
||
|
band1 = (band1*exposureIBL.x) + unity1;
|
||
|
band2 = (band2*exposureIBL.x) + unity2;
|
||
|
half3 diffIBL = SHConvolve(band0, band1, band2, subdermis.rgb*skinMask);
|
||
|
diffIBL *= OUT.Albedo;
|
||
|
|
||
|
//PEACH FUZZ
|
||
|
diffIBL += OUT.Fuzz * _FuzzColor.rgb * (band0 + band1 + band2);
|
||
|
|
||
|
#ifdef MARMO_TRANSLUCENCY_IBL
|
||
|
//TRANSLUCENCY
|
||
|
float3 diffSH = SHLookup(-smoothN);
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
float3 diffSH1 = SHLookup1(-skyN1);
|
||
|
diffSH = lerp(diffSH1, diffSH, _BlendWeightIBL);
|
||
|
#endif
|
||
|
diffSH *= exposureIBL.x;
|
||
|
diffSH += SHLookupUnity(-worldN);
|
||
|
diffIBL += diffSH * OUT.Translucency * _TranslucencySky;
|
||
|
#endif
|
||
|
|
||
|
OUT.Emission += diffIBL;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//GLOW
|
||
|
#ifdef MARMO_GLOW
|
||
|
half4 glow = tex2D(_Illum, uv_glow);
|
||
|
glow.rgb *= _GlowColor.rgb;
|
||
|
glow.rgb *= _GlowStre4ngth;
|
||
|
glow.a *= _EmissionLM;
|
||
|
//NOTE: camera exposure is already in albedo from above
|
||
|
glow.rgb += OUT.Albedo * glow.a;
|
||
|
OUT.Emission += glow.rgb;
|
||
|
#endif
|
||
|
|
||
|
#ifndef MARMO_ALPHA
|
||
|
OUT.Alpha = 1.0;
|
||
|
#endif
|
||
|
|
||
|
//camera exposure is built into OUT.Albedo & SpecularRGB
|
||
|
OUT.Albedo *= exposureIBL.w;
|
||
|
OUT.Emission *= exposureIBL.w;
|
||
|
#ifdef MARMO_SPECULAR_DIRECT
|
||
|
OUT.SpecularRGB *= exposureIBL.w;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#endif
|