GAMES101-現代計算機圖形學學習筆記(09)

GAMES101-現代計算機圖形學學習筆記(09)


原課程視頻鏈接以及官網
b站視頻鏈接: link.
課程官網鏈接: link.

着色(shading)

重心座標

上一篇文章說到紋理映射,實質上紋理映射就是把uv座標下的紋素映射到圖像像素的過程。而我們在畫三角形的過程中通常只是定義了三個頂點的屬性,其內部屬性往往需要通過三個頂點插值得來,像法向量,顏色值,深度值,還有紋理座標等。所以我們需要一個插值的方式來解決這個問題,常用的有利用重心座標進行插值

那麼重心座標是什麼?簡單來說就是找到三角形ABCABC內部的一個點P(x,y)P(x,y),有 (x,y)=αA+βB+γC(x, y)=\alpha A+\beta B+\gamma C , 且 α+β+γ=1\alpha +\beta +\gamma = 1,那麼 (α,β,γ)(\alpha ,\beta ,\gamma) 就是點 PP的重心座標,如下圖:
在這裏插入圖片描述
它有什麼用處?看到座標A,B,C 其實可以想到,如果把A,B,C換成 法向量(nx,ny,nz),紋理座標(ux,uy)都是成立的

如何求解?把 α\alpha 看做 Wv1W_{v 1}β\beta 看做 Wv2W_{v 2}γ\gamma 看做 Wv3W_{v 3} ,可得如下方程:
Px=Wv1Xv1+Wv2Xv2+Wv3Xv3P_{x}=W_{v 1} X_{v 1}+W_{v 2} X_{v 2}+W_{v 3} X_{v 3}

Py=Wv1Yv1+Wv2Yv2+Wv3Yv3P_{y}=W_{v 1} Y_{v 1}+W_{v 2} Y_{v 2}+W_{v 3} Y_{v 3}

Wv1+Wv2+Wv3=1W_{v 1}+W_{v 2}+W_{v 3}=1將它們移項即可得到解:
Wv1=(Yv2Yv3)(PxXv3)+(Xv3Xv2)(PyYv3)(Yv2Yv3)(Xv1Xv3)+(Xv3Xv2)(Yv1Yv3)W_{v 1}=\frac{\left(Y_{v 2}-Y_{v 3}\right)\left(P_{x}-X_{v 3}\right)+\left(X_{v 3}-X_{v 2}\right)\left(P_{y}-Y_{v 3}\right)}{\left(Y_{v 2}-Y_{v 3}\right)\left(X_{v 1}-X_{v 3}\right)+\left(X_{v 3}-X_{v 2}\right)\left(Y_{v 1}-Y_{v 3}\right)}

Wv2=(Yv3Yv1)(PxXv3)+(Xv1Xv3)(PyYv3)(Yv2Yv3)(Xv1Xv3)+(Xv3Xv2)(Yv1Yv3)W_{v 2}=\frac{\left(Y_{v 3}-Y_{v 1}\right)\left(P_{x}-X_{v 3}\right)+\left(X_{v 1}-X_{v 3}\right)\left(P_{y}-Y_{v 3}\right)}{\left(Y_{v 2}-Y_{v 3}\right)\left(X_{v 1}-X_{v 3}\right)+\left(X_{v 3}-X_{v 2}\right)\left(Y_{v 1}-Y_{v 3}\right)}

Wv3=1Wv1Wv2W_{v 3}=1-W_{v 1}-W_{v 2}

紋理映射過程

簡單的紋理映射的過程:在光柵化過程中,對當前掃描到的點的uv座標進行採樣,得到的顏色直接賦給物體

for each rasterized screen sample (x,y):    
	(u,v) = evaluate texture coordinate at (x,y)    
	texcolor = texture.sample(u,v);    
	set sample’s color to texcolor

紋理分辨率過小

但是這樣會帶來一些問題,就是當紋理分辨率過小,而需要用來覆蓋的物體過大時,多個像素座標(x,y)都會採樣到同一個紋素,產生一些鋸齒的效果,這時我們就有一些解決方法,如:最近鄰插值,雙線性插值,雙三次插值,如下圖:
在這裏插入圖片描述

最近鄰插值

假設紅點是像素座標點對應的紋理像素座標,那麼最近鄰插值就是把離它最近的紋素分配給當前像素點:
在這裏插入圖片描述
上圖的結果就是紅點的紋素應該是它右上角黑點紋素對應的值

雙線性插值

雙線性插值就是找它周圍四個點對應的紋素進行插值,如下圖:
在這裏插入圖片描述
那麼如何進行插值?
在這裏插入圖片描述
先考慮一維上的線性插值,假設有一個起始點V0和終止點V1,那麼V(x)在這兩點間的插值就是:lerp(x,v0,v1)=v0+x(v1v0)\operatorname{lerp}\left(x, v_{0}, v_{1}\right)=v_{0}+x\left(v_{1}-v_{0}\right)

雙線性插值就是在橫座標(豎)上先做兩次插值,再在豎座標(橫)上做一次插值即可:
在這裏插入圖片描述

雙三次插值

這裏的雙三次不同於三維空間中的三線性插值,應該叫做雙三次插值(Bicubic),它是對二維空間的插值,考慮了鄰近十六個採樣點的插值,具體方法同雙線性插值

紋理分辨率過大

同樣,當紋理分辨率過大時,如果以某種角度或者由於物體過遠,對紋理進行相同的採樣率得到的結果卻會遠遠不同(往往會很差)。通俗來說就是如果我們由近到遠看一個物體,同時它的紋理分辨率十分高。當它離我們比較近時,它在我們人眼中的佔比非常大,我們需要對紋理有很高的採樣率才能把它的很多細節看得清楚。但是當它離我們很遠時,假如在肉眼中只有非常小的比例,我們就不需要看到它的很多細節,但是這時我們還是用之前的採樣率去對它紋理進行採樣,得到的結果就會“亂掉”(摩爾紋),可以看下圖:
在這裏插入圖片描述
實際上一個像素,所覆蓋的紋理區域也是不同的,所以當發生這種變化或者一個像素覆蓋紋理區域過大時,我們也不應該用同樣的採樣率對紋理進行採樣,因爲它:
在這裏插入圖片描述
那麼如何解決這種問題?答案是mipmap,但是在看mipmap之前需要先了解一下點查詢和範圍查詢

點查詢和範圍查詢

點查詢:已知一個點,快速查出其結果是多少。對應紋理上來說就是給定像素點,查得最近鄰,雙線性,雙三次插值的結果
範圍查詢:不知道哪個點,但是給定了你一個區域,可以直接得到對應的值(平均值之類的),而mipmap就是基於範圍查詢的

Mipmap

它是一種快速,近似,僅限於正方形範圍的範圍查詢

Mipmap就是通過一張紋理,生成許多高層(分辨率每次縮小到一半)的紋理,如下圖:
在這裏插入圖片描述
它的開銷也是十分小的,因爲每次只存儲了上一幅圖像的1/4,對於額外開銷 SS ,可以通過錯位相減得到 3S=114n3 S=1-\frac{1}{4^{n}}
S=14+116+164++14nS=\frac{1}{4}+\frac{1}{16}+\frac{1}{64}+\cdots+\frac{1}{4^{n}}

4S=1+14+116++14n14 S=1+\frac{1}{4}+\frac{1}{16}+\cdots+\frac{1}{4^{n-1}}

4SS=3S=114n4 S-S=3 S=1-\frac{1}{4^{n}}
又因爲 114n1-\frac{1}{4^{n}} 取極限爲1,所以 S=1/3S=1/3,所以總開銷爲 4/3.

假設我們定義Mipmap的層級爲D,那麼如何確定某個像素P對應的Mipmap層級呢?
首先找到該點和相鄰像素點在紋理上的映射點,計算邊長L,所以層級可以由 D=log2LD = log_{2}L 算出(因爲隨着層數增加,紋理分辨率是以4倍的速度減小,所以L是以2倍的速度增加的)
在這裏插入圖片描述
當我們得到了層級後,在這一層上進行紋理插值即可。但是我們發現,層級之間是離散的,也就是說,一些像素在0層插值,一些像素在1層插值,這種變化也會使得紋理“割裂”:
在這裏插入圖片描述
解決方法就是,每次插值,現在D層插值紋理(可以用雙線性之類的方法),再在D+1層插值紋理,把兩層結果再進行插值(把log的結果去和前一層和後一層進行插值比較),這樣的結果就是平滑的了:
在這裏插入圖片描述
但是Mipmap也會有缺點,因爲它的範圍只是限定在正方形範圍內的,所以會產生over-blur的問題:
在這裏插入圖片描述

各向異性濾波

各向異性濾波能夠部分解決這種問題,因爲它的範圍不是限定在正方形範圍內的,而是矩形範圍。如果說下圖中Mipmap的圖片縮小是沿着對角線進行的,而各向異性濾波的壓縮就是沿着水平和豎直線進行的:
在這裏插入圖片描述
所以它是使得原圖的像素可以查詢紋理中一些矩形區域,這樣就能部分解決一些形變壓縮的紋理查詢問題:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章