關于《Thinking in Unity3D》
筆者在研究和使用Unity3D的過程中,獲得了一些Unity3D方面的信息,同時也感嘆Unity3D設計之精妙。不得不說,筆者最近幾年的引擎研發工作中,早已習慣性的從Unity3D中尋找解決方案。
什么是材質?
材質是一個相對廣泛的概念,不同的專業領域有不同的定義。 在此也不一一舉例說明了,我們只說在3D游戲引擎中,材質的定義。
材質的本質定義,是指能夠描述一個物體的顯示外觀的一系列數據。它包括幾個方面
1、渲染狀態
渲染狀態是指早期的setRenderState那一套東西。比如,前后面裁剪,是否開啟混合,混合因子等等。
2、著色方式
著色方式,在固定管線年代,是通過一系列的API進設置。 在可編程管線年代。就對應的是我們的著色器代碼。
3、參數
不管是固定管線還是非固定管線,我們都可以設置一些參數用于著色計算。比如顏色,光源信息等等
4、紋理貼圖
紋理貼圖是表現一個物體表現的顏色細節的必不可少的東西。就是一張張圖片。
有了上面的這些數據后,我們就可以根據一定的運算規則,將一個幾何體的質感顯示為我們想要的樣子。
材質、Shader、模型關系圖
材質系統的常見需求
一個工具或者系統的設計不可能是憑空而出的。 一定是根據需求和經驗的積累,才形成了我們今天這種“材質系統”的概念。 說到這里,那么我們常見的材質系統需要做到什么樣子呢。
一、模板 + 實例
材質是一個模板,通過對某一個材質進行實例化,指定不同的數據和貼圖,就可以讓物體表現出不同的顯示效果。 和Class + Object的關系很像。
二、多Pass
有時候,我們為了實現一個繪制效果,靠單次繪制是無法實現的。比如描邊效果。 這就要求我們單個物體能夠在進行繪制的時候,多次提交材質并繪制。
三、多Technique
多Technique是指一個材質中,應該包含不只一個實現方案。 這樣當我們進行材質更替,或者進行高中低端機適配的時候。 就不會那么麻煩。 同時在數據管理上,也顯得更為規范。
四、高中低端機適配
高中低端機適配是一個很重要的特性,因為玩家的機型不可能是一樣的。 在需要保證效率的情況下,我們很多時候需要降低物體渲染的復雜度。在《3D游戲中的畫質與效率適配》一文中。筆者也描述過,有兩種方案。 一種是通過宏定義,一種是動態切換Technique。
總結下來,就是說一個材質模板文件應該像這樣的一個結構
MaterialTemplate
{
Technique
{
Pass{}
Pass{}
}
Technique
{
Pass{}
Pass{}
}
}
Unity3D中的材質系統
在說到Unity3D中的材質系統的時候,我們先來看一下我們創建一個材質需要做的事情。
一、創建一個Shader并編寫出自己想要的效果
二、創建一個Material并將這個Material的Shader指定為自己的材質
三、為這個Material設置參數,賦上貼圖等
四、將創建好的Material拖到對象上
我們再來看一個典型的Shader應該具備的內容
Shader "MyShader" { Properties { _MyTexture ("My Texture", 2D) = "white" { } // other properties like colors or vectors go here as well } SubShader { LOD 100 // here goes the 'meat' of your // - surface shader or // - vertex and program shader or // - fixed function shader Pass{} Pass{} } SubShader { LOD 1000 // here goes a simpler version of the SubShader // above than can run on older graphics cards Pass{} Pass{} } }
我們可以看到。 每一個Shader有多個SubShader,每一個SubShader有多個Pass。 這樣看起來和我們前面提到的MaterialTemplate結構幾乎一致。
而在Unity3D中。Shader就是材質模版。 Material就是一個材質實例。 每一個Material你可以認為是一個材質實例的序列化存儲。
Unity3D中的材質LOD
那對于前面提到的 高中低端機適配。 有兩種方法解決。一是通過宏定義,這個并不是Unity3D的推薦方式,且需要Shader編寫的相關知識,在這里不作詳細討論。 如果有興趣的朋友,可以訪問括號中的鏈接(http://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html),以后的文章在涉及Unity3D的Shader編寫方面的內容時,再進行討論。 在此主要討論Unity3D中通過材質LOD進行畫質控制。
在Unity3D的Shader中,可以為每一個SubShader指定一個LOD值,這個LOD值可以通過設置Shader.globalMaximumLOD和Shader.maximumLOD來實現SubShader的切換。所有的SubShader按順序進行判定,當一個SubShader滿足下面兩個條件時,才表明可用。
1、SubShaderLOD值小于設定的值。(你可以把LOD看作是開銷,開銷越大的SubShader指定越高的LOD值)
2、SubShader所有Pass使用到的顯卡特性被當前設備支持。
注:Shader API文檔地址:http://docs.unity3d.com/ScriptReference/Shader.html
注:Shader LOD文檔地址:http://docs.unity3d.com/Manual/SL-ShaderLOD.html
注:Unity3D為每一檔的內置Shader都設置了一個默認值,在LOD文檔中有
注:如果不指定LOD值,那LOD=infinite 。 你可以當它是一個小于0的值。
注:這個值除了可以自己給以外,還可以在Edit->Project Settings->Quality面板中指定,如下圖
設置面板
Unity3D中的材質替換
官方文檔地址:http://docs.unity3d.com/Manual/SL-ShaderReplacement.html
夜視效果
有時候,我們希望能夠進行一些特殊操作。將場景物體的按另一種渲染方式渲染到RT中。 比如,僅渲染物體的深度,把物體渲染成純白,把物體渲染成紅綠熱成像模式等等。但是,我們的材質在一開始就指定好了。如果要替換的話,就需要遍歷所有對像,為它們重新指定材質。渲染完畢后,再切換回來。Unity3D為我們提供了更直接的方式。Camera.RenderWithShader和Camera.SetReplacementShader。前者是僅作用一次,后者是一直生效,如果想取消設置。 使用Camera.ResetReplacementShader即可。
那么問題來了,我們有時候只想渲染一些特殊的物體。比如,我們想處理除主角以外的內容。 這就需要對主角進行剔除。 那上面兩個函數的第二個參數replacementTag就起作用了。如果設置了它,在進行材質替換時,它會和SubShader中的 RenderType的值 進行比對。 比如,我們即將替換的材質如下。
Shader "EffectShader" { SubShader { Tags { "RenderType"="Opaque" } Pass { ... } } SubShader { Tags { "RenderType"="SomethingElse" } Pass { ... } } ... }
如果我們調用了camera.SetReplacementShader (EffectShader, "RenderType");那么,一個物體在被渲染時,會產生以下幾種結果。
1、如果物體當前激活的SubShader的RenderType是Opaque,那么將會采用EffectShader的第一個SubShader。
2、如果物體當前激活的SubShader的RenderType是SomethingElse,那么將會采用EffectShader的第二個SubShader。
3、如果物體當前激活的SubShader的RenderType在EffectShader中沒有與之對應的項,此物體將會在渲染中被忽略。
4、如果物體當前激活的SubShader沒有RenderType這個Tag,此物體將會在渲染中被忽略。
結束語
Unity3D擁有著一個靈活的渲染管線和自由的材質系統。與其它圖形引擎不一樣的是,Unity3D針對游戲需求所留出來的接口非常好用。
而本文僅僅是對Unity3D的材質系統進行初步的描述。要想完全把Unity3D的材質系統總結出來,不是一兩篇文章可以搞定的。Unity3D文檔中的 Shader Reference可以作為一個十分不錯的開始http://docs.unity3d.com/Manual/SL-Reference.html
文章列表