棋盤格與幻影坦克
看本篇文章前先溫習下我的幻影坦克架構指南(一)
這篇文章主要要解決的問題是,在電腦上比如說在QQ群中,我點開一張幻影坦克,因為背景不是純黑的,所以會導致別人看到的時候會出現白底的幻影。
比如像這樣:
不管是白底還是黑底,感覺都不太正常,仔細看都能看出影子出來。
本篇文章只對灰度圖進行討論,並且假設,QQ聊天背景為白色,那麼把圖片拉到白色背景的時候,我們圖片的背景顏色值差不多 為0.5的灰色,顏色計算公式差不多為:
alpha計算公式為:
好的,確定下目標:為了讓灰底顯示的圖片與黑底的差不多。那麼就是 ,受到我們控制的只有alpha這個值,所以圖片每個像素的透明度越高,那麼我們在QQ上打開的效果越好,也就是說在教程1裡面提到的為了解決問題:
如果是灰度圖,那麼對每個像素 也就是 ,因為alpha值的值域就是[0,1],如果超過就不正常。處理的做法就是將 縮小一定的比例(圖像顯示上就是變暗),因為對 顏色進行放大容易超過1,從而導致 顏色信息丟失。
教程1中黑底圖的亮度縮小了一定的比例,所以 會變得很大,因為 變小了,並且如果白底為黑色,而黑底為白色的時候,不管縮小多少都會顯示出來。
所以本文的最終目標是:尋找一種保證黑底的亮度不被縮小,並且還要解決QQ發出來的白底圖會出現黑底圖幻影的問題。
白底:
黑底
不調低黑底的亮度,合成出來的圖片:
白底
完全被黑底給覆蓋了,理由也很簡單,黑底的顏色亮度比白底高,導致alpha值為1,直接就拿背景色來顯示,顯然不可取。
那麼怎麼辦?這裡用到兩個技術,一: 棋盤的靜態渲染,二:人眼的柵格錯覺。
棋盤渲染:PS4pro所謂棋盤渲染到底是什麼概念? - 一疼的回答 - 知乎
https://www.zhihu.com/question/50716623/answer/124122543柵格錯覺:如何解釋這張「永遠追不到的黑點」圖? - 暗涌的回答 - https://www.zhihu.com/question/38874715/answer/82533109
了解了之後,我們來構造兩張圖(重點,敲黑板)
白底:
被我標記出來的顏色坐標為原來的顏色,沒有標記出來的,為白色。記住(同奇同偶)。
黑底:
被我標記出來的顏色為原來的顏色,沒有標記出來的為黑色。(不是同奇同偶數)
沒錯兩張圖片計算alpha值的時候,可以不用擔心黑底的顏色亮度比白底的高!因為黑底對應計算的白底值為 ,而白底對應黑底計算值 也就是 值永遠坐落於0~1之間,所以就沒有必要調低黑底的亮度了。
而背景色為灰色的時候,我們利用眼睛的柵格錯覺(屏幕解析度越高越好),會自動幫我們把顯示出來的顏色與相鄰的顏色插值,讓人眼感覺圖片顯示的暗一點。
棋盤格合成出來的效果:
白底:
黑底:
QQ上發出來的效果:
QQ上點開放大的效果:
關鍵代碼:
private void SetWhiteColor(Bitmap picture) {n int width = picture.Width;n int height = picture.Height;n for (int i = 0; i < width; i++) {n for (int j = 0; j < height; j++) {n if ((i + j) % 2 == 0) {n Color c = Color.FromArgb(255, 255, 255, 255);n picture.SetPixel(i, j, c);n }n }n }n}nnprivate void SetBlackColor(Bitmap picture) {n int width = picture.Width;n int height = picture.Height;n for (int i = 0; i < width; i++) {n for (int j = 0; j < height; j++) {n if ((i + j) % 2 != 0) {n Color c = Color.FromArgb(255, 0, 0, 0);n picture.SetPixel(i, j, c);n }n }n }n}n
PS為什麼不討論彩色坦克呢?
因為彩色坦克都是以犧牲亮度跟色彩來保證黑底為彩色的,詳見:幻影坦克架構指南(三),如果犧牲色彩的話,那就是本文的內容了,犧牲亮度絕對不可取,因為會導致 過大。
所以本文也算是幻影坦克系列的終結文章吧,理論上在QQ聊天上的幻影坦克也到此為止了。
自己寫了個工具,下載地址:
鏈接:/s/1dkWLhO 密碼:lt32
推薦閱讀:
※一口氣解決RenderQueue、Ztest、Zwrite、AlphaTest、AlphaBlend和Stencil
※關於Unity動畫系統優化,你可能遇到這些問題
※一個關於渲染管線中坐標變換的簡單實例
※Unity3D插件開發教程(四):獲取地址組件