此為 Three.js 中物體的遠近關係 系列文章 - 第 7 篇:
- Three.js 中物體的遠近關係 (1) - 什麼是深度測試?
- Three.js 中物體的遠近關係 (2) - 左手/右手座標系與齊次座標
- Three.js 中物體的遠近關係 (3) - 深度值的計算方式
- Three.js 中物體的遠近關係 (4) - 對數深度值
- Three.js 中物體的遠近關係 (5) - 渲染物體的順序
- Three.js 中物體的遠近關係 (6) - 如何正確的渲染透明粒子?
- Three.js 中物體的遠近關係 (7) - 使用 polygonOffset 動態改變深度值
前言
在第四篇系列文 - 大尺度場景下導致的 z-fighting 中提到當兩個物體的深度值非常接近時,會難以辨別是哪個物體在前、哪個物體在後造成 z-fighting 問題,今天這篇文章則是希望使用 polygonOffset 來改變物體的深度值以解決 z-fighting 的問題
polygonOffset 的用法
1 | const material = new THREE.Material({ |
polygonOffset: 開啟後可以利用 polygonOffsetFactor 及 polygonOffsetUnits 調整深度值
polygonOffsetFactor: 調整 polygonOffset
偏移的比例
polygonOffsetUnits: 調整 polygonOffset
偏移的大小
polygonOffset 的計算公式
$$
offset = m * factor + r * unit
$$
offset: 最終改變的深度偏移值
m: 深度坡度(depth slope),代表著 z 軸深度值除以 x, y 軸的變化量,後面會再提到
factor: polygonOffsetFactor
設定的值
r: 是一個常數,代表深度值的最小單位,實際的值取決於 深度值的精度
unit: polygonOffsetUnits
設定的值
所以當希望一個物體離我們比較近的時候可以設定 polygonOffsetFactor
及 polygonOffsetUnits
都是負數,這樣可以將深度值變小代表物體離鏡頭更近,反過來則是將 polygonOffsetFactor
及 polygonOffsetUnits
設成正數,代表物體離鏡頭更遠
範例 - 應用 polygonOffset
在這個範例中我們嘗試將自己的 logo 貼到車子的前面,其中 logo 跟車頭燈所在的那片平面,他們的 z 值都是一樣的,所以當沒有設定 polygonOffset
前,可以看到 logo 出現明顯的 z-fighting 問題
此時將 polygonOffset
打開,因為希望 logo 可以顯示在前面,所以將 polygonOffsetFactor
及 polygonOffsetUnits
都設成負數使 logo 的深度值變小,可以簡單的設定 polygonOffsetFactor = -0.1
及 polygonOffsetUnits = -1
,如此一來就可以看到 logo 正常顯示不會一直閃爍
深度坡度分析
深度坡度(depth slope) 代表 z 軸深度值除以 x, y 軸的變化量,這意味著 深度坡度 的值是浮動的,當物體垂直於視線方向的鏡頭時,即使 x, y 軸的座標改變,z 軸的深度值都不會改變,也就是說此時 深度坡度 的值接近於 0,而當物體幾乎平行於鏡頭時,x, y 軸的座標只要變一點,z 軸的深度值就會急劇的改變代表此時 深度坡度 的值非常大
以下面的影片展示為例,藍色的直線指向 +z 軸,當設定 polygonOffsetFactor = -0.1
及 polygonOffsetUnits = 3
並且 logo 所在的平面幾乎垂直於鏡頭時,由於 深度坡度 的值很小,因此最後計算出來的深度值幾乎都是受到 polygonOffsetUnits
的影響,造成 logo 的深度值變大而隱藏在藍色車子裡面,但當將鏡頭往上或往下移動時,深度坡度 的值就會變大,因此 polygonOffsetFactor
會大於 polygonOffsetUnits
造成的影響,就可以看到 logo 顯示在前面