参考网址:
https://www.cnblogs.com/timlly/p/11098212.html
https://zhuanlan.zhihu.com/p/72161323
http://www.iryoku.com/translucency/
1、首先效果图:
1、surf函数的解析
输入的参数:
struct Input
{
float2 uv_MainTex;
};
在_MainTex前加了一个前缀:uv,获取uv坐标:
_MainTex ("Diffuse Map(RGB)", 2D) = "white" {}
输出的参数:
struct MySurfaceOutput
{
half3 Albedo;
half3 Normal;
#ifdef ENABLE_SEPARATE_DIFFUSE_NORMALS
half3 NormalBlue;
half3 NormalGreen;
half3 NormalRed;
#endif
half3 Emission;
half Specular;
half Gloss;
half Alpha;
half Scattering;
#ifdef ENABLE_TRANSLUCENCY
half3 Translucency;
#endif
#ifdef ENABLE_RIMS
half BackRimWidth;
half FrontRimWidth;
#endif
};
surf函数的主体部分:
float2 uv = IN.uv_MainTex; //得到uv坐标
#ifdef ENABLE_SEPARATE_DIFFUSE_NORMALS
float3 normalHigh = UnpackNormal(tex2D(_BumpMap, uv));
float3 normalLow = UnpackNormal(tex2Dbias(_BumpMap, float4(uv, 0, 3)));
o.Normal = normalize(lerp(normalLow, normalHigh, _Bumpiness));
o.NormalRed = normalize(lerp(normalLow, normalHigh, _BumpinessDR));
o.NormalGreen = normalize(lerp(normalLow, normalHigh, _BumpinessDG));
o.NormalBlue = normalize(lerp(normalLow, normalHigh, _BumpinessDB));
#else
#ifndef NOGLSL
o.Normal = UnpackNormal(tex2Dbias(_BumpMap, float4(uv, 0, (1-_Bumpiness)*3)));
#else
// no GLSL support (most likely Intel igp)
// fallback to smoothing to fully perpendicular normal instead of low res mipmap
// this could result in differences if normal contains larger features, not just
// small bumpy ones.
// TODO could geet rid of normalize op by pecifying packed normal for various platforms (or is there a define i didn't find?)
// o.Normal = normalize(lerp(half3(0,0,1),UnpackNormal(tex2D(_BumpMap, uv)), _Bumpiness));
// FIXME should normalize it, but there are no more instructions left!
o.Normal = (lerp(half3(0,0,1),UnpackNormal(tex2D(_BumpMap, uv)), _Bumpiness));
#endif
#endif
这段只是为了计算法线。
_BumpMap 为凹凸图/法线图。
half3 specGlosDepth = tex2D(_SpecGlosDepthMap, uv).rgb;
half depth = specGlosDepth.b;
o.Scattering = saturate((depth + _ScatteringOffset) * _ScatteringPower);
其中_SpecGlosDepthMap的定义为:三个维度存放了三个不同的信息。分别是镜面反射系数、光滑度、深度。
_SpecGlosDepthMap (“Specular ® Glosiness(G) Depth (B)”, 2D) = “white” {}
在unity中也可以很方便的查看各个通道的信息:
上面的三句代码是,采样纹理,得到b通道的数值,即深度信息,对深度进行偏移,并进行缩放。这个最终表达的是次表面散射的强度。
half3 c = tex2D(_MainTex, uv).rgb;
o.Albedo = c.rgb * _Color.rgb;
o.Alpha = 1; // no transparency
o.Specular = specGlosDepth.g * _SpecRoughness;
o.Gloss = specGlosDepth.r * _SpecIntensity;
采样纹理,对颜色进行缩放,alpha设置为1,对光滑度进行缩放,为啥存放在specular中呢???,对镜面反射强度进行缩放。
#ifdef ENABLE_RIMS
half rimSpread = 1 - depth*0.8;
o.BackRimWidth = _BackRimWidth * rimSpread;
o.FrontRimWidth = _FrontRimWidth * rimSpread;
#endif
如果开启了边缘效果。那么1 - depth*0.8;表示,越薄则边缘光越强,与厚度成反比。
#ifdef ENABLE_TRANSLUCENCY
// Calculate the scale of the translucency effect.
depth = 1-depth;
depth = saturate((depth + _TranslucencyOffset) * 1);
float scale = 8.25 * depth / _TranslucencyRadius;
float d = scale * depth;
half translucencyStrength = (1-depth) * _TranslucencyPower;
// Could use a lookup map for this, but it's actually faster to compute on my GTX460
// half3 translucencyProfile = tex2D(_LookupTranslucency, half2(d, 0)).rgb;
float dd = -d * d;
half3 translucencyProfile =
float3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
float3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
float3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
float3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
float3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
float3(0.078, 0.0, 0.0) * exp(dd / 7.41);
o.Translucency = translucencyStrength * translucencyProfile;
#endif
这个暂时不懂。。
下面是光照函数:
摘取片段:
half4 c = _LightColor0.rgba;
c.rgb *= s.Albedo * ( diff //漫反射
#ifdef ENABLE_TRANSLUCENCY //半透明效果
+ translucency * atten
#endif
#ifdef ENABLE_RIMS
+ (frim * atten).xxx //正面边缘光
#endif
)
+ (specLevel * atten).xxx //这部分是镜面反射
#ifdef ENABLE_RIMS
+ brim.xxx //这是背面边缘光
#endif
;