圖形學3D渲染管線學習

小紫蘇發表於2021-12-09

圖形學3D渲染管線

DX和OpenGL左右手座標系不同,會有一些差距,得出的矩陣會不一樣;

OpenGL的投影平面不是視景體的近截面;

頂點(vertexs)

頂點座標,顏色,法線,紋理座標(UV),連線索引;

圖元(primitives)

幾何頂點被組合為圖元(點,線段或多邊形),圖元裝配;

片元(fragments)

圖元被分幾步轉換為片元:圖元被適當的裁剪,顏色和紋理資料也相應作出必要的調整,相關的座標被轉換為視窗座標。最後,光柵化將裁剪好的圖元轉換為片元;

一、頂點資料(Vertex)

頂點座標,顏色,法線,紋理座標(UV),連線索引(三角形連線順序-左右手座標系順序 不同);

頂點資料在流水管線中以圖元處理:

點(GL_POINTS)、線(GL_LINES)、線條(GL_LINE_STRIP)、三角面(GL_TRIANGLES);

四邊形頂點資訊:頂點位置、顏色、UV、四個頂點順序;

索引可以避免共享頂點間資料的多餘——頂點快取物件(Vertex Buffer Object,VBO)

二、頂點著色器(Vertex Shader)

1.矩陣變換

通過矩陣變換將世界座標系下的頂點變換到視口座標系下顯示;

齊次變換:將一個原本是n維的向量用一個n+1維向量來表示(是不是很像投影);

互為逆矩陣:相乘結果為1;

轉置矩陣:行列互換;

正交矩陣:行列向量互相垂直,正交矩陣的逆矩陣就是他的轉置矩陣;

1)模型矩陣到世界矩陣

Local Coordinate——World Coordinate;

頂點在世界座標系下可以進行平移(Translation),旋轉(Rotation),縮放(Scaling)操作;

按順序矩陣連乘得到世界矩陣下頂點的座標;

如果進行縮放操作要考慮法線變換(非均勻縮放-逆矩陣的轉置矩陣獲得變換法線-切線空間);

OpenGL Normal Vector Transformation

2)世界矩陣到攝像機矩陣

World Coordinate——View Coordinate;

攝像機矩陣也叫觀察矩陣;

攝像機的一些引數:

EyePosition:攝像機位置

FocusPosition:觀察目標點(at)

UpDirection:攝像機上方向(不是Y,相對世界)

Near:近截面、Far:遠截面

FOV(vertical field of view):垂直視場角

Aspect Ratio :螢幕縱橫比

以上引數定義了視景體(臺體);

頂點座標轉換到攝像機矩陣逆向思維,理解為將當前頂點平移攝像機當前位置向量的反向量;

image-20211208234540797

攝像機*攝像機變換矩陣肯定會得到一個單位矩陣(座標系都是單位矩陣);

攝像機當前的x,y,z軸組成的矩陣和攝像機變換矩陣互為逆矩陣;

image-20211209000201960

通過攝像機引數求得攝像機的xyz軸向量;

image-20211208234204150

由於正交矩陣的逆矩陣就是他的轉置矩陣,再新增單位1;

image-20211209000609321

將攝像機變換矩陣和平移矩陣相乘得到攝像機矩陣;

image-20211209000720748

以上為左手座標系下的攝像機矩陣;

3)攝像機矩陣到投影矩陣

View Coordinate——Projection Coordinate;

正交投影和透視投影;

在Dx中近截面就是投影平面;

正交投影每個座標點只是丟棄了z座標,就不推導了;

透視投影:通過相似三角形求出視景體內頂點x,y座標在投影平面的相對位置,保留z座標;

image-20211209002653905

D3DXMATRIX matProject;
// 這個函式是設定正交投影矩陣
D3DXMatrixOrthoLH(&matProject, width, height, Znear, Zfar);
pD3dDevice->SetTransform(D3DTS_PROJECTION, &matProject);

OpenGL投影矩陣

從右到左將以上矩陣連乘獲得區域性空間到裁剪空間的變換矩陣:

V(clip) = M(projection)*M(view)*M(model)*V(local)

2.著色計算

Flat Shading——一個頂點代表三角形顏色,預設索引中第一個頂點顏色;

Gouraud Shading——逐頂點著色,只計算三個頂點關照資訊,在光柵化階段做插值得到各個片段光照資訊,缺點:插值導致高光非線性;

Phong Shading——馮氏光照,逐片段著色(畫素)法線插值出各個片元的法線資訊,在片元著色器中使用法線、UV、位置等計算光照;

三、曲面細分著色器(Tessellation Shader)

可選階段;

外殼著色器(Hull Shader)、鑲嵌器(Tessellation)、域著色器(Domain Shader)

不建立高模,根據與攝像機距離使用鑲嵌器細化模型,新增三角面(LOD);

Image [20]

四、幾何著色器(Geometry Shader)

可選階段;

以圖元作為輸入資料,可以建立銷燬幾何圖元;

法線視覺化——毛髮效果;

根據距離攝像機遠景動態調整多邊形邊數實現LOD效果;

公告牌技術(BillBoards)——3D圖片替代模型,總是朝向攝像機;

五、圖元組裝(Primitive Assembly)

1.裁剪(Clipping)

Image [22]

1)線段裁剪

點面關係,線面關係,通過向量在面上的投影,以及點是否在矩形內;

八方位裁剪法;

2)三角形裁剪

平頂三角和平底三角形,判斷出界平移頂點;

裁剪演算法有Cohen-Sutherland演算法Liang-Barsky演算法Sutherland-Hodgman多邊形裁剪演算法

2.背面剔除(Back-Face Culling)

只和三角形與攝像機的距離有關,不依賴攝像機朝向;

根據三角形頂點順序,使用左右手座標系,叉乘求出法向量;

頂點順時針法向量朝外剔除,逆時針朝內剔除;

3螢幕對映 (Screen Mapping)

1)透視剔除(Perspective Division)

將視景體空間頂點,除以w分量獲得標準裝置空間,-1到1的立方體空間(CVV-標準視體);

w分量保留的z座標的資訊,正交投影w分量為1,w分量也就是z值代表了深度資訊;

OpenGL變換OpenGL投影矩陣

2)視口變換(View Transform)

通過執行透射除法獲得歸一化的裝置座標NDC(Normalized Device Coordinate);

z值在視口變換過程中被對映,OpenGL對映到[-1,1],DirectX[0,1];

NDC座標對映到視窗座標要通過平移和縮放過程(相機的寬高比);

視口矩陣:xy為視窗相對於螢幕的位置;

image-20211209013022842

六、光柵化(Rasterization)

將圖元離散為片元的過程;

圖元覆蓋一個片元(Overlap)——點取樣(Point Sampling),畫素中間點在三角形內;

超級取樣和多重取樣技術,涉及到抗鋸齒;

1.三角形組裝(Triangle Setup)

三角形組裝會對頂點的輸入資料(比如,顏色、法線、紋理座標)進行插值,得到各個片段對應的資料值,為後面的片元著色器提供片後設資料;

2.三角形遍歷(Triangle Traversal)

遍歷這些三角圖元覆蓋了哪些片元的取樣點,隨後得到該圖元所對應的片元;

頂點資料插值獲得片元的顏色,法線,UV,深度等資訊,用於投射正交插值獲得正確的透視顏色紋理等資訊;

3.線段的掃描轉化

  • Bresenham光柵化演算法

  • 數字微分畫線演算法DDA (Digital Differential Analyzer)

    直線公式,斜率小於1,y增量為整數,大於1,x增量為整數;

4.多邊形填充

求多邊形的幾何重心,以重心為頂點,向多變的各個頂點連線,分割為三角形;

重心顏色:所有三角形頂點顏色的平均值;

計算每個三角形的重心(三個頂點的x,y分別相加除以3);

將三角形重心座標和麵積關聯起來;

sx += curx*curs;

sy += cury*curs;

重心的座標為:tatal.s總面積

center.x = sx/total.s;

center.y = sy/total.s;

七、片元著色器(Fregment Shader)

色彩混合:顏色的RGB值相加,用於混合所有光照效果

色彩調製:色彩乘法,RGB值分別相乘,相當於給RGB值都乘以一個係數,將顏色變亮或變暗;

1.Phong光照模型

1)環境光

用來模擬全域性光照效果;在物體光照資訊基礎上疊加較小的光照常量;

2)漫反射

光線進入物體內部重新散射出來,看做均勻分部所以和觀察者位置無關;隻影響亮度;

  • 蘭伯特餘弦定律(Lambert Consine Law)

    取決表面法線和光線的夾角,夾角越大分量越小,漫反射越小;90度漫反射幾乎為0;

    image-20211209095512523

  • 半蘭伯特模型(Half Lambert)

    v社做半條命時提出,改變物體暗區域的光照資訊;

    將漫反射係數從[0,1]改為[0.5,1],提高暗部的亮度資訊;

    //法線和光線的夾角,
    float diflight = dot(s.Normal,lightDir);
    float hLambert = difLight * 0.5 + 0.5;
    

3)鏡面反射高光

和觀察者的位置有關,不同角度觀察結果不同;

  • Phong光照模型

光線反射向量和觀察向量的夾角;

高光指數:e

image-20211209102210717

在夾角大於90度的情況,會造成高光丟失現象,光線會不連續,有明顯的明暗分界線;

  • Blinn-Phong光照模型

光線向量和觀察向量的中間位置(半形向量)和法線的夾角;

在任何角度觀察,夾角都不會大於90度;不會出現高光不連續現象;

img

  • 材質

    struct Material
    {
    	vector3 ambient;	//環境光
    	vector3 diffuse;	//漫反射
    	vector3 Specular;	//鏡面反射 
    	vector3 emissive;	//自發光
    	float e;			//鏡面反射係數
    }
    

    物體最終顏色 = 環境光結果*環境光反射係數 + 漫反射結果*漫反射係數+鏡面反射結果(計算了高光指數)*鏡面反射係數+材質自發光顏色*自放光係數;

2.紋理貼圖 (Textures)

紋理對映,將影像資訊對映到三角形網格;

凹凸貼圖(bump mapping)、法線貼圖(normal mapping)、高度紋理(height mapping)、視差貼圖(parallax mapping)、位移貼圖(displacement mapping)、立方體貼圖(cubemap)、陰影貼圖(shadowmap);

  • UV座標的定址方式

歸一化到[0,1]之間,畫素大小為2的次方,方便計算處理;

定址方式也叫平鋪方式:重複定址(repeat)、邊緣鉗制定址(clamp)和映象定址(mirror);

uv超出0-1,該如何定址(就是圖片的平鋪,邊緣畫素擴充套件,映象);

  • 紋理取樣方式

紋理畫素和圖元畫素不是一一對應,要用到紋理的濾波方式;

點過濾(point)、線性過濾(linear)、最近領點過濾(nearest neighbor point)和雙線性過濾(bilinear),Unity的Trilinear濾波的技術;

Image [58]

  • 法線貼圖 (Normal Mapping)

物體空間(object space)和切線空間(tangent space)

根據物體空間計算的法線,在物體旋轉移動後回得到錯誤的光照資訊;

切線空間:相對於頂點座標儲存計算;

頂點本身法線為N軸,模型給定定義一條和該頂點相切的切線T軸,N和T叉乘得到B軸;

法線(N)、切線(T)和副切線(B) ,三個軸組成切線空間;

法線貼圖就是在切線空間中記錄了法線擾動的方向;

以頂點法線N為z軸座標系,擾動後的法線z軸也總是朝向(0,0,1),所以得得到法線貼圖總是淡藍色(RGB);

法線紋理最終值需要做個對映,由於維度向量取值[-1,1],紋理通道範圍在[0,1],最終記錄結果為:(normal+1)/2;

切線空間座標系到世界座標系的轉換矩陣

物體移動旋轉時,法線乘以這個矩陣就可以得到改變後的法線;

Image [61]

因為z總是朝向(0,0,1)紋理就可以直接記錄xy——紋理壓縮:DXT1,DXT5;

3.鋸齒和抗鋸齒 (Aliasing and Anti-aliasing)

  • 超級取樣抗鋸齒 (Super-Sampling Anti-aliasing——SSAA)

    將原圖解析度放大一倍,再取樣;光柵化和片元著色都是原來的4倍,渲染快取也是4倍;

  • 多重取樣抗鋸齒 (Multi-Sampling Anti-aliasing——MSAA)

    每個片元有多個取樣點,計算取樣點的覆蓋率(Coverage),光柵化階段計算取樣點覆蓋率,在片元著色器計算顏色值後乘以這個覆蓋率;

    MSAA和延遲渲染(deferred render)不相容(延遲渲染需要Geometry 和Lighting兩個Pass,lighting階段無法通過GBuffer獲得片元覆蓋率);

4.陰影 (Shadows)

光照烘焙獲得Shadowmap;先光照烘焙獲得深度資訊,再通過陰影貼圖判斷那些片元落在陰影中;

Shadowmap的精度會導致陰影粉刺,需要便宜深度來消除粉刺現象;

陰影鋸齒通過百分比漸進過濾(PCF)實現軟化陰影(softshadow);

八、測試和混合(Tests & Blending)

1.裁切測試 (Scissor Test)

裁切測試可以避免當視口比螢幕視窗小時造成的渲染浪費問題;一般預設不開啟,

2.Alpha測試 (Alpha Test)

​ 片段著色器中丟棄alpha值小於0.1的片段;

  • Early-Z Culling

    硬體廠商用來加速渲染的手段;在片元著色之前提出被遮擋的片元;

    但是生效要求只能通過光柵化插值得到深度,不能再片元著色器階段去修改深度緩衝;

3.模板測試 (Stencil Test)

模板測試有一個對應的快取, 即模板快取(Stencil Buffer), 用於記錄所有畫素的模板值, 預設值為0;

片元攜帶的參考值和模板快取中的值比較,滿足比較函式,呼叫操作函式更新模板值;

  • 模板值: 模板快取中已經存在的值

  • 參考值: 在渲染該物體前, 由程式設定的指定值

  • 比較函式: 決定如何將兩個值作比較的函式

  • 操作函式: 定義通過或者不通過測試後對模板值的更新操作

Unity中模板測試不可程式設計,可配置管線階段;

Stencil
{
    Ref refValue		//參考值
    Comp always			//比較函式	
    Pass keep			//模板測試和深度測試都通過後的操作
    Fail keep			//模板測試和深度測試都未通過後的操作
    ZFail keep			//模板測試通過而深度測試未通過後的操作
    WriteMask 255		//使用參考值更新模板值之前, 在模板值與掩碼按位與之後再更新		255代表不做處理
    ReadMask 255		//讀取模板值後, 將其與掩碼按位與之後再與參考值作比較		  255代表不做處理
}

/*
UnityEngine.Rendering.CompareFunction比較函式列舉
0(Disabled): 關閉模板測試, 等同於全部通過測試, 經過測試發現不是真的關閉.
1(Never): 全部不能通過測試
2(Less): 待比較的值小於快取中的值時通過測試
3(Equal): 待比較的值等於快取中的值時通過測試
4(LessEqual): 待比較的值小於等於快取中的值時通過測試
5(Greater): 待比較的值大於快取中的值時通過測試
6(NotEqual): 待比較的值不等於快取中的值時通過測試
7(GreaterEqual): 待比較的值大於等於快取中的值時通過測試
8(Always): 全部通過測試, 預設值
*/

/*
UnityEngine.Rendering.StencilOp操作函式列舉
0(Keep): 保持模板快取中的值不變
1(Zero): 將模板快取中的值置為0
2(Replace): 使用參考值替換模板快取中的值
3(IncrementSaturate): 使模板緩衝區值增大, 最大限制為可表示的最大無符號值
4(DecrementSaturate): 使模板緩衝區值減小, 最小限制為0
5(Invert): 對模板緩衝區值按位求反
6(IncrementWrap): 與IncrementSaturate類似, 只是達到最大後繼續增大將重新設定為 0
7(DecrementWrap): 與DecrementSaturate類似, 只是達到最小後繼續減小將重新設定為可表示的最大無符號值
*/

4.深度測試 (Depth Test)

比較當前片段的深度值是否比深度緩衝中預設的值小(預設比較方式),如果是更新深度緩衝和顏色緩衝;否則丟棄片段不更新緩衝區的值;

Early-Z Culling也是利用Z-Buffer的技術來進行深度測試的,只不過該測試是在片段著色器之前進行;

深度測試是可配置的階段——ZTest和ZWrite

  • Z-Fighting

深度緩衝精度不夠,深度值相近的片元會造成重疊模糊問題:

Image [83]

解決:物體不要靠太近;使用高精度的深度緩衝;

  • 隱藏面消除 (Hidden Surface Removal, HSR)

前面的圖元組裝裁剪,背面揀選,和Z-Buff都屬於HSR,裁剪針對圖元,Z-Buffer針對畫素點;目的都是為了減少到達片元著色器的片元個數,提高渲染效能;

1)視椎體剔除 (Viewing-Frustum Culling)

利用物體包圍盒來做交差檢測,常見的包圍盒有軸對齊包圍盒(AABB)和有向包圍盒(OBB)兩種;

需要是由高效資料結構來提升碰撞檢測的效率——八叉樹(OcTree)、二分空間劃分(Binary Space Partitioning)、四叉樹(Quad Tree)、場景圖(Scene Graphs)、kd樹(K-Dimensional Tree)和層次包圍(Bounding Volume Hierarchies);

計算:

點法式判斷三維空間點和麵的關係,裁剪掉不在視景體內的包圍盒頂點;

求視景體六個面:

通過投影矩陣,求出投影和攝像機的逆矩陣,反向求出視景體對應面;

求逆矩陣——行列式,代數餘子式,伴隨矩陣,行列式的值,有固定公式;

近截面裁剪:

三角形和麵的關係,用向量表示三角形和麵;兩條共起點的向量可以表示三角形;分解成線和麵的關係;

三角形和近截面的關係:

1個角在視景體內——偏移另外兩個頂點到視景體平面上;

2個角在視景體內——三角形拆分為2個三角形,注意三角形頂點連線順序;

2)入口剔除 (Portal Culling)

將室內的門或者窗戶看做視椎體來進行裁剪;實現"籠中窺夢"的效果;

3)遮擋剔除 (Occlusion Culling)

通過離線烘焙的犯法來預先計算出潛在可視集合(Potentially Visible Set,PVS);

PVS記錄了每個地形塊(Tiles)可能看到的物體的集合,用於執行時查詢計算;

場景劃分為小地形塊,每個塊上隨機取N個取樣點;

從取樣點發射射線獲取場景中和射線相交的物體,記錄物體ID;

根據攝像機位置,使用取樣點機率的物體id列表進行渲染;

取樣精度和烘焙效率問題;

6.Alpha混合 (Alpha Blending)

經過前面所有的測試才能進入Alpha混合階段,一個測試過不了都到不了Alpha混合;

Alpha混合實現物體半透明效果,渲染順利非常重要,可能需要手動改Queue(渲染佇列)的值;

  • 渲染順序:

先渲染不透明物體,從前往後渲染;——不透明物體渲染前先進行深度檢測,先後近的物體,遠處物體通不過深度檢測,就不用進行深度寫入操作;

再渲染半透明物體,從後往前渲染;——半透明物體渲染需要知道前一層的顏色資訊進行混合,先渲染遠處物體,在畫近處物體時可以通過顏色快取獲取前一層顏色資訊;

畫家演算法:先畫物體會被後畫物體覆蓋;

Unity ShaderLab中渲染佇列設定;

Queue 其他預定義的值為:Background = 1000 , AlphaTest = 2450,Overlay = 4000。預設值是Geometry =2000;

ShaderLab預設開啟深度測試和深度寫入;

//將本 Shader 計算出的顏色值(源顏色值,即藍色) * 源Alpha值(0.6) + 目標顏色值(可以理解為背景色) * (1-0.6)
Blend SrcAlpha OneMinusSrcAlpha
// Transparent (透明) = 3000,值越小越先渲染,而後渲染( Queue 值大)的物體會覆蓋先渲染的物體    
Tags {"Queue" = "Transparent"}

ZTest LEqual 	       //小於等於
ZWrite On 		//開啟
//ZTest 可取值為:Greater , GEqual , Less , LEqual , Equal , NotEqual , Always , Never , Off,預設是 LEqual,ZTest Off 等同於 ZTest Always
//ZWrite 可取值為:On , Off,預設是 On
  • 順序無關半透明演算法(Order-independent transparency,OIT)

深度剝離(Depth Peeling)

雙向剝離(Dual Depth Peeling)——兩個方向剝離,一個從前往後,一個從後往前,兩個方向效率提高;

相關文章