【Cesium 歷史博客】地平線剔除算法


Horizon Culling | cesium.com

在開發 Cesium 程序時,需要快速確定場景中的對象什么時候不可見,從而判斷它不需要渲染。

一種方法是使用視錐體平視剔除,但是還有另一種重要的剔除方法是地平線剔除。

上圖中,綠色點是 viewer 內可見的。紅色點是不可見的,因為它們在視錐體外面(視錐體用粗白線畫出)。藍色點雖然在視錐體內,但是它在地球背面,所以它也是不可見的。換句話說,它在地平線下。

地平線剔除的思路很簡單,即不需要渲染 viewer 視野中地平線之下的東西。聽起來簡單,但是細節挺多的,尤其是要考慮到性能問題(要快速剔除)。Cesium 每次渲染時,為了檢測這些地形瓦片的可見性,就要測試上百次,不過這很重要。

相對於球體的地平線下點剔除

可為所有靜態對象(例如瓦片)計算其范圍球體(boundingSphere)。假設這個范圍球體很小以至於與地球比起來,像一個點,如果這個點在地平線下,那么我們也能說這個瓦片就在地平線下。

當前提出的新算法僅限於對橢球體計算單個點的情況。現在不妨設“遮擋點”已經被計算出來了。

為了說明簡便,先進行正球體的地平線剔除,然后再推廣到橢球體的地平線剔除。

考慮下面這張圖片:

上圖中,藍色的圓是一個單位球面,從 Viewer 向外延申並和單位球面相切的這兩條細黑線表示地平線。

垂直的這根粗黑線表示地平線交單位球面的所有地平點,是一個圓。

從 Viewer 到這個圓上的所有點的向量,就構成了一個圓錐體(包括陰影部分)。

譯者注

想象一下一個漏斗套一個乒乓球,大概就是這個情況

圖中陰影部分表示地平線以下的區域,Viewer 看不到這些區域。換句話說,如果一個點在這個陰影區域,那么這個點就在地平線下。

計算某點位於平面的哪一側

首先,做一個簡單的計算,來算出這個點在垂直黑直線那個圓的圓面的哪一邊:

  • V:Viewer的位置
  • C:單位球面的中心
  • H:地平線切單位球面的點
  • T:待計算的目標點
  • P:H點投影到VC向量的點
  • Q:T點投影到VC向量的點

由勾股定理:

\[||\vec{VH}||^2 + ||\vec{HC}||^2 = ||\vec{VC}||^2 \]

由單位球,易得 \(\vec{HC}\) 向量的長度是1:

\[||\vec{VH}||^2 = ||\vec{VC}||^2-1 \]

易證 \(△VCH\)\(△HCP\) 相似,所以有:

\[\frac{||\vec{PC}||}{||\vec{HC}||}=\frac{||\vec{HC}||}{||\vec{VC}||} \]

代入 \(||\vec{HC}|| =1\),整理得

\[||\vec{PC}||=\frac{1}{||\vec{VC}||} \]

所以,Viewer 到平面(下文均用平面簡稱,即地平線與球面相切的所有點的集合構成的圓周代表的面,即圖上垂直黑色粗線)的距離:

\[||\vec{VP}||=||\vec{VC}|| - \frac{1}{||\vec{VC}||} \]

如果,\(\vec{VT}\)\(\vec{VC}\) 的投影 \(\vec{VQ}\) 長度小於 \(\vec{VP}\),那么點就在平面內(視錐內)。

換句話說,如果 \(||\vec{VQ}||>||\vec{VP}||\),那么點就在地平線下:

\[||\vec{VQ}||=||\vec{VT}||cos(\vec{VT}, \vec{VC})=\vec{VT}·\hat{VC}>||\vec{VP}||=||\vec{VC}|| - \frac{1}{||\vec{VC}||} \]

左右均乘以 \(||\vec{VC}||\),即

\[\vec{VT}·\hat{VC}·||\vec{VC}||=\vec{VT}·\vec{VC}>||\vec{VC}||^2-1 \]

結論

若想知道目標點位於平面的前面還是后面,只需取 Viewer 到目標點的向量 \(\vec{VT}\)、Viewer 到單位球心的向量 \(\vec{VC}\),求其內積,判斷結果與 Viewer 到單位球心距離與1的差的大小即可。

若大於,則點在地平線下(平面后),反之則在平面前(地平線上)

判斷目標點與圓錐體的關系

仍舊是考慮原來的圖,這次考慮兩個角 \(∠HVC\)(記為α)、\(∠TVC\)(記為β)

img

當角 β < α 時,目標點 T 就位於圓錐內了。

\([0, π]\) 區間上,對於任意的 β > α,有

\[cos(β) > cos(α) \]

角 α 是 \(Rt△VCH\) 的一個角,所以:

\[cos(β) > \frac{||\vec{VH}||}{||\vec{VC}||} \]

由余弦的定義,cos(β) 可寫為

\[cos(β) = \frac{\vec{VT}·\vec{VC}}{||\vec{VT}||·||\vec{VC}||} \]

\[cos(β) = \frac{\vec{VT}·\vec{VC}}{||\vec{VT}||·||\vec{VC}||} > \frac{||\vec{VH}||}{||\vec{VC}||} \]

兩邊同時乘上 \(||\vec{VC}||\) 並同時平方,則

\[\frac{(\vec{VT}·\vec{VC})^2}{||\vec{VT}||^2}>||\vec{VH}||^2 \]

根據上一節的計算結果 \(||\vec{VH}||^2=||\vec{VC}||^2-1\)

最終,得到的不等式關系是:

\[\frac{(\vec{VT}·\vec{VC})^2}{||\vec{VT}||^2}>||\vec{VC}||^2-1 \]

\(\vec{VT}\)\(\vec{VC}\) 都很容易計算,若上式不等號成立,則說明目標點在視錐內,否則在視錐外。

推廣到橢球體的情況

上述均為單位球的情況,現在推廣到橢球體上。

單位球的方程是:

\[x^2+y^2+z^2=1 \]

橢球體的方程是:

\[\frac{x^2}{a^2}+\frac{y^2}{b^2}+\frac{z^2}{c^2}=1 \]

其中,a、b、c是三個軸的半長(軸半徑)。

利用縮放矩陣,可以將橢球體上的所有點歸為單位球上的計算:

\[M=\begin{bmatrix} \displaystyle\frac{1}{a} & 0 & 0 \\ 0 & \displaystyle\frac{1}{b} & 0 \\ 0 & 0 & \displaystyle\frac{1}{c} \\ \end{bmatrix} \]

代碼

作者認為數學推導過程很重要,但是可以歸結成一些簡單的代碼。每當攝像機位置改變時,都要執行

// 橢球的三個軸半徑 此處使用 WGS84橢球體
var rX = 6378137.0;
var rY = 6378137.0;
var rZ = 6356752.3142451793;

// 向量CV,縮放到單位球空間(除以各軸半徑),方便計算
var cvX = cameraPosition.x / rX;
var cvY = cameraPosition.y / rY;
var cvZ = cameraPosition.z / rZ;
// 向量VH長度的平方
var vhMagnitudeSquared = cvX * cvX + cvY * cvY + cvZ * cvZ - 1.0;

然后對於每個點,要進行測試遮擋剔除算法:

// 目標點T,縮放到單位球空間(除以各軸半徑),方便計算
var tX = position.x / rX;
var tY = position.y / rY;
var tZ = position.z / rZ;

// 向量VT
var vtX = tX - cvX;
var vtY = tY - cvY;
var vtZ = tZ - cvZ;
// 向量VT長度的平方
var vtMagnitudeSquared = vtX * vtX + vtY * vtY + vtZ * vtZ;

// VT點乘VC 和 VT點乘CV的相反數是一樣的
var vtDotVc = -(vtX * cvX + vtY * cvY + vtZ * cvZ);

// bool值,前者是判斷是否在平面內,后者判斷是否在錐體內
var isOccluded = vtDotVc > vhMagnitudeSquared && vtDotVc * vtDotVc / vtMagnitudeSquared > vhMagnitudeSquared;

在 Cesium 中,預先進行了單位球空間的縮放,而不是每次測試都縮放。

EllipsoidalOccluder.prototype.isPointVisible = function (occludee) {
  var ellipsoid = this._ellipsoid;
  var occludeeScaledSpacePosition = ellipsoid.transformPositionToScaledSpace(
    occludee,
    scratchCartesian
  );
  return isScaledSpacePointVisible(
    occludeeScaledSpacePosition,
    this._cameraPositionInScaledSpace,
    this._distanceToLimbInScaledSpaceSquared
  );
};

展望

與之前使用最小范圍球進行剔除的方法相比,使用這個技術減少大約 15% 的瓦片繪制。

其他就不翻譯了

實際應用

在 Cesium 的私有類 EllipsoidalOccluder (位於Core目錄下)中,就使用了這個算法進行剔除計算。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM