今天來談談3D開發中的兩個重要知識點Culling(剔除)和Clipping(切分)。
左圖表示一個完整的3D渲染流程,可以看到Culling和Clipping處理發生在投射計算和渲染計算之前。
Culling過程是用于剔除不需要參與渲染的物體和三角面,進而達到節約資源的目的。一般來說Culling分為以下4種:
- Frustum culling:視錐剔除,PV3D裡最重要的剔除方式,下面詳述。
- Back-face culling:當面背對相機時候剔除,由PV3D自動執行。
- Contribution culling:當物體在畫面上過小情況下的剔除,PV3D裡面沒有這種機制,但是可以用遠平面(camera.far)來剔除。
- Occlusion culling:包藏剔除,适用于一個物體完全被另一個物體遮擋的情況,PV3D不包含這種機制。
Frustum culling在PV3D中分兩種:分别是基于camera(相機)和基于viewport(視口)的。
使用以下代碼開啟基于相機的剔除功能(DebugCamera是預設開啟的):
camera.useCulling = true;
通過檢視do3d.culled屬性可以知道物體是否被剔除。要注意這種剔除機制是針對整個物體(do3d)計算的,隻有當整個物體完全不在視錐内,才會被剔除。
另一種基于視口的剔除在PV3D中是預設開啟的,也可以用以下代碼來制定:
viewport.autoCulling = true;
這種剔除機制是基于面(triangle)的,任何超過視口平面的矩形渲染區的三角面都不會被渲染。
注意:如果物體的某些面超過了近平面(camera.near),那麼即使視口剔除是關閉的,超過的面也會被剔除。
我們可以通過檢視PV3D狀态視圖中給出的資訊,來了解一下剔除的實際作用,在左圖中的COb、CTr分别代表了被剔除的物體和三角面。
了解了剔除機制,那麼Clipping又是什麼呢?試想一下,如果物體的某些面超出了視錐(比如鏡頭進入一個球體内部,必定有部分面是處于近平面的後方而被剔除的)。如果被剔除的三角面有部分頂點是在視口内部的,就會出現破面的問題(如下圖左邊黑色的區域)。
Clipping是用切分面的方法(通過計算三角面與視錐平面之間的交點來生成新的三角面)來解決由于culling産生的破面問題。在PV3D中Clipping是通過FrustumClipping類來實作的:
ender.clipping = new FrustumClipping(FrustumClipping.ALL);
該類需要的唯一參數表示視錐的某些面。視錐的每個面都可以參與計算Clipping,但是這麼做資源耗費很大,一般情況下隻要計算近平面Clipping就足夠了:
ender.clipping = new FrustumClipping(FrustumClipping.NEAR);
通過下面兩張圖可以對比一下兩種計算方式的差别:
ALL:
NEAR:
兩種計算方式都解決了破面問題,可以看到僅使用近平面Clipping的方式效率更高一些。
雖然我們通過Culling減輕了渲染計算量,但是也帶來了破面的副作用。然後又通過Clipping計算來解決這個問題,隻要設定合理,還是能節約大量的 CPU資源。記住上面提到過的在PV3D中超過近平面的三角面是确定一定以及肯定會被剔除的,是以在某天你肯定會遇到破面的問題,在你打開 Clipping功能前,考慮以下三個建議:
- 優先考慮僅近平面Clipping,大部分情況下足夠了。
- 如果可以肯定某物體不會超出視錐範圍,可以設定其useClipping屬性為 false來排除計算。
- 配合設定camera.useCulling = true。記住在一個渲染流程中,Culling在Clipping之前檢測。如果整個物體都被剔除,那麼也就沒必要檢測基于面的Clipping了。隻有當物體與視錐相交時才有必要計算Clipping。
參考資料:
- http://blog.zupko.info/?p=170
- Papervision 3D Essential