前面的話
unitychan是日本unity官方團隊提供的一個Demo潜沦,里面有很好的卡通渲染效果勤众,值得參考學習
上圖是我整理出來的shader結構鸟雏,可以看到Unity娘被拆分成了很多個小的部件耕赘,我想主要是為了掛動態(tài)骨骼吧辩棒。因為有很多部件的材質,shader其實都是一樣的可以合并成少數幾個
我打算分3個部分來學習
- CharaMain.cginc 主要用于衣服等材質
- CharaSkin.cginc 皮膚效果
- Hair 頭發(fā)、眼睛羡玛、睫毛等部位的渲染
CharaMain.cginc
本篇先寫第一部分body材質别智。CharaMain.cginc中包含漫反射、高光稼稿、反射薄榛、邊緣光讳窟、陰影等效果的實現,接下來我們詳細拆解
基礎著色效果(模擬漫反射)
這里是用視角向量跟法線點積(但這樣的做法就不會受光照角度變化)敞恋,然后用結果采樣一張類似這樣的衰減紋理
// Falloff. Convert the angle between the normal and the camera direction into a lookup for the gradient
float_t normalDotEye = dot( normalVec, i.eyeDir.xyz );
float_t falloffU = clamp( 1.0 - abs( normalDotEye ), 0.02, 0.98 );
float4_t falloffSamplerColor = FALLOFF_POWER * tex2D( _FalloffSampler, float2( falloffU, 0.25f ) );
float3_t shadowColor = diffSamplerColor.rgb * diffSamplerColor.rgb;
float3_t combinedColor = lerp( diffSamplerColor.rgb, shadowColor, falloffSamplerColor.r );
combinedColor *= ( 1.0 + falloffSamplerColor.rgb * falloffSamplerColor.a );
效果如下丽啡,邊緣較白
但我感覺加上采樣顏色后效果不是很明顯,邊緣顏色會深一些耳舅。
高光效果
// Use the eye vector as the light vector
float4_t reflectionMaskColor = tex2D( _SpecularReflectionSampler, i.uv.xy );
float_t specularDot = dot( normalVec, i.eyeDir.xyz );
float4_t lighting = lit( normalDotEye, specularDot, _SpecularPower );
float3_t specularColor = saturate( lighting.z ) * reflectionMaskColor.rgb * diffSamplerColor.rgb;
combinedColor += specularColor;
這個高光的計算很奇葩碌上,也是用法線跟視角向量的點積,最后的效果就是有一點淡淡的高光浦徊。也是跟真正的燈光角度無關的。
這里還用到了一張貼圖天梧,高光會用到這張圖的rgb通道盔性,后面要寫的反射,會用到這張圖的a通道呢岗。
大概就是描出來那些地方高光強一些
反射
// Reflection
float3_t reflectVector = reflect( -i.eyeDir.xyz, normalVec ).xzy;
float2_t sphereMapCoords = 0.5 * ( float2_t( 1.0, 1.0 ) + reflectVector.xy );
float3_t reflectColor = tex2D( _EnvMapSampler, sphereMapCoords ).rgb;
reflectColor = GetOverlayColor( reflectColor, combinedColor );
combinedColor = lerp( combinedColor, reflectColor, reflectionMaskColor.a );
combinedColor *= _Color.rgb * _LightColor0.rgb;
float opacity = diffSamplerColor.a * _Color.a * _LightColor0.a;
這里是采樣一張環(huán)境貼圖冕香,為啥用張這樣的圖呢?我覺得他主要是為了能反射出這種銀色的色調罷了后豫。你想要什么色調就換啥樣的環(huán)境圖悉尾。
GetOverlayColor這個函數是用來融合自身貼圖顏色,跟反射環(huán)境貼圖顏色的挫酿。里面用了很多小技巧
先來看看直接輸出反射貼圖是什么樣
通過GetOverlayColor融合后的反射顏色
然后這里會用到高光反射貼圖的A通道构眯,來表示某些區(qū)域的反射的強度。
用alpha通道做差值后會發(fā)現早龟,大部分區(qū)域的反射顏色都不見了惫霸,因為大部分是黑色。只有少數白色區(qū)域葱弟,能看到一些反射效果
接收陰影處理
這里是計算其他物體投射在身上的陰影壹店,這里插入了一個自定義的陰影顏色,為了明顯一點我直接調成純黑芝加,然后弄了一個物體擋住了unity醬~ 效果如圖
使用LIGHT_ATTENUATION指令對陰影貼圖采樣并且返回數據供你使用硅卢。如果你想知道LIGHT_ATTENUATION指令具體做了些什么,檢查 AutoLight.cginc文件
#ifdef ENABLE_CAST_SHADOWS
// Cast shadows
shadowColor = _ShadowColor.rgb * combinedColor;
float_t attenuation = saturate( 2.0 * LIGHT_ATTENUATION( i ) - 1.0 );
combinedColor = lerp( shadowColor, combinedColor, attenuation );
#endif
邊緣高光
終于這里有一個跟著光照角度變換的效果了藏杖,哈哈
一般我們會使用菲尼爾效應來實現邊緣光将塑,而unitychan里面則是采用了一張邊緣光貼圖
用N.L計算出來的值域在[-1,1]之間,*0.5+1后制市,轉成[0,1]區(qū)間抬旺,然后對這張1維的rim圖采樣。
我們從右邊打一盞平行燈祥楣,來看看采樣的效果开财。跟光向量夾角越小的值越接近1汉柒,也就越白
但是邊緣光效果要收到漫反射影響,所以他這里乘上了之前采樣出來的漫反射漸變责鳍,可以看到高光被控制在了邊緣
falloffU = saturate( rimlightDot * falloffU );
完整效果
總結
CharaMain.cginc中用了很多的小技巧實現了漫反射碾褂、高光、反射历葛、邊緣光正塌。她沒有傳統卡通渲染賽璐璐的陰影漸變,也沒有油膩的高光恤溶。她的效果都有種欲出還收的感覺乓诽。
我還是覺得效果太淡了一些