[OpenGL] ShapeNet 模型 render 問題

ShapeNetCore 是一個很大的 3D 模型 dataset。他的檔案格式是 .obj。因為研究上的需要,要把 3D 模型 render (phong shading) 成 12 個角度的圖。

我是用 OpenGL 並用 vertex shader 和 fragment shader 去繪製的,有環境光和一顆點光源。理想上應該要有這種非常光滑的圖(這是 ModelNet40 的一個飛機模型):

螢幕快照 2017-03-27 上午12.43.48.png

但 ShapeNetCore 的一台飛機畫出來卻會這樣:

螢幕快照 2017-03-27 上午12.40.46.png

 

這問題經過大量的 Google 和思考,最後確認了原因:

ShapeNetCore 的模型 obj 檔案中,同樣三個點 A B C 組成的面,正面和反面可能會重複出現。也就是會有 F1(A, B, C) 和 F2(A, C, B)。這兩個面是完全重疊的,而法向量則恰好相反。

 


TL;DR

解法:動態在 render 時刪除那些"法向量背對視角(看不到)的面"並且重新計算所有頂點法向量。


 

在 fragment shader 中,會利用該像素的表面法向量光線視角算出表面顯示的顏色。而像素的表面法向量則是在 fragment shader 中自動由附近的頂點法向量內插得到的。

但 obj 檔案並不一定會給每個頂點的頂點法向量,所以實際上,頂點法向量是在 obj 檔案載入的時候,先列出有哪些面使用該頂點,並一一用每個面的三頂點外積得到所有平面法向量,再平均起來。

當同一個頂點被正反兩個面都使用到的時候,這兩個面的法向量相加恰好等於 0,互相抵消。因此,這個面的法向量會是錯誤的。最差的情況甚至是三個面都有正反面,抵消完整個歸零,所以頂點法向量 = 0。

附上一張概念圖:

螢幕快照 2017-03-27 上午1.12.55.png

N2 是正面,N2′ 則是和 N2 疊合卻反向的面。

螢幕快照 2017-03-27 上午1.14.01.png

 

問題清楚了,接下來得想解決方法。

Google double-faced 之類的關鍵字,會找到 Back face culling 之類的。但這不是我們要的,因為我們不是要 “不顯示一個正確的面的背面" ,而是要 “不顯示一個錯誤的面 (的正面)"。

最後的方法是,在每一個角度要 render 時,都根據當前的視角,列出哪些面的法向量和視線反向(朝向遠方),刪除那些面,只留下和視角同向(朝向眼睛)的面。再用剩餘的面,執行上述計算所有頂點法向量的步驟,然後餵進 vertex shader。

 

其他軟體

其他軟體有些也有遇到一樣的問題,有些則是處理的不錯。

Blender

非常的順利。要不是想要保持 data 的一致性(因為 ModelNet40 是用我的 OpenGL 程式畫的),我就直接換成用 Blender render 了。

Meshlab

顯示錯誤(跟我的問題一樣)。

GLC Player

正常顯示。

 

廣告
[OpenGL] ShapeNet 模型 render 問題