threeJs中鏡頭拉遠導致物體閃爍

2021-09-24 15:44:02 字數 3116 閱讀 1947

z-buffer

在threejs中,使用深度緩衝(z-buffer)來完成場景可見性計算,即確定場景哪部分可見,哪部分不可見。深度緩衝(z-buffer)是乙個二維陣列,其中的每乙個元素對應螢幕上的乙個畫素,如果場景中的兩個模型在同乙個畫素生成渲染結果,那麼圖形處理卡就會比較二者的深度,並且保留距離觀察者較近的物體在該畫素點的渲染結果,這樣就形成了近的模型遮擋遠的模型的結果。

上面說到,深度緩衝(z-buffer)是乙個二維陣列,但是陣列的元素型別卻可以不同,不同的元素型別代表著不同的精度。這和顏色的精度很像,比如gif影象最多用8bit儲存乙個顏色,也即gif最多支援256種色彩。以此類推,如果深度緩衝的也用8bit來儲存乙個畫素的深度,那就是說該深度快取只有256個深度級別。在threejs中只實現了一種深度緩衝,但是在例子中,又實現了乙個精度更高的深度緩衝——logarithmicdepthbuffer,可以看示例webgl_camera_logarithmicdepthbuffer

z-fighting

當場景中的兩個模型在同乙個畫素生成的渲染結果對應到乙個相同的深度值時,渲染器就不知道該使用哪個模型的渲染結果了,或者說,不知道哪個面在前,哪個面在後,於是便開始「胡作非為」,這次讓這個面在前面,下次讓那個面在前面,於是模型的重疊部位便不停的閃爍起來。這便是z-fighting問題。

這裡寫描述

解決 z-fighting

要解決z-fighting問題,有兩個思路:

讓各模型渲染結果不要在同乙個畫素出現相同深度值

人為設定渲染順序,這樣即使出現相同深度值,也能正確渲染

這裡說一下第二種方法為什麼也能解決z-fighting,比如有兩個模型a和b,a的渲染順序是0,b的渲染順序是1,既是先渲染a,再渲染b,所以,如果a和b在某個地方出現了相同的深度值,那麼後渲染的b會覆蓋掉先渲染的a。下面是按照這兩個思路提出的一些解決辦法。

別讓模型靠得那麼近

手動設定一定的偏移即可讓這個問題解決,比如下面兩個例子:

刻度的z值為0,和尺子處於同一平面,會出現z-fighting問題,可以看到刻度文字不停閃爍

有z-fighting的例子

刻度得z值設定3,和尺子分處不同的平面,無z-fighting問題

無z-fighting的例子

設定合適的near和far值

在建立相機的時候,會有near和far兩個引數,用來設定相機的近平面和遠平面。這個兩個引數其實和深度緩衝(z-buffer)也密切相關,深度緩衝其實是非線性的,靠近相機的地方精度更高。什麼意思呢?假如你的深度緩衝只有10個深度級別,你的相機的near=1,far=100,那麼你的深度緩衝可能是這樣的:

深度級別 深度範圍

0 0~1.0

1 1.0~1.1

3 1.1~1.234

4 1.234~1.325

5 1.325~1.55667

6 1.55667~1.9634

7 1.9634~5.434

8 5.434~23.34834

9 23.34834~99.999

(資料是杜撰的)

這樣的非線性深度快取可能會造成在離相機較遠的地方深度等級的劃分過於粗糙,比如上面的深度等級9,離相機的距離從23.34834到99.999的面都屬於同乙個深度級別,從上面可以,兩個面對應到同乙個深度級別就可能會出現z-fighting,所以,這個深度快取出現z-fighting的概率還是挺大的。

一般來說,選擇乙個稍微大一點的near值效果會明顯,比如把near從0.1設為1。

polygonoffset 是否開啟多邊形偏移

polygonoffsetfactor 多邊形偏移因子

polygonoffsetunits 多邊形偏移單位

當發生兩個面深度值相同時,設定了polygonoffset的面便會向前或向後偏移一小段距離,這樣就能區分誰前誰後了。

當polygonoffsetfactor和 polygonoffsetunits的都是正值時,向遠離相機的方向偏移,當兩者都是負值時,向靠近相機的地方偏移。

設定polygonoffsetfactor和 polygonoffsetunits是有所講究的:

當面和近平面(near)、遠平面(far)幾乎平行的時候,乙個很小的偏移就足夠,你可以設定polygonoffsetfactor=0, polygonoffsetunits=1.0

當面和近平面(near)、遠平面(far)有乙個明顯的角度時,這時候就需要乙個較大的偏移和乙個較小但非零的偏移因子。這是因為要分開兩個交叉的面要比分開兩個重合的面要更大的偏移。你可以設定如polygonoffsetfactor=0.75, polygonoffsetunits=4.0

這部分內容很多都來自z fighting & polygon offset,原文講得更好點。

設定 render order

threejs的object3d物件定義了乙個renderorder屬性,可以指定物件的渲染順序,按renderorder從小到大排列,小的先渲染,大的後渲染。

設定完renderorder之後,就算兩個面有同樣的深度,但是因為有渲染順序,後渲染的面會覆蓋掉先渲染的面。也因為這樣,設定正確的渲染順序很重要。

此外,這種方法更經常用在處理元素透明問題上,詳見transparent-objects-in-threejs。

使用 logarithmicdepthbuffer 緩衝

緩衝的級別越多,衝突的概率相應的也就越低,所以,我們可以使用乙個精度更高的z緩衝,來代替原有的z緩衝。對於這個方法,threejs官網已經提供了乙個例子webgl_camera_logarithmicdepthbuffer。不過,官網的例子為了演示效果,寫得比較複雜,實際上只需要將logarithmicdepthbuffer引數設為true即可:

var renderer = new three.webglrenderer();

1參考文件

1、解釋如什麼是z-fighting及何用polygon offset

z fighting & polygon offset

(2)z-fighting

3、解釋了 depth write的使用

how to use polygonoffset solving z-fighting poblems

4、講到了解決透明問題的方法,比較全面

transparent objects in threejs

原文訪問

ThreeJS中CameraHelper的使用

參考 想達到這種效果,都必須使用2個相機。就如上圖2所示,螢幕相機的投影是整個螢幕 左右兩個小視窗共同組成 帶相機助手的投影是左面的畫面。偽 螢幕相機 let camera newthree.perspectivecamera 45 1,0.01 300 camera.position.set 1 ...

threejs中矩陣旋轉原理

建立乙個立方體cube放到場景中 繞向量 1,1,0 旋轉30度 var axis new three.vector3 1,1,0 建立乙個三維向量 var rotworldmatrix new three.matrix4 建立乙個4 4矩陣 rotworldmatrix.makerotationa...

threejs 入門中的OrbitControls

threejs 可以通過 npm install three 來安裝 文件介紹 軌道控制使攝像機可以圍繞目標旋轉。orbitcontrols object camera,domelement htmldomelement object 必需 要控制的攝像機。相機不得是其他物件的子物件,除非該物件是場...