六、紋理對映(圖形渲染系列)
Shading Frequencies(著色頻率)
Flat Shading
對面求法線著色,面上所有畫素共用這個顏色。
Gouraud Shading
對三角形的三個頂點求出法線,分別著色,三角形內部插值出畫素顏色,平滑過渡。
Phong Shading
對三角形的三個頂點求出法線,分別著色,三角形內部插值出畫素法線,計算著色。
重心插值
三角形中任意一個點的資料,可以根據三個頂點資料插值獲得。
圖形學中,我們的操作更多的是頂點,從頂點到內部畫素過渡,需要插值。
紋理對映
UV座標
模型上的三角形和UV貼圖上的三角形頂點是對應的;我們根據頂點插值出三角形內部畫素的UV座標,然後去UV紋理查詢顏色。在Blinn Phong 反射模型中,我們可以認為這個值就是漫反射係數
。
紋理對映的問題
紋理過濾
螢幕中模型表面有自己的解析度設為mxn;貼圖也有自己的解析度設為axb;我們要把貼圖對映到模型表面,由於他們的解析度極大可能不一樣,即無法一一對應,貼圖會變得模糊、錯位。所以需要紋理過濾。
紋理解析度太小引起的問題
Nearest Point Sampling(就近紋理取樣)
當我把一個低解析度的貼圖,對映到螢幕中高解析度物體表面時。比如貼圖解析度256x256,螢幕中一面牆解析度為1024x1024。則螢幕畫素區域
進行UV對映的區域為
,對應到紋理上的區域為
= [0,
]。紋理畫素不存在小數的情況,四捨五入,發現螢幕上的16個畫素對應紋理上的1個畫素,導致鋸齒髮生。
Bilinear interpolation (雙線性插值)
找到紋理畫素鄰近4個畫素的位置,分別在水平和垂直方向做線性插值。把結果再做一次線性插值。
Bicubic interpolation(雙三次插值)
取附近16個點插值。
紋理解析度太大引起的問題
我們把網狀格子紋理對映到一個平面。如果只是簡單的取樣:根據一個畫素的中心點判斷是否在三角形內。會導致如下圖右邊的情況。近處出現鋸齒,遠處出現摩爾紋。
為什麼會出現這種情況呢?
紋理中每個格子所佔用紋理畫素個數是固定的,比如nxn。在螢幕中因為投影的關係近處的格子放大,會有更多的螢幕畫素來表示一個格子比如8nx8n,這導致螢幕上的多個畫素對應紋理上的一個畫素,根據前面的Nearest Point Sampling可知鋸齒情況發生。而在遠處螢幕上的一個畫素可能覆蓋紋理上的一大片畫素,多個texel 會被一個pixel取樣,且隨著距離越遠,texel數量越多。即一個取樣點內訊號變化過高,導致摩爾紋走樣。
之前講過處理走樣的辦法:先模糊處理,再取樣。如下圖右側,我們經過MSAA的效果。
多重取樣,但是效能有問題
Range Query(範圍查詢)
走樣的產生原因是訊號變化過快,取樣頻率跟不上。我們需要一個更高頻的取樣方法去復原訊號,比如MSAA,但是會有效能損失。如何避免取樣?給定一個紋理區域,我們立刻可以獲得其平均值。這種方式就是範圍查詢
Mipmap
允許快速、近似、方形、的範圍查詢
從一張圖生成一系列低解析度(每次等比縮小一半)的圖。額外儲存量收斂在1/3。
如何確定渲染的Mipmap的層級圖?
我們如何知道某個螢幕畫素應該使用哪個層級的紋理呢。我們找到螢幕畫素鄰近的四個畫素組成的區域,邊長為1個畫素;對映到0級紋理上的近似正方形區域,我們可以求出近似的邊長L。則層級D =
。
Trilinear Interpolation(三線性插值)
在一個場景中,從近道遠,根據L計算得到的mipmap的層級是遞增的整數。層級的遞進導致畫素非線性變化。如下圖,顏色過渡很生硬。
為了模擬整數層之間的效果,比如1。5層,我們需要做線性插值。
我們先找出螢幕上畫素分別在D層和D+1層mipmap的雙線性插值,對這兩個值再做一次線性插值。我們就實現了層級之間的連續過渡,如下圖。
三線性插值也是有缺點的,會導致Overblur,如下圖。
Overblur產生原因見下文。
Anisotropic Filtering (各向異性過濾)
mipmap僅支援方形的範圍查詢;Ripmaps不僅支援方形查詢範圍,還支援長方形範圍查詢,缺點就是生產的圖佔用記憶體為原來3倍。如下圖。
由於透視的原因,螢幕上的一個畫素對映到紋理上很可能是個不規則長方形,如下圖。
如果用mipmap的方式,取樣的區域就是包裹長方形的最小正方形,取樣區域增大,造成Overblur。Ripmaps本身含有長方形貼圖,解決了長方形範圍查詢的情況,但是對於斜的長方形查詢,還是會出現問題。