哈哈,我又回來了,自從上篇的特效Shader之後,這是這個系列的第二彈。老實說這次想寫的內容,我也考慮了很久,最終還是將內容暫定爲使用的頻率較多的外發光。其實外發光可以說是一個爛大街的Shader了,網上也有很多的例子。但是例子多不就從側面說明了,這種類別的Shader的重要性嗎?作爲一個學習爲主,內容爲主的系列Shader,那麼這次的主題就定爲它了。。。。。。哈哈哈哈哈哈哈哈哈哈哈
不多說了,先上圖:
從這個圖片上面,大家也可以看出來,這個其實不是單純的外發光效果,而是既有內發光也有外發光的效果。根據我的設定調整,這個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,哈哈哈哈哈哈