Games101 筆記 Lecture 7-9 Shading [Graphics pipeline, Texture Mapping]
- Graphics (Real-time Rendering) Pipeline
- Shader Programs
- Texture Mapping
-
- 說明
- 映射關系的得到方法
- Visualization of Texture Voordinates
- Interpolation Across Triangles: Barycentric Coordinates
-
- 重心坐标 Barycentric Coordinates
- 重心坐标的使用
- Texture queries
-
- Simple Texture Mapping: Diffuse Color
- Texture Magnification(紋理太小帶來的問題)
- Bilinear interpolation 雙線性插值
- Bicubic Interpolation雙三次插值
- Texture Magnification (hard case)(紋理太大帶來的問題)
-
- 使用超采樣解決
- 借助範圍查詢解決
- 查詢問題算法介紹
- Mipmap
-
- 怎麼得到近似的正方形區域
- 怎麼查詢
- mipmap的限制
- Anisotropic Filtering(各向異性過濾)
- EWA filtering
- Applications of Textures
-
- Environment Map
- Textures can affect shading
-
- 凹凸貼圖
- 位移貼圖
Graphics (Real-time Rendering) Pipeline
圖形管線 or 實時渲染管線
管線:從一個場景到一張圖,中間經曆的過程稱為管線,表現的是一系列操作。
過程:
從一開始,輸入是一堆空間中的點,并且經過了第一步之後,做一個投影變換,将三維空間中的點投影到平面上,這些點會形成三角形,通過光栅化離散成不同的fragment,畫在離散的螢幕上(在不做MSAA之類的情況下,可以認為一個fragment就是一個像素)。當将三角形打散在螢幕上之後,開始對其進行着色,每個像素都知道是什麼樣的顔色,然後得到整個螢幕的表現。如果用了MSAA,就是好多個不同的fragment會形成一個像素的顔色,需要維護每個fragment對應的深度和顔色,最後再拼成一個圖。
MVP變換,将每一個頂點做一次變換。
光栅化:對螢幕上每個像素點看是否在三角形内。
Z-buffer:當光栅化産生一定數量的fragment or 像素之後,判斷是否可見。
Shading:頂點和像素都會有shading。(取決于着色的方法)
該部分大多都是可程式設計的。(用Shader控制頂點和像素是如何着色的)
紋理映射:三角形内部的像素與紋理的對應關系。
Shader Programs
現代GPU允許自己程式設計去解決頂點和像素如何進行操作的問題。
Shader本質上是可以在硬體上執行的語言。
Program vertex and fragment processing stages
Describe operation on a single vertex(or fragment)
- Shader function executes once per fragment.
- Outputs color of surface at the current fragment’s screen sample position.
- This shader performs a texture lookup to obtain the surface’s material color at this point, then performs a diffuse lighting calculation.
注意:
- Shader是每一個頂點or fragment(pixel)會執行一次,寫完之後是通用的,每一個元素都需要如此運作。裡面不需要寫for循環。
- 如果寫的是頂點的操作,就叫做Vertex Shader(頂點着色器)
- 如果寫的是像素的操作,就叫做Pixel Shader (像素着色器)或Fragment Shader(片段着色器)
Texture Mapping
說明
定義任何一個點的基本屬性。(這個點定義在物體表面上)
- Surface lives in 3D world space. 任何一個三維物體的表面都是二維的。通過這種方式,物體表面和一張圖會存在一一對應關系。
- Every 3D surface point also has a place where it goes in the 2D image (texture)
- 将這張紋理圖檔蒙在物體表面的過程就是紋理映射。映射是一一對應的關系,是以需要找到物體表面的點和紋理之間的映射關系。
映射關系的得到方法
- 需要藝術家的創作,做出一個模型,然後通過一種展開的方式對應。
- 自動化的過程。給定任何一個模型,使用一種辦法展開一個平面,并且還希望産生的三角形盡可能的少扭曲。如果保證紋理上對應顔色無縫銜接就更好了。
Visualization of Texture Voordinates
Each triangle vertex is assigned a texture coordinate (u,v).
uv的範圍通常歸一化到[0,1]内。
三角形每一個頂點都對應一個uv。
紋理可以應用到各種不同的物體表面。
不同的位置可以映射到相同的紋理上,紋理可以重複使用。紋理本身的設計也很重要。
Interpolation Across Triangles: Barycentric Coordinates
三角形的三個頂點有各自不同的屬性,如何将這個屬性在三角形内部做平滑的過度。任意給定三角形内的點,應該得到插值之後的結果。
重心坐标 Barycentric Coordinates
Q1: Why do we want to interpolate:
- Specify values at vertices.為了在三角形内部做插值,而引入重心坐标。
- Obtain smoothly varying values across triangles.
Q2: What do we want to interpolate?
- Texture coordinates, colors, normal vectors,…
重心坐标是定義在一個三角形上的。
首先有一個三角形ABC,重心坐标指的是,在三角形ABC三個點所形成的的平面内任意一點(x,y)都可以表示為三個頂點A,B,C的線性組合。
( x , y ) = α A + β B + γ C α + β + γ = 1 (x,y) = \alpha A + \beta B + \gamma C \\ \alpha + \beta + \gamma = 1 (x,y)=αA+βB+γCα+β+γ=1
和為1是為了限制點在三角形所在的平面内。
如果三個系數均為非負,則該點在三角形内部。
A點的重心坐标:
( α , β , γ ) = ( 1 , 0 , 0 ) ( x , y ) = α A + β B + γ C = A (\alpha , \beta ,\gamma) = (1,0,0) \\ (x,y) = \alpha A + \beta B + \gamma C = A (α,β,γ)=(1,0,0)(x,y)=αA+βB+γC=A
某一點的重心坐标還可以通過面積求出。
α = A A A A + A B + A C β = A B A A + A B + A C γ = A C A A + A B + A C \alpha = \frac {A_A} {A_A+A_B+A_C}\\ \beta = \frac {A_B} {A_A+A_B+A_C}\\ \gamma = \frac {A_C} {A_A+A_B+A_C} α=AA+AB+ACAAβ=AA+AB+ACABγ=AA+AB+ACAC
三角形的重心對應的重心坐标為:
( α , β , γ ) = ( 1 3 , 1 3 , 1 3 ) (\alpha ,\beta ,\gamma) = (\frac{1}{3},\frac{1}{3},\frac{1}{3}) (α,β,γ)=(31,31,31)
重心坐标的一般表達式:
α = − ( x − x B ) ( y C − y B ) + ( y − y B ) ( x C − x B ) − ( x A − x B ) ( y C − y B ) + ( y A − y B ) ( x C − x B ) β = − ( x − x C ) ( y A − y C ) + ( y − y C ) ( x A − x C ) − ( x B − x C ) ( y A − y C ) + ( y B − y C ) ( x A − x C ) γ = 1 − α − β \alpha = \frac{-(x-x_B)(y_C-y_B) + (y-y_B)(x_C-x_B)}{-(x_A-x_B)(y_C-y_B) + (y_A -y_B)(x_C-x_B)}\\ \beta = \frac{-(x-x_C)(y_A-y_C) + (y-y_C)(x_A-x_C)}{-(x_B-x_C)(y_A-y_C) + (y_B -y_C)(x_A-x_C)}\\ \gamma = 1 - \alpha - \beta α=−(xA−xB)(yC−yB)+(yA−yB)(xC−xB)−(x−xB)(yC−yB)+(y−yB)(xC−xB)β=−(xB−xC)(yA−yC)+(yB−yC)(xA−xC)−(x−xC)(yA−yC)+(y−yC)(xA−xC)γ=1−α−β
重心坐标的使用
如果要做插值,同樣應該用重心坐标去将頂點處的屬性值線性組合起來。
V = α V A + β V B + γ V C V = \alpha V_A + \beta V_B + \gamma V_C V=αVA+βVB+γVC
position, texture coordinates, color, normal, depth, material attributes…
在投影變換下,無法保證重心坐标不變。
如果想插值三維屬性,應該取三維空間中的坐标,計算重心坐标後插值。而不能在投影之後的三角形裡面做。
“深度”:先利用逆變換,找到三維坐标,在三維空間中把深度插值好,再轉換過來。
Texture queries
可以不單單指定顔色。
Simple Texture Mapping: Diffuse Color
for each rasterized screen sample (x,y): usually a pixel’s center
(u,v) = evaluate texture coordinate at (x,y); using barycentric coordinates
texcolor = texture.sample(u,v);
set sample’s color to texcolor; usually the diffuse albedo Kd
Texture Magnification(紋理太小帶來的問題)
Generally don’t want this - insufficient texture resolution
A pixel on a texture - a texel (紋理元素、紋素)
紋理太小會出現問題。
螢幕分辨率很高,但是紋理本身太小。
螢幕上一個點對應到紋理上可能不是一個整數,将其round到整數點上,相當于在一定範圍内的像素都在查找紋理上相同的一個點texel上去。
如果希望得到盡可能連續一點的值,則需要通過插值。
Bilinear interpolation 雙線性插值
Linear interpolation (1D) 線性插值:
l e r p ( x , v 0 , v 1 ) = v 0 + x ( v 1 − v 0 ) lerp(x,v_0,v_1) = v_0+x(v_1-v_0) lerp(x,v0,v1)=v0+x(v1−v0)
記:
u 0 = l e r p ( s , u 00 , u 10 ) u 1 = l e r p ( s , u 01 , u 11 ) u_0=lerp(s,u_{00},u_{10})\\ u_1=lerp(s,u_{01},u_{11}) u0=lerp(s,u00,u10)u1=lerp(s,u01,u11)
則雙線性插值::
f ( x , y ) = l e r p ( t , u 0 , u 1 ) f(x,y)=lerp(t,u_0,u_1) f(x,y)=lerp(t,u0,u1)
該點考慮了周圍四個點像素,在四個點圍成的區域内有一個平滑的過度。
Bicubic Interpolation雙三次插值
取周圍的16個值做三次插值。
計算量會比Bilinear大,但是效果更好。
圖形學中,好的品質帶來更大的開銷,得到好的品質之後再去想怎麼降低開銷。
Texture Magnification (hard case)(紋理太大帶來的問題)
出現走樣的問題:遠處會出現摩爾紋Moire,近處會出現鋸齒Jaggies。
螢幕上的一個紋理區域覆寫到的紋理區域大小不同。一般都是利用其中心點坐标對應的紋理值作為改像素的值。但如果覆寫了紋理上很大的一片區域,但還是利用其中心點的值作為該像素的值,這個做法是有問題的,當像素覆寫的紋理區域較大時,就不能這樣采樣了。
使用超采樣解決
使用超采樣的确可以解決這個問題,但是開銷太大了。
走樣:信号變化過快,采樣的頻率跟不上。
當紋理特别大時,一個像素内部就包含着很大一塊紋理。在像素内,信号變化頻率很高,隻用一個采樣點跟不上。
一個像素記憶體在很高頻的信号,希望把這個像素内的信号重構出來,需要一個更高頻的采樣方法。
做法:在一個像素上取好多個紋理的值然後平均起來。
借助範圍查詢解決
另一種思路:采樣會引起走樣,那麼避免采樣。原本像素會在紋理上覆寫很大的區域,如果不采樣,立刻可以知道這個像素的平均值是多少,就可以解決這個問題。
查詢問題算法介紹
-
點查詢問題(Point Query)
給定一個點,然後得其值。(通過雙線性插值或者雙三次插值等方法)
-
範圍查詢問題(Range Query)
不做采樣,給定一個區域,立刻得到其覆寫範圍的平均值。
也有其他種類的範圍查詢,需要得知範圍内的最大值or最小值等。
範圍查詢應該支援查詢任意大小的範圍。
實際上是算法問題。
Mipmap
Allowing fast, approx., square range queries
允許做範圍查詢。
- 快
- 不準确的(中間涉及到近似)
- 僅可以做正方形範圍的查詢
從一張圖生成一系列圖。
每一層都會在上一層的基礎上,将分辨率縮小一半。
在拿到紋理之後,渲染之前,可以提前計算mipmap。
在CV屆将其稱作Image Pyramid(圖像金字塔)。
相比于原始的圖檔,引入了多少額外存儲量?
多引入了三分之一的存儲量。
怎麼得到近似的正方形區域
這裡是近似微分的一種了解方法。
怎麼查詢
已知一個像素,得到其在紋理上面對應的正方形,然後在mipmap上查詢這個L*L區域對應的紋理。
L大小的區域,一定在第D層對應一個像素,可以通過L确定D的值,即應該在第幾層查找。
然後在第D層查找這個像素,就可以得到這個區域對應的紋理。
因為隻計算了離散的第整數層,是以相鄰像素對應的層數可能會有突變,若想得到平滑的結果,需要在整數層間也進行一次插值。
比如想得到第x層的值,則先在x_up=ceil(x)和x_down=floor(x)兩個整數層内部,分别利用雙線性插值得到對應的查詢值,然後将這兩個查詢值再進行一次插值(層間插值)。通過這樣的三線性插值得到任意層數對應的平滑過渡的查詢值。
這樣一來,對于任何查詢的區域,都可以利用三線性插值,做一次查詢,得到這整個區域覆寫的平均值。
三線性插值在圖形學中應用十分廣泛,因為它可以得到一個完全平滑的變化,在層與層之間和層内都是連續的。
mipmap的限制
效果上會将遠處的結果所有細節全都模糊掉。(Overblur)
不對的地方:隻能查詢正方形區域内,是近似的不是準确的。
解決方法↓
Anisotropic Filtering(各向異性過濾)
效果比三線性插值好
在mipmap的基礎上,針對不同的長寬比也進行了一系列的計算。
開銷是原來的三倍。
生成的是RipMap
螢幕上的像素,映射到紋理上, 很有可能出現的并不是規矩的正方形,很有可能是比較長的長方形,這樣mipmap的表現就不是很好,而各向異性過濾可以有效解決這個問題,打破正方形的限制。
但是有些像素映射到紋理上是斜着的長方形,上面兩種算法都不能得到比較好的結果,是以有↓
EWA filtering
用很多圓形去覆寫不規則的形狀
多次查詢,找到可以覆寫的圓形。性能消耗略大
Applications of Textures
in morden GPUs, texture = memory + range query(filtering)
可以用紋理表示很多東西
Environment Map
可以用紋理去描述環境光的樣子,也可以用環境光去渲染其他物體,比點光源好很多。
應用環境光時,會有一個假設:
認為環境光都是來自無限遠處,隻需要記錄方向資訊,沒有實際的深度意義。
不管觀測點在哪兒,認為環境光光源比較遠,則在活動範圍内,認為從同一個方向來的光都是一樣的。
Spherical Environment Map
如果可以将環境光描述在某個紋理上,則可以使用它來渲染一些東西。
在一個屋子裡面放上一個金屬球或者鏡子球,它反射出來的東西就是環境光。
這也給了一種環境光的存儲方法:Spherical Environment Map
就把環境光存儲在球面上,然後按照一定的方式給展開。
這種存儲方法存在扭曲問題。做到了描述,但是不是均勻的描述。
Cube Map
假設用一個球的表面來記錄來自某方向的光線,認為有一個包圍盒将該球包住,從球心往原來記錄光線資訊的球表面連一條線,直至打到立方體的表面上,這樣将光線資訊存放在立方體的表面上。
立方體的表面是均勻的,很少出現扭曲的現象。
但是如果給定一個方向,原本隻需要很簡單從球上拿到,現在需要先判斷存放在哪個面上,再求出在該面上的具體位置。
Textures can affect shading
凹凸貼圖
紋理不止可以描述顔色,也可以做其他的事情:定義任何不同位置的任何不同屬性。
可以定義在一個表面上任意一個點的相對高度。(定義在某個點處,在基礎高度的基礎上,沿着法線方向往上或者往下平移多少)
凹凸貼圖:
在不把幾何形體變複雜的情況下,通過應用一個複雜的紋理進而定義任何一個點的相對高度,相對高度一變,法線就會發生變化,shading的結果就會發生變化。人們看到不同的明暗對比,一定程度上是因為法線發生變化産生了着色上的明暗對比,人們會認為這裡存在凹凸的東西。
使用凹凸貼圖或者法線貼圖的辦法其實是在試圖人為的加一個假的法線出來,在任何一個點都可以通過紋理映射求出假的法線,通過這個假的法線可以給一個假的着色結果,進而欺騙人的眼睛,讓人覺得有凹凸的效果,但實際并沒有改變其幾何狀态。
首先,通過法線貼圖,可以定義一個複雜的紋理,但是并不改變其幾何資訊。
将任何一個像素的法線都進行一個擾動。通過定義不同位置的高度,臨近位置的高度差,求出切線,然後來重新計算其法線。
紋理定義的是任何一個點其相對位置高度的移動。通過高度的變化來改變法線。
通過凹凸貼圖定義切線,再由切線得到法線。
對于三維,可以求偏導數。
位移貼圖
displacement mapping
凹凸貼圖穿幫點:在邊緣處沒有突出的幾何;自己在自己身上不會有産生陰影的地方。
會将三角形頂點真實地進行移動。着實地改變了幾何頂點的位置。
要求三角形需要足夠細,避免出現三角形内還需要移動某個點的情況出現。模型要跟得上所定義的紋理變化速度,要求三角形足夠細,細到頂點之間的間隔比紋理定義的頻率要高。(采樣的情況:希望模型可以完整地反應紋理的高度變化,模型的采樣率需要足夠高。)
可以開始先用一個稍簡單的模型,在應用位移貼圖的時候考慮是否需要更複雜的幾何,如果需要更複雜,則可以将目前的三角形拆分開,做細分。