1. 程式人生 > 實用技巧 >渲染管線學習隨筆 --- 三角形的頂點繞序與背面消隱

渲染管線學習隨筆 --- 三角形的頂點繞序與背面消隱

今天依然在研究BlauHimmel大神的光柵器程式碼 [1]。在自己實現的時候發現自己的顏色填充渲染只渲染了一半的三角形,還有部分渲染部分被截去了。經前輩指點,問題應該是出在三角形的頂點繞序:因為三角形的頂點在生成 Mesh 的時候排列混亂,導致攝像機沒法分清平面的正面背面,從而影響了渲染效果。

所以打算學習並總結一下這個問題(以下內容總結自《騰訊遊戲學院:渲染管線之背面消隱[2]):

  • 什麼是背面消隱

在渲染由多個三角形網格所組成的物體時,在將物體渲染到螢幕時,我們需要根據相機的視角刪除不需要渲染的網格(或多邊形)。這些網格是相機視角無法看到的網格部分,比如說在物體背向相機的網格(相機看不到的面)。

  • 頂點繞序與背面消隱的關係

由於背面消隱的基本數學計算是根據被渲染物體的每個面的法向量來計算的,而每個面的法向量又基於三角形的頂點來計算。三角形的法向量計算方式如下:

// p1, p2, p3, 為三角形的三個頂點
Vector3 v1 = p2.position - p1.position;
Vector3 v2 = p3.position - p2.position;
// 計算法向量
Vector3 normal = Vector3.Cross(v1, v2);

其中,所有三角形的三個頂點必須嚴格按照逆時針或者順時針的順序儲存,否則將會影響相機判斷那個面面對相機需要渲染,哪些面需要剔除。

在得到面的法向量後,我們需要求得觀察向量(相機到三角形某一頂點的向量)與法向量的夾角來判斷這個面是否要渲染。若夾角小於 90 度,則這個面需要被渲染。若大於等於 90 度則不渲染。計算方式如下:

// 觀察向量
Vector 3 viewDir = p1.position - camera.position;
// 判斷是否渲染
if(Vector3.Dot(normal, viewDir) < 90){    
    // render code ...
    return true;
}      
return false;

背面消隱的圖片講解請看《騰訊遊戲學院:渲染管線之背面消隱》[2]

以上的完整虛擬碼如下:

 1 bool BackFaceCulling(Vertex p1, Vertex p2, Vertex p3){
 2     // p1, p2, p3, 為三角形的三個頂點
 3     Vector3 v1 = p2.position - p1.position;
 4     Vector3 v2 = p3.position - p2.position;
 5     // 計算法向量
 6     Vector3 normal = Vector3.Cross(v1, v2);
 7 
 8     // 觀察向量
 9     Vector 3 viewDir = p1.position - camera.position;
10     // 判斷是否渲染
11     if(Vector3.Dot(normal, viewDir) < 90){    
12         // render code ...
13         return true;
14     }      
15     return false;
16 }

TODO:接著完善自己的程式碼。

參考材料:

[1]BlauHimmel --- Simple-3D-Renderer:https://github.com/BlauHimmel/Simple-3D-Renderer

[2] 騰訊遊戲學院:渲染管線之背面消隱:https://gameinstitute.qq.com/article/detail/289434