文章目錄
- 一.Shading Model(Blinn-Phong Reflectance Model)
- 1.相關定義(Shading is Local)
- 2.Diffuse Reflection(Blinn-Phong)
- 3.Specular Term(Blinn-Phong)
- (1)高光條件
- (2)半程向量
- (3)高光表示
- (4)Q1:爲什麼Blinn-Phong中的高光項表示中沒有Shading Point接收到的能量?
- (5)Q2:爲什麼採用的是半程向量和法線的夾角而不是觀測方向和反射方向的夾角?
- (6)Q3:式子中指數怎麼來的?
- 4.Ambitent Term(Blinn-Phong))
- 5.模型總結
- 二.Shading Frequencies
- 1.Flat shading(Shade each triangle)
- 2.Grouraud shading(Shade each vertex)
- 3.Phong shading(Shade each pixel)
- 4.逐頂點法線計算
- 5.逐像素法線計算
- 三.Graphics(Real-time Rendering)Pipeline
- 四.Text Mapping(紋理映射)
- 五.Interpolation Across Triangles:Barycentric Coordinates(重⼼座標)
- 六.紋理應用
一.Shading Model(Blinn-Phong Reflectance Model)
Games101 lecture7-8-9-10
Shading(着色)定義爲對不同對象應用不同材質的過程。不同的材質也就是不同的着色方法。有許多着色模型,例如Blinn-Phong Reflectance Model(經驗模型)。如下圖着色模型:
從上面來看,分爲三部分,高光(Specular highlights),漫反射(Diffuse reflection),環境光照(Ambient lighting)。
1.相關定義(Shading is Local)
對於着色,現階段光照是正對某一點的,該點稱爲Shading Point(着色點),雖然點可以位於任何一個曲面上,但在一個足夠小的局部範圍下,總是認爲該點處於一個平面上(如上圖)。從而可以定義該平面法線(Surface normal),觀測方向(Shading Point看向觀測點方向),以及光照方向(Light direciton,光源位置減去點的位置然後歸一化即可)。以上向量表示方向,故爲單位向量。除此之外還有着色點的顏色等參數。
同時着色具有局部性(Local),即考慮着色時只考慮Shading Point本身,但是不考慮其他物體的存在(比如該點是否在陰影內,被遮擋情況)。
2.Diffuse Reflection(Blinn-Phong)
所謂漫反射,也就是光線在反射的時候時往在各個方向上均勻散射的。
(1)Shading Point接收的能量強度
當Shading Point表面法線和光線有一定夾角的時候,夾角越小,亮度越大,如下圖所示。因爲角度不同時Shading Point周圍的單位面積(固定)所接受到的能量情況是不同的,即有。
(2)到達Shading Point的能量強度
這裏的光源假設認爲是點光源(三維空間),它會往四周輻射光線,能量會逐步衰減(每個圈是球殼)。如下圖所示:
假設距離點光源距離爲1(單位距離)的時候,其光強度爲,現在如果要算出距離點光源距離爲處某點的強度,因爲能量守恆,則有如下式子(強度x球殼面積),則。
(3)漫反射表示 & Shading Point的顏色
至此,如果知道一個Shading Point距離點光源的距離,即可知道有多少強度的光傳播到該點附近的單位面積上以及單位面積上接收到的能量情況,就能表示漫反射了,式子如下圖:
式子如下:
由於漫反射是均勻輻射的,所以對於Shading Point而言,其結果與觀測點無關。
假設有一個點光源,Shading Point和光源距離爲,光源單位距離強度爲,則到該點的能量強度爲;該點單位面積接收的能量爲(單位向量點乘等於其夾角餘弦),但是餘弦可能爲負數(也就是光線從點的下方射入,無物理意義),所以取值爲)。
如果其材質有顏色,則考慮爲漫反射係數,如果其值爲1,則表示該點完全不吸收能量(完全反射),即爲最亮;如果其值爲0,則吸收所有能量,即爲最暗(例子如下圖)。如果將係數表示一個三通道的RGB值,每個通道取值爲,那麼就可以在Shading Point上定義某一種顏色。
3.Specular Term(Blinn-Phong)
由觀察可得,當觀測方向和鏡面反射方向足夠接近的時候,就能看到高光,如下圖。
(1)高光條件
Blinn-Phong模型基於此,認爲和接近也就相當於法線方向和半程向量(bisector)接近。兩者夾角爲,用其餘弦(兩者點乘)衡量是否接近,取值爲(0,1),越接近則值趨於1,否則趨於0。如下圖。
(2)半程向量
這裏的半程向量也就是光照方向和觀測方向的角平分線方向,這裏只要用平行四邊形法則然後歸一化(長度變爲1)處理即爲所求,式子如下:
(3)高光表示
則高光表示如下,其中爲鏡面反射係數,係數越大,亮度越大。同時因爲高光通常是白色,所以表示顏色通常也爲白色。
(4)Q1:爲什麼Blinn-Phong中的高光項表示中沒有Shading Point接收到的能量?
同上面的漫反射比較,會發現這裏省略了Shading Point接收到的能量(實際任何反射都應該考慮),但是因爲Blinn-Phong模型是經驗模型,更加關注是否能看到高光,即和是否接近。
(5)Q2:爲什麼採用的是半程向量和法線的夾角而不是觀測方向和反射方向的夾角?
如果採用的觀測方向和鏡面反射方向的夾角的話,其模型稱爲Phong Reflectance Model,而Blinn-Phong Reflectance Model是對其的改進,因爲半程向量容易計算且反射方向不易計算。
(6)Q3:式子中指數怎麼來的?
雖然向量之間夾角餘弦可以表示兩者是否接近,但是其容忍度較高,也就是其能看到高光的區間(餘弦正值區域)較大,而實際高光是兩者方向十分接近的時候纔會出現高光,否則是沒有高光,所以需要縮小高光區間。下圖可以看出增加時,能看到高光的區間逐漸縮小。在Blinn-Phong模型中,的值約爲100~200。
在實際例子中,當增加時,高光會越來越小,如下圖:
4.Ambitent Term(Blinn-Phong))
此時暫時假設任何一點接收到環境光的強度相同,如下圖:
(1)環境光表示
式子如下,其中爲接收到的環境光強度,同理爲環境光係數,也可以在點上定義一種顏色。
同時環境光不依賴觀測方向、光照方向和法線方向,因爲各個方向上強度相同,所以環境光是一個常數,而這就保證物體任何地方至少有一個常數顏色(物體本身不存在一個地方是完全黑的)。
但是實際的環境光計算,需要用到全局光照,此時用的常數環境光只是便於理解。
5.模型總結
環境光是個常數;漫反射與觀測方向無關,與法線方向和關照方向有關;高光將三項相加,結果如下圖:
其式子如下:
二.Shading Frequencies
有了模型之後,就是對Shading Point進行着色,這裏涉及到着色頻率的概念。
着色頻率(Shading Frequencies)是指要對哪些點進行着色,例子如下圖:
三個球採用同樣的模型,但是着色頻率不同結果。
1.Flat shading(Shade each triangle)
如第一個球體而言,對每一個面進行着色,對每個三角形面求出其法線(任意兩邊做叉積),然後根據公式求出結果,即爲整個三角形面的顏色。
2.Grouraud shading(Shade each vertex)
如第二個球體而言,對每個三角形頂點着色,求出其法線,三角形內容顏色通過插值算出。
3.Phong shading(Shade each pixel)
如第三個球體而言,對每個像素進行着色,求出其法線。注意區別Phong shading是個着色頻率,Blinn-Phong是個着色模型。
三種模型結果需要看物體模型的複雜度,頂點數目等,如果物體足夠複雜(面足夠多,足夠小),Flat shading的效果也會很好,如下圖:
4.逐頂點法線計算
如上圖所示,對於一個頂點,會被個三角形所共用,則其法線等於與之相鄰的三角形面的法線的平均或者加權平均(權重爲三角形的面積),法線最後都需要歸一化(化爲單位向量),式子如下:
5.逐像素法線計算
如上圖,當已知頂點(上圖左右兩個黑點)的法線之後,中間的法線插值得出,法線最後都需要歸一化(化爲單位向量)。
三.Graphics(Real-time Rendering)Pipeline
1.簡介
渲染管線(Graphics Pipeline)或實時渲染管線(Real-time Rendering Pipeline),指的是從某個場景到最後輸出圖像的整個過程,GPU從硬件上實現了圖形管線,如下所示:
首先輸入的空間中的頂點,經過Vertex Processing(包含MVP變換,着色等)之後,將點投影到屏幕空間上;接着Triangle Processing,這些點會在屏幕空間上形成三角形;之後經過Rasterization光柵化(包含採樣過程)將三角形離散成爲Fragment(片元,類比像素,如果使用MSAA,即爲sample);然後在Fragment Processing階段(包含Z-Buffer測試,着色等),對Fragment着色,此階段也可以包含在上一步光柵化階段裏;最後在Framebuffer Operations階段輸出圖像。
需要注意的是上面所說的Shading發生在第一步和第四步裏面,這是因爲對於不同的着色頻率發生階段不同。如果是Grouraud shading對頂點着色就可以在Vertex Processing階段處理,但是如果是Phong shading對像素着色,就需要等待像素產生,即Fragment Processing階段處理。
2.Shader
圖像管線中存在可編程的部分,所以可以人爲控制頂點和像色着色部分,而決定頂點和像素如何處理運作的代碼即爲Shader。Shader會對每個頂點或者像素執行一次(通用執行,即shader只處理一個頂點或者像素 )。如果shader是處理頂點,即爲vertex shader(頂點着色器);處理像素(或者fragment),則爲fragment shader(片段着色器)或者pixel shader(像素着色器)。
比如使用OpenGL的着色語言GLSL寫的fragment shader例子如下:
uniform sampler2D myTexture; // 全局變量,表示紋理
uniform vec3 lightDir; // 全局變量,表示光照方向(認爲每個像素都有一個固定的光照方向)
varying vec2 uv; // per fragment value (interp. by rasterizer)
varying vec3 norm; //法線(插值)per fragment value (interp. by rasterizer)
void diffuseShader()
{
vec3 kd;//漫反射係數
kd = texture2d(myTexture, uv); //(紋理替代kd)material color from texture
kd *= clamp(dot(–lightDir, norm), 0.0, 1.0); // 漫反射部分,Lambertian shading model(OpenGL認爲關照方向射向點,所以需要有個負號)
gl_FragColor = vec4(kd, 1.0); // output fragment color,gl_FragColor是個固定值,表示fragment的顏色
}
四.Text Mapping(紋理映射)
紋理映射的根本作用是定義任何一點的基本屬性,在Blinn-Phong Reflectance Mode中我們使用紋理來替代漫反射係數。
前提,任何物體表面都是二維的,也就是說紋理是一張應用於物體表面可變化的圖,從而物體表面和紋理上的點就有一一對應關係,如下圖:
前提已知空間中的三角形到紋理的映射關係(美工解決),我們所作的工作是將紋理應用到物體表面。
1.紋理座標系
這需要在紋理上定義一個座標系,通常默認規定取值爲(與紋理圖片大小無關),如下圖:
2.紋理複用(Tileable Texture)
同時紋理可以應用在不同的物體表面,並且可以進行復用,如下圖(左邊是渲染圖,右邊是圖)。會發現雖然紋理複用在座標上是有邊界的,但是在物理表面是沒有邊界的,這種紋理被稱爲Tileable Texture。
五.Interpolation Across Triangles:Barycentric Coordinates(重⼼座標)
1.插值定義
前面在講着色頻率以及紋理時提到了插值,三角形的頂點有各自不同的屬性,插值的目的就是讓該屬性在三角形內進行平滑的過渡。屬性包括紋理映射,頂點顏色,Phong shading中的頂點法線等等。插值通過重心座標完成。
2.重心座標
重心座標是針對三角形的,不同的三角形有着不同的重心座標系統。它可以用三角形三個頂點的線性組合來表示三角形平面內任何一點,只要三者的係數和爲1且爲非負數即可,式子如下,從中可以很容易看出三個頂點的重心座標爲,,,。
(1)三角形內任意點重心座標
而對於三角形內任意一點的重心座標,可以通過面積比算出來,如下圖中三角形內部黑點。
先將其與三個頂點連接,可以得到三個內部三角形,若表示A點所對的三角形面積,同理知道和,則其重心座標如下:
如果只知道三頂點的座標,,,則可以用上面的公式退出下面的一般表達式:
(2)三角形重心的重心座標
而對於三角形的重心而言,三角形的重心是三角形三條中線的交點,重心是三點座標的平均值,並且重心和三角形3個頂點組成的3個三角形面積相等,可以得到其重心座標如下:
(3)使用重心座標進行插值
使用重心座標對三角形內的點進行插值,對於需要插值的屬性也用重心座標進行線性組合,如下圖所示,三個頂點的屬性爲,,,這些屬性可以是位置,紋理座標,顏色,法線,深度,材質屬性等等。則對於三角形內一點,其重心座標爲,則其屬性即爲。
需要注意的是重心在投影下不能保證不變的。也就是說如果想要對三維空間的某種屬性進行插值的話,就應該在三維空間下計算重心座標系統,不能在投影之後的三角形上計算。比如光柵化階段三角形已經被投影到屏幕空間上時,此時如果要對深度進行插值,不能直接在該三角形內計算,而是應該在三維空間下的三角形先計算好重心座標,插值完成後再投影到屏幕空間上。
六.紋理應用
至此,可以進行簡單的紋理應用,其應用過程如下:
for each rasterized screen sample (x,y): //(x,y)通常爲像素中心
(u,v) = evaluate texture coordinate at (x,y)//將點的u,v座標通過重心座標進行插值得到
texcolor = texture.sample(u,v);//得到u,v座標對應的紋理顏色
set sample’s color to texcolor;//用texcolor代替原本顏色(通常是kd)
1.Texture Magnification(紋理過小情況)
但是通過上述的過程進行應用之後,會造成Texture Magnification問題,也就是紋理的分辨率過低時被應用到高分辨率物體上(查詢紋理座標時會得到非整數的值)。解決方式如下:
(1)Nearest
可以是讓一定範圍內(u,v)座標查找距離最近的(比如四捨五入爲整數值)的紋理元素(紋素,紋理上的像素,texel),如下圖中Nearest所示,會造成塊狀。
(2).Bilinear interpolation(雙線性插值)
但是其效果不好,更好的方式是雙線性插值法(Bilinear interpolation),具體做法如下:
對於一個texel,,如上圖紅點所示,此時我們想要知道的是紋理在紅點處的值。其中黑點表示紋理座標。首先找到與之相鄰的四個點,,,,再找到紅點和左下角的水平距離以及豎直距離,此時以兩個像素之間爲單位1的話,可以認爲。如下圖所示。
接下來需要定義線性插值(Linear interpolation)操作,其中和分別表示定義在位置0和1上的值,表示需要線性插值屬性,即有
這樣就可以使用對兩條水平的邊進行插值,即有
接下來在豎直方向上用對和進行插值,即可得到紅點處的值,即有
以上即爲雙線性插值方法,即水平和豎直方向上都做插值(順序不限)。其效果如下圖:
2.Texture Magnification(紋理過大情況)
當紋理過大時,比如下圖中紋理是格子,此時會出現嚴重的走樣問題。
這是因爲屏幕上遠處和近處的像素覆蓋的紋理範圍是各不相同的,如下圖。當覆蓋區域過大但仍舊採用像素重心進行應用時就會走樣。
之前說過走樣產生的本質原因是信號(函數)變換過快(高頻率),但是採樣速度跟不上。在紋理過大時問題上體現爲在一個像素內部可能包含很大的紋理(高頻),紋理會發生變化,但是隻用一個像素對其進行採樣,就會發生走樣現象。考慮之前使用MSAA/超採樣來反走樣,這裏同樣可以使用,但是開銷過大。
所以考慮避免採樣,這就需要知道如何得到一個區域(像素覆蓋區域)內的平均值。圖形學中使用Mipmap/image pyramid來完成該操作。
(1)Mipmap定義
Mipmap的特點是隻能用於方形區域,屬於近似查詢,查詢速度快。
Mipmap就是用一張圖生成更多層的圖,然後去查詢像素所在層數,再進行計算,具體操作如下圖:
其中原始紋理稱爲第0層(Level 0)紋理,可以通過Mipmap生成更高層紋理,使得第層的分辨率都是第層縮小到一半。在這裏假設原始紋理的存儲爲1,則一共使用了存儲量,即使用了額外的存儲量,如下式子:
(2)使用Mipmap計算Level D
首先如下圖(左邊時屏幕空間,右邊是紋理座標),假設此時需要得到四個紅點中的左下角紅點所代表像素的覆蓋面積,可以將與之相鄰的像素中心同樣投影到紋理座標上,如上邊右圖所示。這樣就可以算出紋理座標上該點與相鄰點的距離,簡單起見從中取一個最大值作爲區域的邊長,從而近似得到該像素在紋理上覆蓋區域的正方形大小,如下圖所示。
計算公式如下,其中爲Mipmap的紋理層數。
得到了近似區域的大小,即可知道區域對應的層數,比如區域爲4x4大小,則其必定在第二層上,則在第二層上會變成一個像素。
(3)Trilinear interpolation(三線性插值)
但是將需要查詢的Mipmap層數進行可視化如下圖,會發現此時層層之間的查詢不連續,因爲此時層數都是整數值,所以需要使用插值來進行平滑的過度。
考慮在層與層之間進行插值,首先在第層和第層上分別做雙線性插值得到對應結果,再利用這兩個值在層與層之間進行插值(非水平非豎直方向,層與層),此爲Trilinear interpolation(三線性插值)。
其結果圖如下,層與層之間有很好的過度:
(4)Anisotropic Filter(各向異性過濾)
現在回到最開始的網格圖,應用Mipmap結果如下圖,遠處出現了嚴重的Overblur(過度模糊)現象。
這是因爲屏幕空間上的像素對應到紋理上覆蓋的區域不一定都是正方形,如下圖所示。採用Mipmap,這些長條狀的區域都會使用一個正方形區域近似,就會求得一個更大區域的平均值,從而過度模糊。
而Anisotropic Filter(各向異性過濾)可以部分解決這個問題,它和Mipmap相比,它計算了不同長寬比的紋理層數,如下圖所示,Mipmap計算的是對角線上,而Anisotropic Filter還計算了周圍的對象,這就可以解決矩形狀區域的快速查詢,但是總共的存儲量是原本的3倍(收斂極限)。
3.其他的紋理應用
(1)Environment Map/Lighting
使用紋理記錄環境光,然後再進行渲染。還可以將環境光記錄在球面上(Spherical Environment Map),如下圖。
但是這樣將其展開的時候就會發現有扭曲現象,如下圖:
改進方式是Cube Map,也就是給球面一個包圍盒,如下圖,則原來存儲在球面上的關照信息衍生到包圍盒上,這樣就會得到一個六張圖片組合的環境光,如下圖。
(2)凹凸/法線貼圖(Bump Mapping)
紋理除了可以定義顏色之外,還可以定義其他不同的屬性,比如定義在一個表面上任意一點的相對於基礎表面上沿着法線方向的相對高度,從而避免使用大量的三角形來定義部分複雜(凹凸不平)的幾何形體,如下圖:
通過凹凸貼圖這樣就可以在不改變幾何形體的情況下來改變着色結果,將像素的法線進行(Perturb)擾動(僅僅爲了着色計算而使用),也就是相對於平面的高度變化,相當於改變了法線(實際沒有改變物體原本的法線),比如下圖中點通過凹凸貼圖會被認爲移動到了上面的點。
<1>接着考慮凹凸貼圖上的法線如何變化?(先在貼圖上定義切線,通過切線得到對應法線)
簡單起見先考慮一維貼圖/Flatland上的變換情況,如下圖情況,原本平面是平的,藍色線是由凹凸貼圖定義得到的,原本的表面法線在點是,這裏是一個臨時的座標系,然後用差分方式(用相鄰兩點的高度差進行計算)近似求出貼圖上點的切線(也就是該點的導數),如下式子,其中爲凹凸貼出的影響因子。
導數相當於水平方向上移動一個單位距離,豎直方向上移動,則此處的切線用向量表示爲,則擾動後的法線應該和切線垂直,即將其逆時針旋轉,得到對應法線爲,最後需要歸一化。
將上述結果推廣到實際情況,對於二維貼圖,假設原本法線爲,再求出座標上的對應的導數,如下:
類比flatland情況,推導略,則得到法線如下:
(3)位移貼圖(Displacement mapping)
於凹凸貼圖相比較,位移貼圖實際上通過頂點的移動改變了物體的幾何形狀,這對模型三角形要求精細,兩者結果比較如下圖: