? ?
?
?
本系列文章由@淺墨_毛星云?出品,轉(zhuǎn)載請(qǐng)注明出處。 ?
文章鏈接:?http://blog.csdn.net/poem_qianmo/article/details/40723789
?
作者:毛星云(淺墨)?? ? 微博:http://weibo.com/u/1723155442
郵箱:? happylifemxy@163.com
?
?
[cpp] ?view plaincopy print?
?? ?? Shader?"淺墨Shader編程/0.TheFirstShader"??? {?? ???? ????Properties??? ????{?? ????????_MainTex?("【紋理】Texture",?2D)?=?"white"?{}?? ????????_BumpMap?("【凹凸紋理】Bumpmap",?2D)?=?"bump"?{}?? ????????_RimColor?("【邊緣顏色】Rim?Color",?Color)?=?(0.17,0.36,0.81,0.0)?? ????????_RimPower?("【邊緣顏色強(qiáng)度】Rim?Power",?Range(0.6,9.0))?=?1.0?? ????}?? ?? ???? ????SubShader??? ????{?? ???????? ????????Tags?{?"RenderType"?=?"Opaque"?}?? ?? ???????? ????????CGPROGRAM?? ?? ???????? ????????#pragma?surface?surf?Lambert?? ?????????? ???????? ????????struct?Input??? ????????{?? ????????????float2?uv_MainTex; ????????????float2?uv_BumpMap; ????????????float3?viewDir; ????????};?? ?? ???????? ????????sampler2D?_MainTex; ????????sampler2D?_BumpMap; ????????float4?_RimColor; ????????float?_RimPower; ?? ???????? ????????void?surf?(Input?IN,?inout?SurfaceOutput?o)?? ????????{?? ???????????? ????????????o.Albedo?=?tex2D?(_MainTex,?IN.uv_MainTex).rgb;?? ???????????? ????????????o.Normal?=?UnpackNormal?(tex2D?(_BumpMap,?IN.uv_BumpMap));?? ???????????? ????????????half?rim?=?1.0?-?saturate(dot?(normalize(IN.viewDir),?o.Normal)); ?//saturate 把輸入的值限制在0到1之間 ???????????? ????????????o.Emission?=?_RimColor.rgb?*?pow?(rim,?_RimPower); ?//pow(x,y)x的y次方 ????????}?? ?? ???????? ????????ENDCG?? ????}??? ?? ???? ????Fallback?"Diffuse"?? }?? 由于這是第一篇Shader系列文章,已經(jīng)涉及到很多內(nèi)容了,所以淺墨不可能展開(kāi)講解這段代碼的具體思路和寫(xiě)法,不過(guò)已經(jīng)詳細(xì)注釋,大家應(yīng)該會(huì)多少有點(diǎn)明白。隨著稍后文章的深入,這段代碼就顯得很簡(jiǎn)單易懂了。
拷貝完成,保存一下這段代碼,unity會(huì)自動(dòng)檢測(cè)和編譯被保存的代碼,我只需返回Unity窗口,等待編譯完成即可。若沒(méi)有錯(cuò)誤,在“0.TheFirstShader”的inspector面板中得到的結(jié)果應(yīng)該是有紅色的錯(cuò)誤提示的。
?
需要注意的是,Shader想要使用到游戲物體上,一般得有個(gè)媒介,這個(gè)媒介就是我們的老朋友——材質(zhì)(Material)。我們把Shader作用于材質(zhì),接著再把材質(zhì)對(duì)應(yīng)地作用于給游戲物體,這樣寫(xiě)的Shader就間接地給物體表面使用了。
?
?
?
而這一層關(guān)系,在Unity中完全可以通過(guò)點(diǎn)點(diǎn)鼠標(biāo),拖動(dòng)來(lái)完成。下面我們就來(lái)講一講如何將一個(gè)著色程序的結(jié)果顯示到物體表面上。
?
知道以上原理了就很簡(jiǎn)單了,在“0.TheFirstShader.shader”的同一目錄下創(chuàng)建一個(gè)Material。同樣是可以通過(guò)Create下拉菜單->Material或者空白處右鍵->create->Material來(lái)完成。
?
為了到時(shí)候方便對(duì)應(yīng),我們將這個(gè)材質(zhì)也取名為0.TheFirstShader。
?
?
接著,將0.TheFirstShader.shader拖動(dòng)到0.TheFirstShader材質(zhì)身上然后釋放。
?
?
拖動(dòng)完成后,我們單擊0.TheFirstShader材質(zhì),打開(kāi)他的面板,發(fā)現(xiàn)他已經(jīng)和一開(kāi)始不一樣了,泛著藍(lán)光:
?
?
還沒(méi)完,接下來(lái)我們還得給這個(gè)材質(zhì)添加兩張紋理圖片。圖片淺墨也已經(jīng)提前準(zhǔn)備好了,在名為T(mén)extures01 by QianMo.unitypackage的Unity包中,同樣雙擊這個(gè)包然后打開(kāi)導(dǎo)入到項(xiàng)目中。
?
【Textures01 by QianMo.unitypackage單獨(dú)下載請(qǐng)點(diǎn)我】
?
我們?cè)赥extures文件夾下找到這兩張紋理,接下來(lái)做的就是將他們拖動(dòng)到0.TheFirstShader材質(zhì)對(duì)應(yīng)的紋理區(qū)域中,如下:
?
?
?
或者點(diǎn)擊這里的Select分別選擇,操作如下:
?
?
兩張紋理選擇完畢后,我們的材質(zhì)就準(zhǔn)備好了,最后的結(jié)果,有點(diǎn)黑科技,如各種科幻游戲和電影中發(fā)光的礦石,非常炫酷:
?
?
?
?
OK,那么就只剩下最后一步了,就是在場(chǎng)景中創(chuàng)建一個(gè)物體,然后將我們做好的材質(zhì)拖拽到物體身上賦給這個(gè)物體就行了。
?
菜單欄【GameObject】->【Create Other】->【Capsule】或者【Create】下拉菜單->【Capsule】來(lái)在場(chǎng)景中創(chuàng)建一個(gè)膠囊裝的物體。把他拖動(dòng)到和我們的第一人稱(chēng)攝像機(jī)【First Person Controller】很近的地方,這樣方便觀察,接著就可以把我們的“0.TheFirstShader”材質(zhì)直接拖拽給場(chǎng)景中的這個(gè)膠囊,或者Hierachy面板中【Capsule】名字上就行了,操作如下圖中的箭頭所示:
?
?
?
?
?
經(jīng)過(guò)拖拽,Capsule加上Material后的效果如下:
?
?
?
?
?
?
?
?
4.1?給使用Shader的物體加上文字說(shuō)明 ?
?
?
為了以后介紹多個(gè)Shader寫(xiě)法時(shí)能更清晰更方便,淺墨專(zhuān)門(mén)在QianMo’s Toolkit中做了一個(gè)可以在場(chǎng)景中和游戲窗口中分別顯示附加給任意物體文字標(biāo)簽信息的工具腳本,叫做ShowObjectInfo,其詳細(xì)注釋的代碼如下:
?
?
?
[csharp] ?view plaincopy print?
?? ?? ?? ?? #if?UNITY_EDITOR?????? ?? ?? using?UnityEngine;?? using?UnityEditor;?? using?System.Collections;?? ?? [AddComponentMenu("淺墨's?Toolkit?v1.0/ShowObjectInfo")]?? ?? ?? public?class?ShowObjectInfo?:?MonoBehaviour?? {?? ?? ???? ???? ???? ????public?string?text="鍵入你自己的內(nèi)容?by淺墨"; ????public?Camera?TargetCamera; ????public?bool?ShowInfoInGamePlay?=?true; ????public?bool?ShowInfoInSceneEditor?=?false; ????private?static?GUIStyle?style; ?? ?? ?? ???? ???? ???? ????private?static?GUIStyle?Style?? ????{?? ????????get?? ????????{?? ????????????if?(style?==?null)?? ????????????{?? ???????????????? ????????????????style?=?new?GUIStyle(EditorStyles.largeLabel);?? ???????????????? ????????????????style.alignment?=?TextAnchor.MiddleCenter;?? ???????????????? ????????????????style.normal.textColor?=?new?Color(0.9f,?0.9f,?0.9f);?? ???????????????? ????????????????style.fontSize?=?26;?? ????????????}?? ????????????return?style;?? ????????}?? ?? ????}?? ?? ?? ?? ?? ???? ???? ???? ????void?OnGUI(?)?? ????{?? ???????? ????????if?(ShowInfoInGamePlay)?? ????????{?? ???????????? ???????????? ????????????Ray?ray?=?new?Ray(transform.position?+?TargetCamera.transform.up?*?6f,?-TargetCamera.transform.up);?? ???????????? ????????????RaycastHit?raycastHit;?? ???????????? ????????????collider.Raycast(ray,?out?raycastHit,?Mathf.Infinity);?? ?????????????? ???????????? ????????????float?distance?=?(TargetCamera.transform.position?-?raycastHit.point).magnitude;?? ???????????? ????????????float?fontSize?=?Mathf.Lerp(26,?12,?distance?/?10f);?? ???????????? ????????????Style.fontSize?=?(int)fontSize;?? ???????????? ????????????Vector3?worldPositon?=?raycastHit.point?+?TargetCamera.transform.up?*?distance?*?0.03f;?? ???????????? ????????????Vector3?screenPosition?=?TargetCamera.WorldToScreenPoint(worldPositon);?? ???????????? ????????????if?(screenPosition.z?<=?0){return;}?? ???????????? ????????????screenPosition.y?=?Screen.height?-?screenPosition.y;?? ?????????????? ???????????? ????????????Vector2?stringSize?=?Style.CalcSize(new?GUIContent(text));?? ???????????? ????????????Rect?rect?=?new?Rect(0f,?0f,?stringSize.x?+?6,?stringSize.y?+?4);?? ???????????? ????????????rect.center?=?screenPosition?-?Vector3.up?*?rect.height?*?0.5f;?? ?? ?? ???????????? ???????????? ????????????Handles.BeginGUI();?? ???????????? ????????????GUI.color?=?new?Color(0f,?0f,?0f,?0.8f);?? ????????????GUI.DrawTexture(rect,?EditorGUIUtility.whiteTexture);?? ???????????? ????????????GUI.color?=?new?Color(1,?1,?1,?0.8f);?? ????????????GUI.Label(rect,?text,?Style);?? ???????????? ????????????Handles.EndGUI();?? ????????}?? ????}?? ?? ???? ???? ???? ????void?OnDrawGizmos()?? ????{?? ???????? ????????if?(ShowInfoInSceneEditor)?? ????????{?? ???????????? ???????????? ????????????Ray?ray?=?new?Ray(transform.position?+?Camera.current.transform.up?*?6f,?-Camera.current.transform.up);?? ???????????? ????????????RaycastHit?raycastHit;?? ???????????? ????????????collider.Raycast(ray,?out?raycastHit,?Mathf.Infinity);?? ?????????????? ???????????? ????????????float?distance?=?(Camera.current.transform.position?-?raycastHit.point).magnitude;?? ???????????? ????????????float?fontSize?=?Mathf.Lerp(26,?12,?distance?/?10f);?? ???????????? ????????????Style.fontSize?=?(int)fontSize;?? ???????????? ????????????Vector3?worldPositon?=?raycastHit.point?+?Camera.current.transform.up?*?distance?*?0.03f;?? ???????????? ????????????Vector3?screenPosition?=?Camera.current.WorldToScreenPoint(worldPositon);?? ???????????? ????????????if?(screenPosition.z?<=?0)?{?return;?}?? ???????????? ????????????screenPosition.y?=?Screen.height?-?screenPosition.y;?? ?????????????? ???????????? ????????????Vector2?stringSize?=?Style.CalcSize(new?GUIContent(text));?? ???????????? ????????????Rect?rect?=?new?Rect(0f,?0f,?stringSize.x?+?6,?stringSize.y?+?4);?? ???????????? ????????????rect.center?=?screenPosition?-?Vector3.up?*?rect.height?*?0.5f;?? ?? ?? ?? ???????????? ???????????? ????????????Handles.BeginGUI();?? ???????????? ????????????GUI.color?=?new?Color(0f,?0f,?0f,?0.8f);?? ????????????GUI.DrawTexture(rect,?EditorGUIUtility.whiteTexture);?? ???????????? ????????????GUI.color?=?new?Color(1,?1,?1,?0.8f);?? ????????????GUI.Label(rect,?text,?Style);?? ???????????? ????????????Handles.EndGUI();?? ?? ????????}?? ?? ????}?? ?? }?? ?? #endif?? ?
?
這個(gè)腳本的用法倒是很簡(jiǎn)單,在代碼的說(shuō)明部分已經(jīng)詳細(xì)寫(xiě)出,在這里我們?cè)倭谐鲆槐?#xff1a;
?
第一步:在Unity中拖拽此腳本到某物體之上,或在Inspector中[Add Component]->[淺墨's Toolkit v1.0]->[ShowObjectInfo]
第二步:在Inspector里,ShowObject Info 欄中的TargetCamera參數(shù)中選擇需面向的攝像機(jī),如Main Camera,FirstPerson Controller等
第三步:在text參數(shù)里填需要顯示輸出的文字。
第四步:完成。運(yùn)行游戲或在場(chǎng)景編輯器Scene中查看顯示效果。
?
?
也就是拖拽ShowObjectInfo腳本或者直接添加組件給需要附加文字的物體,然后在Inspector中輸入需要顯示的文字,然后選擇其面對(duì)的攝像機(jī)就可以了。
?
?
?
我們將ShowObjectInfo腳本拖拽給上文中剛剛變得炫酷外形黑科技的Capsule:
?
那么他在Inspector就多了一個(gè)“ShowObject Info(Script)”組件,將該組件的Text項(xiàng)中填上“凹凸紋理+邊緣發(fā)光效果”,TargetCamera中填上First Person Controller的子物體Main Camera:
?
?
?
最后,得到的效果就是這樣:
?
?
?
?
?
?
?
?
?
?
?
?
五、總結(jié)、配套資源&最終工程下載 ?
?
?
?
好了,本篇的文章到這里就大概結(jié)束了。
?
今天講的內(nèi)容還是非常多的,對(duì)于新接觸Unity的朋友們來(lái)說(shuō)或許還得好好消化消化,而熟悉Unity的朋友應(yīng)該很快就可以看懂,或者覺(jué)得淺墨講了一堆廢話(huà),orz。
?
這篇文章的內(nèi)容說(shuō)白了就非常簡(jiǎn)單,也就是新建工程,然后導(dǎo)入三個(gè)淺墨提前準(zhǔn)備好的unitypackage游戲資源,點(diǎn)一點(diǎn)鼠標(biāo)拖動(dòng)拖動(dòng)腳本,新建一個(gè)Shader,寫(xiě)點(diǎn)代碼,再創(chuàng)建一個(gè)Material,Shader賦給這個(gè)Material,最后創(chuàng)建一個(gè)膠囊狀Capsule,Material賦給這個(gè)Capsule,點(diǎn)運(yùn)行查看最終效果。一切,就是這么簡(jiǎn)單。:)
?
?
本文配套的三個(gè)unitypackage打包請(qǐng)點(diǎn)擊此處下載:
?
【淺墨Unity3D Shader編程】之一 配套的三個(gè)unitypackage打包下載
?
?
?
本文最終的Unity工程請(qǐng)點(diǎn)擊此處下載:
?
【淺墨Unity3D Shader編程】之一 配套Unity工程
?
?
?
最后放幾張最終的場(chǎng)景美圖吧。
?
站在亭子上看世界:
?
?
?
逼真的光暈:
?
?
?
漂亮的天空:
?
?
?
?
亂真的水面:
?
?
?
藍(lán)天和草地樹(shù)木交相輝映:
?
?
?
?
OK,全文到此結(jié)束。
新的游戲編程之旅已經(jīng)開(kāi)啟,下周一,我們不見(jiàn)不散。
?
轉(zhuǎn)載于:https://www.cnblogs.com/lifesteven/p/5613101.html
總結(jié)
以上是生活随笔 為你收集整理的shader 编程入门(一) 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。