程序繪畫——用代碼畫一個(gè)黑白棋盤格
相信很多朋友們第一次接觸“程序繪畫”是在小學(xué)時(shí)期信息技術(shù)課,課本上介紹了一種名叫海龜繪圖(Turtle Graphics)的有趣軟件?;叵胍幌?,我們是怎么讓小海龜運(yùn)動(dòng)起來的?答案是:利用代碼。1996年,Seymour Papert和Wally Feurzig發(fā)明了一種專門給兒童學(xué)習(xí)編程的語言——Logo語言,我們正是利用這種語言指揮海龜在屏幕上繪圖的。然而隨著時(shí)代的發(fā)展,Logo已經(jīng)漸漸淡出人們的視線,主流的繪圖方式也發(fā)生了改變。
?
本文介紹的是如何利用著色器(下文寫作Shader)語言達(dá)成繪制3*3棋盤格效果,筆者在這里借助了UE4進(jìn)行演示。如果感興趣的話可以在Unity或者其他在線渲染網(wǎng)站(例如ShaderToy)中利用本文例舉的算法進(jìn)行嘗試。
?
為什么程序繪畫的第一篇文章講的是棋盤呢?因?yàn)槠灞P格子的繪制是程序繪畫中較為基礎(chǔ)的部分,原因是實(shí)現(xiàn)這個(gè)效果的算法比較簡單,可以通過演算輕松的得到結(jié)果,對(duì)感興趣但又不是很了解Shader的同學(xué)比較友好。不過由于涉及到一些術(shù)語,**這篇文章推薦有一定計(jì)算機(jī)圖形學(xué)基礎(chǔ)的同學(xué)閱讀**。那么話不多說,我們正式開始吧!
?
一、開始繪制
打開我們強(qiáng)大的UE4的Shader?Graph,我們正式準(zhǔn)備開始繪圖。首先我們要做的事情是將texcoord(一組紋理坐標(biāo))節(jié)點(diǎn)連接到輸出根節(jié)點(diǎn)的base?color上,會(huì)得到以下效果(圖1):

這是個(gè)什么東西,它是怎么得到的?(怎么說呢,它看起來真的很像某種水果。)首先我們要明確的是:texcoord節(jié)點(diǎn)儲(chǔ)存了一組紋理坐標(biāo),它的范圍從0?~?1。如果我們以圖1中的矩形的左上角為原點(diǎn)建系,并且讓y軸指向下方,那么texcoord對(duì)應(yīng)的(0, 0)坐標(biāo)就指的是左上角,(1, 1)指的就是右下角。同時(shí),我們將texcoord節(jié)點(diǎn)連接到了base?color上,后者需要一個(gè)Vector3類型的變量(分別指代顏色的RGB)作為輸出,而texcoord的紋理坐標(biāo)是一個(gè)Vector2類型,差了一個(gè)分量。幸運(yùn)的是引擎很聰明地自動(dòng)幫我們加上了0作為第三個(gè)分量,所以實(shí)際上左上角對(duì)應(yīng)的顏色是(0, 0, 0),即黑色;右下角對(duì)應(yīng)的顏色是(1, 1, 0),即黃色。
?
為了進(jìn)一步驗(yàn)證我們的想法是否正確,可以手動(dòng)把 “1” 作為第三個(gè)分量,當(dāng)輸入進(jìn)base?color后,我們會(huì)得到圖2所示的結(jié)果。在圖2的情況下,左上角的輸出是(0, 0, 1),右下角的輸出是(1, 1, 1),符合預(yù)期結(jié)果。

二、數(shù)學(xué)處理
現(xiàn)在我們的數(shù)據(jù)呈現(xiàn)完美的連續(xù)狀態(tài)。如果我們想要得到分明的棋盤格子的話,這意味著我們需要把連續(xù)的數(shù)據(jù)轉(zhuǎn)變成“平臺(tái)”。在這里,我們可以通過引入Floor函數(shù)對(duì)坐標(biāo)進(jìn)行取整來實(shí)現(xiàn)。Floor函數(shù)可以把小數(shù)向下取整,得到一段數(shù)據(jù)。但是我們需要三行三列格子,怎么辦呢?我們可以通過乘以3得到3段數(shù)據(jù),如3圖所示:

看上去效果不太對(duì)?原因是顏色分量超出1的部分被按照1來計(jì)算了,所以出現(xiàn)了區(qū)域顏色一致的情況。實(shí)際上右下角的格子的數(shù)據(jù)是(2, 2, 0),但輸出的效果卻是(1, 1, 0),便得到了黃色。如果我們對(duì)這些數(shù)據(jù)除以2,就可以讓九宮格的顏色區(qū)分開來,如圖4所示:

我們離最終的效果已經(jīng)很接近了。觀察一下現(xiàn)在的棋盤,每個(gè)格子的數(shù)據(jù)分別是:
(0, 0, 0) ?????(0.5. 0, 0) ????(1, 0, 0)
(0, 0.5, 0) ???(0.5. 0.5, 0) ???(1, 0.5, 0)
(0, 1, 0) ?????(0.5. 1, 0) ????(1, 1, 0)
相信你一定已經(jīng)發(fā)現(xiàn)其中有趣的規(guī)律了。如果我們針對(duì)每個(gè)格子單獨(dú)輸出其R通道的值,就會(huì)得到黑灰白三色的豎條(圖5);如果我們針對(duì)每個(gè)格子單獨(dú)輸出其G通道的值,就會(huì)得到黑灰白三色的橫條:

如果我們把R通道和G通道相加是不是就可以得到棋盤格子了呢?不,我們會(huì)得到圖6所示的結(jié)果:

結(jié)果很不盡人意,這是因?yàn)槌龅牟糠侄急蛔詣?dòng)變成了1。同時(shí)棋盤雛形上還有灰色的塊,而我們想得到的是一個(gè)黑白的棋盤,也就是說最終輸出的顏色只能有(0, 0, 0)和(1, 1, 1)。怎么實(shí)現(xiàn)黑白的效果呢?其實(shí)現(xiàn)在九宮格的數(shù)學(xué)結(jié)果是這樣的(圖7):

這時(shí)候我們只要取小數(shù)就能得到相對(duì)理想的“灰白棋盤效果”了。想要得到“黑白棋盤效果”,我們只需要對(duì)(0.5, 0.5, 0.5)的灰色乘上2即可。最終得到的效果如圖8所示。如果我們希望增加棋盤的行列數(shù),可以在前面進(jìn)行floor操作時(shí)給texcoord乘上更大的值。


作者:時(shí)光
審核:東達(dá)