曾經(jīng)缭保,我的第一臺電腦找不到顯卡驅(qū)動蘸朋,常年只有16色。
1. 調(diào)色板是干什么的
舊社會的時候以前機能不好的時候韩容,同屏顏色數(shù)受限款违,經(jīng)常只有16色或更少。每個像素顯示哪種顏色也不是用RGB來記錄的群凶,而是記錄一個顏色索引值插爹,到繪制這個像素時用這個索引去尋找真正的顏色(經(jīng)常仍然是一個索引值,笑)请梢。這個顏色索引表格赠尾,就是像素游戲時代的調(diào)色板。
基本上毅弧,歷史上應用調(diào)色板的思路我能想到的有四種:
- 為像素角色更換皮膚
這個是最容易想到的气嫁。比如角色身上的衣服用同一種顏色繪制,改變這個索引的顏色就可以改變衣服的顏色够坐。
除了換衣服之外寸宵,策略游戲的團隊色也可以用調(diào)色板來做。
- 突破顏色數(shù)限制
《三國志IV》是我非常喜歡的一款游戲元咙。他的很多細節(jié)非常值得推敲梯影。比如,這是一款同屏16色的游戲庶香,而武將的頭像就用掉了8色光酣。(順帶一提,這8種顏色因為不可能變動脉课,所以也被用在UI上救军。)留給環(huán)境繪制的顏色不多了。然而《三國志IV》還是可以表現(xiàn)從南到北倘零、一年四季的景色變化唱遭,它是怎么做的呢?
答案就是改變調(diào)色板。當我們從北到南卷動地圖時袖瞻,可以發(fā)現(xiàn)地圖的顏色不是從北到南漸變的司致,而是隨著視角的移動,整體改變顏色聋迎。在北方時整體飽和度低脂矫,到南方整體飽和度高。
假設地圖上沒有任何細節(jié)霉晕,那么只需要消耗一個顏色索引就能實現(xiàn)從北到南的顏色變化庭再。只要平滑地改變索引顏色,就可以使最終的效果非常平滑牺堰。當然游戲中實際添加了大量的草拄轻、山、水等細節(jié)伟葫,這些細節(jié)的顏色也隨著視角移動而改變恨搓。這樣就看起來更自然了。
那么筏养,同屏還是不超過16種索引顏色斧抱,但是在游戲全程能夠呈現(xiàn)的顏色遠遠不止這么點。
老游戲經(jīng)常用這種方法獲得不同風格的場景顏色撼玄,或者在轉(zhuǎn)場時做FadeOut夺姑。
- 調(diào)色板動畫
把『改變索引顏色』這件事做到極致,變成『時刻不停地改變顏色』掌猛,就得到了調(diào)色板動畫盏浙。下面這張圖可以很明顯地感受到瀑布是由幾個固定索引繪制的。
通過改變索引顏色實現(xiàn)動畫的最大意義在于——節(jié)省資源荔茬。只需要一張圖就能做動畫了废膘。隨著存儲越來越不值錢,調(diào)色板動畫逐漸被幀動畫或者sprite動畫替代了慕蔚。
- 受攻擊或者buff特效
例如受到攻擊發(fā)亮的效果丐黄、boss血量低下時閃紅的效果、無敵時亮閃閃的效果等等孔飒,請回憶一下童年灌闺。
2. 調(diào)色板在今天
今天艰争,調(diào)色板仍然存在。大家在繪制像素畫時仍然有意識地控制自己使用的顏色桂对。(畢竟不限制顏色的像素畫就不怎么『像素』了甩卓。)不過隨著顯示設備和存儲設備的進步,即便是在像素游戲里蕉斜,在游戲技術層面大家往往也不太關注調(diào)色板了逾柿。
今天,完美繼承了調(diào)色板思想的應用是……美圖濾鏡机错。(望天
顏色濾鏡可以理解為將每一種顏色映射為另一種顏色。效率最好的實現(xiàn)就是將這種映射提前記錄下來父腕,存成一張查找表弱匪,從而得到了Color Lookup Table侣诵。
很明顯,顏色本身的RGB就成了256 * 256 * 256的三維索引杜顺,這個LUT的圖就是調(diào)色板财搁。
游戲中也有用LUT的實例躬络,比如這篇文章提到了在Grave Keeper中使用LUT實現(xiàn)不同時間的光照。
2D游戲的光照和顏色是一個大話題穷当,以后可能會說吧……本文的重點不在這里提茁,我們先從最原始的調(diào)色板開始討論。
3. 實現(xiàn)簡單的調(diào)色板
How to Use a Shader to Dynamically Swap a Sprite's Colors這篇文章給了一個非常簡明的思路:用圖像的一個通道作為索引(所以是256色的調(diào)色板)茴扁,到一張一維的紋理上查找顏色。
Shader改動前:
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
改動后:
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord);
fixed4 swapCol = tex2D(_SwapTex, float2(c.r, 0));
fixed4 final = lerp(c, swapCol, swapCol.a) * IN.color;
final.a = c.a;
final.rgb *= c.a;
return final;
}
注意這個實現(xiàn)其實是基于顏色替換汪疮,所以調(diào)色板的透明度可以決定顏色替換的比例,不過這不是本文重點智嚷。我們就當做剛健樸實的調(diào)色板來用卖丸。
原圖、調(diào)整顏色的結果盏道、使用的調(diào)色板如下:
原圖只有四種顏色稍浆,所以調(diào)色板里只有4條線,就對應著那4個顏色。另外為什么調(diào)色板背景是灰色的衅枫?只是為了debug嫁艇。
在Unity中的注意事項:
- 原圖和調(diào)色板圖的Filter Mode都選擇Point
- 原圖和調(diào)色板圖的Compression都選擇None
否則像素顏色和位置都是不準確的,不會得到想要的結果为鳄。
這個實現(xiàn)是用r通道實現(xiàn)的256色調(diào)色板裳仆,如果用r、g通道一起做索引孤钦,就得到了16位色調(diào)色板。遠遠超過一般像素游戲的需要了纯丸。
當然在實際應用中我們不會用左側那種原圖偏形。實際的做法我們放在最后討論。先在基礎靜態(tài)調(diào)色板的基礎上看看能做什么觉鼻。
4. 動態(tài)調(diào)色板
How to Use a Shader to Dynamically Swap a Sprite's Colors這篇文章里已經(jīng)給了動態(tài)改變調(diào)色板的實現(xiàn)了俊扭。我懶得畫圖了,鴿了鴿了坠陈。
5. 調(diào)色板動畫
調(diào)色板動畫的思路就是隨時間改變調(diào)色板萨惑。在剛才的靜態(tài)例子中我們只用到了一維的紋理,那么把第二個維度用于時間映射就好了仇矾,是不是很簡明庸蔼。
說起調(diào)色板動畫最簡單的就是做個水流或者瀑布了。首先我做了一個大概這樣的瀑布效果圖:
接下來生成索引圖刻盐,也就是用r通道記錄顏色索引:
什么都看不出來就對了掏膏。因為這張圖只用到了16種顏色,所以r通道最大只有15敦锌,g馒疹、b都是0。
接下來是調(diào)色板圖乙墙。按照設想颖变,顏色應該是循環(huán)映射的,這樣水才能循環(huán)流動起來伶丐。最后做出來的調(diào)色板圖類似這樣:
把二者結合就做出了這樣的動畫:
調(diào)色板動畫可以節(jié)省大量的存儲空間肛走,并且可以通過更換調(diào)色板改變效果。比如這張瀑布的圖可以很容易地通過改顏色改成流下的粘液或者熔巖录别。
調(diào)色板紋理的第二個維度可以干很多事朽色,例如描述同一對象的不同皮膚邻吞,或者同一對象在一天內(nèi)不同時間的顏色等等。
5. 如何愉快繪制
一個現(xiàn)實的問題是葫男,怎么導出索引顏色的原圖抱冷,以及怎么導出調(diào)色板。
我的做法是這樣的:
我用的工具是Aseprite梢褐,創(chuàng)建一個使用索引顏色的圖:
首先確定一個場景用多少顏色旺遮,以瀑布為例是16種顏色,我們就隨便建立一個16色的調(diào)色板然后開始畫:
這一步能夠區(qū)分出所畫的顏色盈咳、便于繪制就可以耿眉,顏色不一定十分正確。
然后我們手動建立一個調(diào)色板文件鱼响。類似下面這樣:
GIMP Palette
#
0 0 0 Untitled
1 0 0 Untitled
2 0 0 Untitled
3 0 0 Untitled
4 0 0 Untitled
5 0 0 Untitled
...
254 0 0 Untitled
255 0 0 Untitled
在剛才那種圖里載入這個調(diào)色板鸣剪,就會將顏色索引映射到(0, 0, 0)、(1, 0, 0)丈积、(2, 0, 0)……這樣的顏色上筐骇。這時候再導出就得到了我們想要的索引圖。
調(diào)色板圖的制作方法是把這個過程反過來:
- 先建立一張256x1的圖
- 每個像素依次填入index=0、index=1……的顏色
- 載入繪制效果圖所用的調(diào)色板文件(比如剛才的瀑布所用的16色調(diào)色板)牙寞,這樣每個索引所在的位置都被對應的顏色著色了
- 導出
這樣導出的是用于一幀的調(diào)色板饺鹃。如果要做多個調(diào)色板就反復進行這個步驟间雀,然后把圖拼起來。
實際上具體問題具體分析惹挟。在做瀑布的調(diào)色板動畫時我是手動編輯的,因為大體上每幀之間就是顏色循環(huán)连锯。用圖像編輯軟件處理的時候還能統(tǒng)一改改飽和度亮度之類的,更方便一些运怖。