2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

3dTiles 幾何誤差詳解

 新進小設(shè)計 2021-11-19

轉(zhuǎn)載請注明出處。全網(wǎng)@秋意正寒

1. 瓦片的調(diào)度

查閱 tileset.json 的規(guī)范,有一個屬性是 refine,它有兩個值:"ADD""REPLACE"。

還有另一個屬性,叫 geometricError,是一個數(shù)字。

"ADD" 的含義是,當(dāng)這一級瓦片顯示不夠精細時,渲染下一級瓦片,這一級的瓦片保留繼續(xù)顯示(增加下一級的內(nèi)容)。

"REPLACE" 的含義是,當(dāng)這一級瓦片顯示不夠精細時,渲染下一級瓦片,這一級的瓦片被銷毀(被下一級“替換”)。

如何衡量這個“不夠精細”?

一個很簡單的思路是利用觀察點(也就是相機)到觀察瓦片的距離來判斷。這個相機與瓦片的距離超過我指定的某個閾值的時候,就要渲染下一級瓦片,而這一級瓦片則根據(jù) refine 的值進行保留或銷毀。

所謂的 “指定的某個閾值”,在這里有一個專有名詞:最大屏幕空間誤差(maximumScreenSpaceError)。

這個值是 Cesium3DTileset 類中的實例屬性,默認值是16.

暫且不說這個16的具體含義,先回顧剛才的思路:計算相機到瓦片的距離,設(shè)為distance,就能與這個值進行比較了嗎?不是的。

1.1 屏幕空間誤差(ScreenSpaceError, sse)

計算當(dāng)前瓦片的屏幕空間誤差值,才能與 maximumScreenSpaceError 進行比較,因為這兩個才是同一種東西嘛。

先說結(jié)論:屏幕空間誤差(ScreenSpaceError, sse)由幾何誤差、相機狀態(tài)有關(guān)的各項參數(shù)計算而來。

也就是說,只要 Cesium 在跑,這個 sse 就是一幀一幀實時計算的,每時每刻都在計算。

查閱 Cesium3DTile 的源碼,不難得知它的計算方法被定義在 Cesium3DTile 中(可以跳過代碼不看):

// Cesium3DTile.js >> Cesium3DTile.prototype.getScreenSpaceError()
Cesium3DTile.prototype.getScreenSpaceError = function (
  frameState,
  useParentGeometricError,
  progressiveResolutionHeightFraction
) {
  var tileset = this._tileset;
  var heightFraction = defaultValue(progressiveResolutionHeightFraction, 1.0);
  var parentGeometricError = defined(this.parent)
    ? this.parent.geometricError
    : tileset._geometricError;
  var geometricError = useParentGeometricError
    ? parentGeometricError
    : this.geometricError;
  if (geometricError === 0.0) {
    // Leaf tiles do not have any error so save the computation
    return 0.0;
  }
  var camera = frameState.camera;
  var frustum = camera.frustum;
  var context = frameState.context;
  var width = context.drawingBufferWidth;
  var height = context.drawingBufferHeight * heightFraction;
  var error;
  if (
    frameState.mode === SceneMode.SCENE2D ||
    frustum instanceof OrthographicFrustum
  ) {
    if (defined(frustum._offCenterFrustum)) {
      frustum = frustum._offCenterFrustum;
    }
    var pixelSize =
      Math.max(frustum.top - frustum.bottom, frustum.right - frustum.left) /
      Math.max(width, height);
    error = geometricError / pixelSize;
  } else {
    // Avoid divide by zero when viewer is inside the tile
    var distance = Math.max(this._distanceToCamera, CesiumMath.EPSILON7);
    var sseDenominator = camera.frustum.sseDenominator;
    error = (geometricError * height) / (distance * sseDenominator);
    if (tileset.dynamicScreenSpaceError) {
      var density = tileset._dynamicScreenSpaceErrorComputedDensity;
      var factor = tileset.dynamicScreenSpaceErrorFactor;
      var dynamicError = CesiumMath.fog(distance, density) * factor;
      error -= dynamicError;
    }
  }

  error /= frameState.pixelRatio;

  return error;
};

這么長,其實在我們關(guān)心的三維模式(即 frameState.mode 為 SceneMode.SCENE3D)下,最核心的只有一句代碼:

error = (geometricError * height) / (distance * sseDenominator);

其中,

  • error 即計算得到的 sse 屏幕空間誤差
  • geometricError 即當(dāng)前瓦片設(shè)置好的幾何誤差,寫在 tileset.json 中
  • height 即瀏覽器當(dāng)前運行著 Cesium 的那個 canvas 的像素高度,如果沒有自己設(shè)置 progressiveResolutionHeightFraction 值,通常 height 值就是canvas 的像素高度,如果你的 Cesium 占據(jù)了全屏,你的顯示器分辨率是 1920 × 1080,那么這個 height 在你瀏覽器全屏?xí)r,通常是 936 像素。
  • distance 是當(dāng)前狀態(tài)下,攝像機的世界坐標(biāo)位置到瓦片中心位置的距離,單位是米
  • sseDenominator 是一個根據(jù)當(dāng)前相機狀態(tài)下,根據(jù)視錐體的張角(fov)、長寬比參數(shù)進行一系列三角計算、四則運算而來的一個參數(shù),具體含義我沒有深究,但是通常狀態(tài)下,很少會去修改默認相機的參數(shù),即張角 60 度,寬高比就是 1920÷936(就是canvas的像素寬高比啦),所以這個值也是固定的,有興趣的讀者可以跟蹤這個參數(shù)的計算過程,還要往里套五六層代碼才知道計算過程。它翻譯過來就是“sse的分母”。

2. 推演

如果不對相機進行修改,使用默認的,而且你的屏幕是1920×1080,恰好你的 canvas 占滿了 body,而且你的瀏覽器是最大化的狀態(tài),那么這個 sseDenominator 的值約為 0.5629165124598852

顯而易見,為了屏蔽屏幕分辨率差異、瀏覽器是否最大化的差異,這個 sseDenominator 的值是會根據(jù)瀏覽器窗口狀態(tài)、canvas大小以及攝像機的狀態(tài)進行變化的。在此,我們假定就是 0.5629165124598852

那么 上述代碼改寫成:

\[sse = \frac{geometricError×936}{distance × 0.5629165124598852} \]

是否還記得一個參數(shù):maximumScreenSpaceError?它的默認值是16

那么,這個16就是一個臨界值,當(dāng) \(sse < defaultMaximumScreenSpaceError = 16\) 時,下一級瓦片加載,此瓦片根據(jù) refine 進行調(diào)整。

假設(shè) sse 剛好等于16,那么得到一個二元方程:

\[16 = \frac{geometricError×936}{distance × 0.5629165124598852} \]

所以,這個等式表達的含義就是,當(dāng)幾何誤差越大(分子變大),要想等式保持相等,那么分母:distance(相機到瓦片的距離)也應(yīng)變大,變大就意味著——根據(jù) refine 來控制瓦片的顯隱或增補時,此瓦片觀察距離由此變大。

所以,這個幾何誤差是一個經(jīng)驗值。

下結(jié)論:

在幾何誤差、相機狀態(tài)是固定值時,只要觀察距離 > 計算此幾何誤差的經(jīng)驗距離,就會渲染下一級瓦片,此瓦片的 refine 規(guī)則若是 REPLACE 則消失,若是 ADD 則保留。
若渲染下一級瓦片,則當(dāng)前瓦片的 sse 必定 < maximumScreenSpaceError。

3. 經(jīng)驗值下的幾何誤差計算

還是以剛好到臨界值,也即默認的 16 時,為例。

設(shè)定某瓦片距離相機超過200米時,該瓦片到達臨界狀態(tài)。

代入上式,計算得到 geometricError 為:

\[geometricError = 200 × 0.5629165124598852×16÷936=1.9245008972987 \]

那么現(xiàn)在這個瓦片的 sse 公式變成了:

\[sse = \frac{1.9245008972987×936}{distance×0.5629165124598852} \]

也就是距離越大,sse 越小。當(dāng)距離超過200米,sse一定小于16,不妨設(shè) refineREPLACE

在視圖中觀察到小于200米時,此瓦片正常顯示,距離一旦大于200米,該瓦片就被 REPLACE 了,此時的 sse 肯定也小于16,只需調(diào)整 maximumScreenSpaceError,在 CesiumLab 中叫顯示精度,調(diào)小一些,該瓦片又被顯示了。

不妨假設(shè)就按 1080p屏幕 + 全屏canvas + 最大化瀏覽器窗口 + 默認相機參數(shù)來算,列舉常見觀察距離的幾何誤差設(shè)置:

觀察距離 幾何誤差
100 0.96225045
200 1.92450090
300 2.88675134
400 3.84900179
500 4.81125224
1000 9.62250447
2000 19.24500897

觀察不難得知,這是一個一次函數(shù):

\[geometricError =f(distance) = distance × 0.5629165124598852×16÷936 \]

而后面三個數(shù)字,則與相機、瀏覽器等因素有關(guān),只要瀏覽器不變,相機不變,顯示器不變,那么無論怎么操作視圖,幾何誤差的計算都只跟經(jīng)驗上的觀察距離有關(guān)。

4. 調(diào)參經(jīng)驗

4.1. 當(dāng)前視角如果不繼續(xù)放大,傾斜攝影的層級比較低(看起來模糊)怎么辦

方案① 調(diào)整最大屏幕空間誤差

調(diào)大 maximumScreenSpaceError,因為幾何誤差不變、距離不變,等式左邊放大,勢必等號要變成大于號:

\[maximumScreenSpaceError > 16 = \frac{geometricError×936}{distance × 0.5629165124598852} \]

根據(jù)上述結(jié)論,同等條件下最大屏幕空間誤差變大,導(dǎo)致計算結(jié)果 小于 最大屏幕空間誤差,從而引發(fā)下一級瓦片渲染,當(dāng)前瓦片執(zhí)行 "refine" 策略。

方案② 根治法:調(diào)整幾何誤差

不渲染下一級瓦片的原因無非是當(dāng)前幾何誤差所代表的經(jīng)驗距離太大了,不小于這個距離就沒法渲染。
解決方法很簡單,把幾何誤差調(diào)小 即可,參考上文。

4.2. 想不加載這么快

同 4.1. 的思路,減小 maximumScreenSpaceError增大 幾何誤差。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多