哈哈,我又回來了,自從上篇的特效Shader之後,這是這個系列的第二彈。老實說這次想寫的内容,我也考慮了很久,最終還是将内容暫定為使用的頻率較多的外發光。其實外發光可以說是一個爛大街的Shader了,網上也有很多的例子。但是例子多不就從側面說明了,這種類别的Shader的重要性嗎?作為一個學習為主,内容為主的系列Shader,那麼這次的主題就定為它了。。。。。。哈哈哈哈哈哈哈哈哈哈哈
不多說了,先上圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TNzMDOwkDN3EzNxQDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
從這個圖檔上面,大家也可以看出來,這個其實不是單純的外發光效果,而是既有内發光也有外發光的效果。根據我的設定調整,這個shader的内發光是黃色的,外發光是白色的。調整系數如下所示:
接下來就到上代碼的階段,這才是最重要的,不過部落客還想在這裡差個題外話(哈哈,就是這麼的啰嗦,來打我啊)。斷斷續續學習Shader也快有半年,老實說這半年裡面在學習的道路上面一直有迷茫,有困惑。最近遇到的一個問題是程式員為什麼要學習Shader ? 老實說一直到現在,我還是有些疑惑。但是,我覺得這并不應該成為妨礙我們廣大猿猴類學習新技術的理由。(哈哈哈哈哈哈哈哈哈) 我個人的想法是學習Shader可以讓我們更好地了解計算機圖形學和渲染管線,學習Shader可以讓我們更加深層次的了解Unity底層那些我們看不到的東西。比較渲染是每個大型引擎的重中之中,我們不應該隻知其然而不知是以然。
而且從現實的層面上來說,目前流行的手機端,暫時限制于性能,一些特别的效果如果能夠良好的使用shader來實作會節約很多的效率。
Shader "Custom/LightShader"
{
Properties {
_RimColor ("Rim Color", Color) = (1,1,1,0.5)
_InnerColor ("Inner Color", Color) = (1,1,1,0.5)
_InnerColorPower ("Inner Color Power", Range(0.0,1.0)) = 0.5
_RimPower ("Rim Power", Range(0.0,5.0)) = 2.5
_AlphaPower ("Alpha Rim Power", Range(0.0,8.0)) = 4.0
_AllPower ("All Power", Range(0.0, 10.0)) = 1.0
}
SubShader {
Tags { "Queue" = "Transparent" }
CGPROGRAM
#pragma surface surf Lambert alpha
struct Input {
float3 viewDir;
INTERNAL_DATA
};
float4 _RimColor;
float _RimPower;
float _AlphaPower;
//float _AlphaMin;
float _InnerColorPower;
float _AllPower;
float4 _InnerColor;
void surf (Input IN, inout SurfaceOutput o) {
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower)*_AllPower+(_InnerColor.rgb*2*_InnerColorPower);
o.Alpha = (pow (rim, _AlphaPower))*_AllPower;
}
ENDCG
}
Fallback "VertexLit"
}
這個發光Shader是使用的Unity的surface shader編寫的其實老實說看起來并不是很直覺,因為裡面的很多代碼都是經過封裝的。是以,代碼封裝是把雙刃劍啊。那麼還是老規矩,代碼解析開始。
Properties {
_RimColor ("Rim Color", Color) = (1,1,1,0.5) //這個屬性的意思是外發光的顔色
_InnerColor ("Inner Color", Color) = (1,1,1,0.5) //這個屬性的意思是内發光的顔色
_InnerColorPower ("Inner Color Power", Range(0.0,1.0)) = 0.5 //這個值表示的意思是内發光的強度
_RimPower ("Rim Power", Range(0.0,5.0)) = 2.5 //這個值表示的意思是外發光的強度
_AlphaPower ("Alpha Rim Power", Range(0.0,8.0)) = 4.0 //這個值的意思是外發光的透明度的值
_AllPower ("All Power", Range(0.0, 10.0)) = 1.0 //這個值的意思是控制所有的發光效果的強度
}
Tags { "Queue" = "Transparent" }
因為要使用透明通道,是以這裡要聲明使用透明隊列。
#pragma surface surf Lambert alpha
這句話的意思是使用surface裡面封裝好的Lambert alpha光照模型,老實說要把Lambert光照模型拆開将的話需要花費很長的時間,這裡面包含了很多的内容,如果想要詳細了解的話可以看我們的樂樂大神的講解http://blog.csdn.net/candycat1992/article/details/39994049 (再次無情甩鍋,哈哈哈哈哈哈哈哈哈)
float3 viewDir;
INTERNAL_DATA
通過聲明INTERNAL_DATA,unity會幫你拿到的視向量,詳細的可以再次看我們的樂樂大神的部落格http://blog.csdn.net/candycat1992/article/details/24541623 (不要拿西瓜皮丢我,哈哈哈哈哈哈)
float4 _RimColor;
float _RimPower;
float _AlphaPower;
//float _AlphaMin;
float _InnerColorPower;
float _AllPower;
float4 _InnerColor;
這些屬性值,都是用來獲得我們上面定義的那些在shader面闆裡面的值。
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
這是通過拿該點标準化過的視向量和法向量做點選,由此來算出該點的相應的光照值。
o.Emission = _RimColor.rgb * pow (rim, _RimPower)*_AllPower+(_InnerColor.rgb*2*_InnerColorPower);
o.Emission的代表的含義是該點的自發光強度,這個值是unity封裝好的,詳細可以看Unity官方API。這裡是拿我們上面定義的外發光的rgb顔色值和rim的_RimPower次方和AllPower相乘,另外再加上InnerColor.rgb乘2再乘_InnerColorPower。
o.Alpha = (pow (rim, _AlphaPower))*_AllPower;
o.Alpha代表的含義是該點的透明度的值,通過rim的_AlphaPower次方的值再乘以_AllPower得到結果。
Fallback "VertexLit"
這個話的意思類似于備胎,就是在目前着色器不能用的時候,就使用這個(有點慘啊。。。。。)
其實可能大家覺得上面的運算看起來不直覺,不明白是什麼意思,在這裡我想說一句名言:計算機圖形學其實在某種程度上是用來欺騙眼睛的一門學科,這裡很多的公式運算很多可能過多的是出于經驗而不是純科學理論。(才不是部落客不知道而亂講呢,嘻嘻嘻嘻嘻嘻嘻嘻嘻)
這次的Shader講解就先到這裡了,因為一些資料沒有帶回來,是以這次講解的有點少,下次補上。
歡迎大家來和我交流,我的郵箱是[email protected] , 大家也可以來群裡面找我344682050,哈哈哈哈哈哈