獨立游戲《FISH 魚》開發(fā)日志系列 - 為Unity3D構(gòu)建程序化的Sprite材質(zhì)系統(tǒng) - Part 1
在過去的一周里,5.23-5.31,我所做的主要工作是,為FISH里的Sprite定制特殊的程序化的效果。FISH場景當(dāng)中,石頭是很重要的一部分,如何利用有限的資源,盡量少的存儲空間,去實現(xiàn)最豐富的效果,是我們需要達(dá)到的目標(biāo)。
FISH場景里的石頭基本上采取的設(shè)計思路是:形式盡量相同,或者自相似,類似分形的邏輯;色彩上可以有多重變化,這樣即便形狀相似,也不會覺得太單調(diào)。在13年的FISH的版本中,所有的石頭,都是直接在PS里繪制完成,石頭的繪制,用了很多PS里的圖層組混合模式(Blending Option)來完成,本身就是一種程序化的繪制方式。參見火星網(wǎng)的專訪
(上圖為PS里石頭的涂層疊加屬性繪制方法)
因此我們在想,既然石頭本身就是程序化的方式繪制出來的,為何不把這套流程搬進(jìn)Unity里,這樣就能夠減少2d材質(zhì)的用量,做到精簡游戲呢,相當(dāng)于直接在Unity里畫出來這些石頭。當(dāng)然,隨便一想就知道,要把PS里的豐富的涂層混合選項(Blending Option)搬進(jìn)Unity很定很費事兒,并且,偏離了我們做游戲的初衷,因此
先分析一下目前石頭是怎么畫的,然后看哪些特征是可以畫在PS里的,哪些特征是需要大量改變的,區(qū)分出這些,比較有利于我們在unity里用最少的力氣實現(xiàn)相應(yīng)的功能。因此簡化一下PS里的工作流,大致可以得到下面這個表。
所以基本上,我們能夠方便的調(diào)整的就是,1. 石頭的基本色,2. 石頭的疊加的紋理材質(zhì),3.石頭的混合顏色(Tint Color),4.以及Tint Color是如何和原本的石頭進(jìn)行過渡的。
因此在明確了這些需求之后,我們就就設(shè)計了Sprite的工具。基本的Inspector是長這個樣子的。
基本上就是2部分組成:Pattern Blend (紋理材質(zhì)疊加)和Tint Blend (混合顏色疊加)。
GIF圖show下:
1. Pattern Blend Mode(紋理材質(zhì)混合模式)
這個功能可以讓我們方便的切換紋理材質(zhì)和基本的sprite 是如何混合的,和PS里圖層混合模式是一個原理。
2. Pattern Blend Opacity (紋理材質(zhì)疊加透明度)
這個功能可以方便的控制紋理材質(zhì)的透明度,石頭的紋理一般都是非常細(xì)膩的,往往透明度無法設(shè)的太高,需要調(diào)整到合適的值才能獲得整體上比較好的效果。
3. Pattern Blend TRS (紋理材質(zhì)的平移旋轉(zhuǎn)和縮放)
4.Tint Color Blend Mode (混合顏色的混合模式)
5. Tint Color Blend Texture TRS (混合顏色的混合材質(zhì),以及其平移旋轉(zhuǎn)縮放)
基本上就是這些功能,沒有用到太高級的東西。大概講一下實現(xiàn):
1. Shader部分主要是使用了一些多重編譯關(guān)鍵字,來支持Sprite對應(yīng)的Shader功能,Pattern Blend 開關(guān),Tint Blend開關(guān),以及二者對應(yīng)的混合模式都是由不同的shader_feature 關(guān)鍵字定義的,可以方便的在對應(yīng)的mono腳本中使用Material.EnableKeyword(string k)來實現(xiàn)相應(yīng)功能的開關(guān)。另外需要注意的是,關(guān)鍵字是有數(shù)量限制的,每一組關(guān)鍵字組合都會被編譯成一個獨立的shader,如果用了太多的關(guān)鍵字,就會導(dǎo)致shader加載時間過長。這這個工具里,我使用了一個Shader文件,但是因為里面用了4組關(guān)鍵字,一共有2*4*2*4=64種組合,因此實際上這個shader最后需要被編譯成64個不同的版本, 也因此,不同的功能組合實際上使用的是不同的material,因此無法batching在一起。而因為此,使用同一材質(zhì)的Sprite,他們無法設(shè)置獨立的?[是否使用Pattern]?[Pattern Blend Mode] [是否使用Tint] [Tint Blend Mode] 這些選項。這點需要注意。
2. shader中的其他的參數(shù)的修改,例如TRS,透明度等是通過MaterialPropertyBlock來實現(xiàn)的。Sprite往往需要共享材質(zhì),在確定了上面所說的關(guān)鍵字組合后,往往同一類石頭會使用同一個材質(zhì),而每個石頭具體的材質(zhì)參數(shù)是獨立的。MaterialPropertyBlock可以通過SpriteRender的Renderer.GetPropertyBlock來獲取。通過設(shè)置每個Renderer的MaterialPropertyBlock,能夠方便的為使用同一個材質(zhì)的sprite指定不同屬性,同時獲得較高的性能。
3. 由于MaterialPropertyBlock本身[不支持]?序列化,因此Mono腳本中需要把材質(zhì)參數(shù)進(jìn)行序列化,然后在腳本的Start()中,進(jìn)行設(shè)置。
目前的問題是,由于使用了大量復(fù)雜的像素shader操作,因此可以想象在平板上的性能不會太好。由于這個是一個面向設(shè)計師的工具,sprite的特效在runtime基本不需要改變,因此未來可以考慮,將生成的特效渲染一次到材質(zhì)上,然后再使用。動態(tài)的加載和釋放這些rendertexture應(yīng)該會更高效。當(dāng)然這個功能略有些復(fù)雜,目前還是先暫時不考慮。
基本上暫時想到這么多,之后的DevLog 里,我會講講如何讓這個系統(tǒng)變得更加易用,如何克服上面提到的無法獨立設(shè)置shader feature 的問題,另外還會展示,如何用這個工具,結(jié)合關(guān)卡設(shè)計的考慮來進(jìn)行創(chuàng)作。
如果您覺得這篇文章內(nèi)容不錯,請關(guān)注我們的微博